I'm writing a program that will simulate a randomized race between runners who are climbing up a mountain where dwarf orcs (dorcs) are coming down the mountain to attack the runners. It begins with two runners named harold and timmy at the bottom of the mountain. The runners make their way up the mountain in randomized moves where they may make progress forward up the mountain, or they may slide back down the mountain. Dorcs are randomly generated, and they inflict damage on a runner if they collide. The simulation ends when one of the runners reaches the top of the mountain, or when both runners are dead.
I'm struggling with a part where I have to implement the actual race loop. Once the race is initialized, the race loop will iterate until the race is over. This happens when either a winner has been declared, or when all runners are dead.
Every iteration of the race loop will do the following:
with 30% probability, dynamically allocate a new dorc as an EntityType structure, and initialize it as follows:
(a) a dorc’s avatar is always “d”
(b) each dorc begins the race at the top of the mountain, which is at row 2
(c) with equal probability, the dorc may be placed either in the same column as timmy, or in the same column as the harold, or in the column exactly half-way between the two
(d) add the new dorc to the race’s array of dorcs
(e) using the pthread_create() function, create a thread for the new dorc, and save the thread pointer in the dorc’s entity structure; the function that each dorc thread will execute is the void* goDorc(void*) function that you will implement in a later step; the parameter to the goDorc() function will be the EntityType pointer that corresponds to that dorc
I guess I'm confused with the logic of how to approach this. I decided to make a function called isOver() to indicate if the race is over, and then a separate function called addDorc() to initialize the Dorc elements and do all the requirements above.
In isOver(), I attempt to add a dorc object to the dorcs array by doing addDorc(race); with every iteration of the race loop/if the race hasn't ended or no one died. But I keep getting the error:
control.c:82:3: error: too few arguments to function ‘addDorc’
addDorc(race);
The problem is I don't think I can manually declare all the parameters in addDorc() because some elements like the "path" argument are based on probability. As mentioned above, with equal probability, the dorc may be placed either in the same column as timmy, or in the same column as the harold, or in the column exactly half-way between the two. The issue is I don't know how to factor this random value when calling addDorc() and would appreciate some help. I also don't know if I'm doing the "with 30% probability, dynamically allocate a new dorc as an EntityType structure" correctly and would be grateful for some input on that as well.
defs.h
typedef struct {
pthread_t thr;
char avatar[MAX_STR];
int currPos;
int path;
} EntityType;
typedef struct {
EntityType ent;
char name[MAX_STR];
int health;
int dead;
} RunnerType;
typedef struct {
int numRunners;
RunnerType *runners[MAX_RUNNERS];
int numDorcs;
EntityType *dorcs[MAX_DORCS];
char winner[MAX_STR];
int statusRow;
sem_t mutex;
} RaceInfoType;
void launch();
int addDorc(RaceInfoType*, char*, int, int);
int isOver(RaceInfoType*);
void initRunners(RaceInfoType*);
int addRunner(RaceInfoType*, char*, char*, int, int, int, int);
int randm(int);
void *goRunner(void*);
void *goDorc(void*);
RaceInfoType *race;
control.c
void launch(){
race = malloc(sizeof(RaceInfoType));
race->numRunners = 0;
initRunners(race);
if (sem_init(&race->mutex, 0, 1) < 0) {
printf("semaphore initialization error\n");
exit(1);
}
strcpy(race->winner, " ");
srand((unsigned)time(NULL));
int i;
for(i = 0; i < race->numRunners; ++i){
pthread_create(&(race->runners[i]->ent.thr), NULL, goRunner, " ");
}
race->numDorcs = 0;
}
int addDorc(RaceInfoType* race, char *avatar, int path, int currPos){
if(race->numDorcs == MAX_DORCS){
printf("Error: Maximum dorcs already reached. \n");
return 0;
}
race->dorcs[race->numDorcs] = malloc(sizeof(EntityType));
int timmysColumn = race->dorcs[race->numDorcs]->currPos;
int haroldsColumn = race->dorcs[race->numDorcs]->currPos;
int halfwayColumn = (timmysColumn+haroldsColumn)/2;
int r = rand()%100;
pthread_t dorc;
if(r <= 30){
strcpy(race->dorcs[race->numDorcs]->avatar, "d");
race->dorcs[race->numDorcs]->currPos = 2;
if(r <= 33){
race->dorcs[race->numDorcs]->path = timmysColumn;
}else if(r <= 66){
race->dorcs[race->numDorcs]->path = haroldsColumn;
}else{
race->dorcs[race->numDorcs]->path = halfwayColumn;
}
pthread_create(&dorc, NULL, goDorc, " ");
}
race->numRunners++;
}
int isOver(RaceInfoType* race){
int i;
for(i = 0; i < race->numRunners; ++i){
if((race->winner != " ") || (race->runners[race->numRunners]->dead = 1)){
return 1;
}
addDorc(race);
return 0;
}
}
void initRunners(RaceInfoType* r){
addRunner(r, "Timmy", "T", 10, 35, 50, 0);
addRunner(r, "Harold", "H", 14, 35, 50, 0);
}
int addRunner(RaceInfoType* race, char *name, char *avatar, int path, int currPos, int health, int dead){
if(race->numRunners == MAX_RUNNERS){
printf("Error: Maximum runners already reached. \n");
return 0;
}
race->runners[race->numRunners] = malloc(sizeof(RunnerType));
strcpy(race->runners[race->numRunners]->name, name);
strcpy(race->runners[race->numRunners]->ent.avatar, avatar);
race->runners[race->numRunners]->ent.path = path;
race->runners[race->numRunners]->ent.currPos = currPos;
race->runners[race->numRunners]->health = health;
race->runners[race->numRunners]->dead = dead;
race->numRunners++;
return 1;
}
Caveat: Because there's so much missing [unwritten] code, this isn't a complete solution.
But, I notice at least two bugs: the isOver bugs in my top comments. And, incrementing race->numRunners in addDorc.
isOver also has the return 0; misplaced [inside the loop]. That should go as the last statement in the function. If you had compiled with -Wall [which you should always do], that should have been flagged by the compiler (e.g. control reaches end of non-void function)
From that, only one "dorc" would get created (for the first eligible runner). That may be what you want, but [AFAICT] you want to try to create more dorcs (one more for each valid runner).
Also, the bug the compiler flagged is because you're calling addDorc(race); but addDorc takes more arguments.
It's very difficult to follow the code when you're doing (e.g.) race->dorcs[race->numDorcs]->whatever everywhere.
Better to do (e.g.):
EntityType *ent = &race->dorcs[race->numDorcs];
ent->whatever = ...;
Further, it's likely that your thread functions would like a pointer to their [respective] control structs (vs. just passing " ").
Anyway, I've refactored your code to incorporate these changes. I've only tried to fix the obvious/glaring bugs from simple code inspection, but I've not tried to recompile or address the correctness of your logic.
So, there's still more work to do, but the simplifications may help a bit.
void
launch(void)
{
race = malloc(sizeof(RaceInfoType));
race->numRunners = 0;
initRunners(race);
if (sem_init(&race->mutex,0,1) < 0) {
printf("semaphore initialization error\n");
exit(1);
}
strcpy(race->winner," ");
srand((unsigned)time(NULL));
int i;
for (i = 0; i < race->numRunners; ++i) {
RunnerType *run = &race->runners[i];
EntityType *ent = &run->ent;
pthread_create(&ent->thr,NULL,goRunner,ent);
}
race->numDorcs = 0;
}
int
addDorc(RaceInfoType* race,char *avatar,int path,int currPos)
{
if (race->numDorcs == MAX_DORCS) {
printf("Error: Maximum dorcs already reached. \n");
return 0;
}
EntityType *ent = malloc(sizeof(*ent));
race->dorcs[race->numDorcs] = ent;
int timmysColumn = ent->currPos;
int haroldsColumn = ent->currPos;
int halfwayColumn = (timmysColumn + haroldsColumn) / 2;
int r = rand()%100;
#if 0
pthread_t dorc;
#endif
if (r <= 30) {
strcpy(ent->avatar,"d");
ent->currPos = 2;
if (r <= 33) {
ent->path = timmysColumn;
} else if (r <= 66) {
ent->path = haroldsColumn;
} else {
ent->path = halfwayColumn;
}
pthread_create(&ent->thr,NULL,goDorc,ent);
}
#if 0
race->numRunners++;
#else
race->numDorcs += 1;
#endif
}
int
isOver(RaceInfoType* race)
{
int i;
for (i = 0; i < race->numRunners; ++i) {
#if 0
if ((race->winner != " ") ||
(race->runners[race->numRunners]->dead = 1))
return 1;
#else
RunnerType *run = &race->runners[i];
if ((race->winner != " ") || (run->dead == 1))
return 1;
#endif
addDorc(race);
#if 0
return 0;
#endif
}
#if 1
return 0;
#endif
}
void
initRunners(RaceInfoType* r)
{
addRunner(r,"Timmy","T",10,35,50,0);
addRunner(r,"Harold","H",14,35,50,0);
}
int
addRunner(RaceInfoType* race,char *name,char *avatar,int path,int currPos,
int health,int dead)
{
if (race->numRunners == MAX_RUNNERS) {
printf("Error: Maximum runners already reached. \n");
return 0;
}
RunnerType *run = malloc(sizeof(*run));
race->runners[race->numRunners] = run;
strcpy(run->name,name);
EntityType *ent = &run->ent;
strcpy(ent->avatar,avatar);
ent->path = path;
ent->currPos = currPos;
run->health = health;
run->dead = dead;
race->numRunners++;
return 1;
}
UPDATE:
I noticed in addDorc(), you put pthread_t dorc; in an if statement. I don't quite understand what my if statement is actually supposed to be checking though.
I forgot to mention/explain. I wrapped your/old code and my/new code with preprocessor conditionals (e.g.):
#if 0
// old code
#else
// new code
#endif
After the cpp stage, the compiler will only see the // new code stuff. Doing this was an instructional tool to show [where possible] what code you had vs what I replaced it with. This was done to show the changes vs. just rewriting completely.
If we never defined NEVERWAS with a #define NEVERWAS, then the above block would be equivalent to:
#ifdef NEVERWAS
// old code ...
#else
// new code
#endif
Would it still be under the if(r <= 30) part like I did in my original code?
Yes, hopefully now, it is more clear. #if is a cpp directive to include/exclude code (as if you had edited that way). But, a "real" if is an actual executable statement that is evaluated at runtime [as it was before], so no change needed.
My other concern is it doesn't look like dorc is used anywhere in the function because you write pthread_create(&ent->thr,NULL,goDorc,ent); which seems to use ent instead?
That is correct. It is not used/defined and the value goes to ent->thr. As you had it, the pthread_t value set by pthread_create would be lost [when dorc goes out of scope]. So, unless it's saved somewhere semi-permanent (e.g. in ent->thr), there would be no way to do a pthread_join call later.
I'm learning a piece of code, I don't know how to implement this function using only one function? How to pass parameters to the function?
#include <stdio.h>
struct colleagues {
int female[10];
int male[10];
} teams[20];
void func(int count[])
{
for (int i = 0; i < 10; i++) {
printf("%d\n", count[i]);
}
}
//FIXME
void showCnt(void (*function)(int *), int XXX[])
{
for (int n = 0; n < 20; n++) {
func(teams[n].XXX);
}
}
int main()
{
//How can i just use only one function showCnt to do this work???, I'm so appreciated.
//***FIXME, How can i pass parameters "teams.female" to showCnt???***
showCnt(function, teams.female);
showCnt(function, teams.male);
return 0;
}
Sorry, I didn't say it clearly. I don't know how to pass the parameters "teams.male" as a array to showCnt(), I'm wondering how to call showCnt() twice separately to print the info.
For example, first, It calls showCnt(teamXX.female), second, it calls showCnt(teamXXX.male). I don't know if I can pass parameters to showCnt() to make "func(team[n].male)" and "func(team[n].female)" working properly.
If I understand you correctly, you want to only call showCnt as
showCnt(function);
and it should print both teams.female and teams.male?
Then to begin with remove the (erroneous) count argument from the function showCnt. Then inside the loop of showCnt call function twice with teams[n].female and teams[n].male.
I have a certain program that lets you register members and save their name and birthdate into arrays. The particular function that does this registration uses the following code;
char regmember (struct member a[])
{
int i = 0;
char wow;
do
{
//registration
printf("\n Do you want to add someone else (y/n):");
scanf(" %c",&wow);
i++
}while(wow != 'n');
int nrofmembers = i;
return nrofmembers;
}
-> I save the user input by using
scanf("%s",a[i].name) and scanf("%d",&a[i].ID);
which is why I am using i++. As you realize, the int variable i, will hold the number of members who have been registered. I want to utilize this info in order to use it in loops in other functions, so I went on to save the value of i in another int variable...
int nrofmembers = i;
My problem is, I can't use that variable (nrofmembers) else where, even though I tried returning it, any advice?
you need both to get i in parameter and to return the new value, you can do
int regmember (struct member a[], int i)
{
... use and modify i
return i;
}
or using it as an input-output variable
void regmember (struct member a[], int * i)
{
... use and modify *i
}
In the first case the caller do for instance :
int i = 0;
for (...) {
...
i = regmember(..., i);
...
}
and in the second case :
int i = 0;
for (...) {
...
regmember(..., &i);
...
}
Suppose you keep the members in a global array, then you can manage how many members are in your array also as a global variable, for example
struct member gMembers[MAX_MEMBERS];
int gnMembers;
Your function can now operate on this array directly:
int regmember (void)
{
if (gnMembers < MAX_MEMBERS)
{
// add member
if (scanf("%s",gMembers[gnMembers].name)==1
&& scanf("%d",&gMembers[gnMembers].ID)==1) {
gnMembers++;
return 1; // success
}
}
return 0; // array full or scanf error
}
I looking for a answer and can't find nowhere. I hope you'll help me. I write a simple app which include struct with a name of worker and . But when i want to change value of name i can't do it. I don't know why. Maybe you can't help me or you know another ways to do it? My code:
struct workers {
char name[256]="no";
int pay=-1;
};
void addOne(struct workers work[20]) {
char name[256];
int i=0;
for (i = 0; work[i].name != "no"; i++) {}
printf_s("Enter name of worker: ");
scanf_s("%s", &name);
//-----error here-----
work[i].name = name;
}
int main()
{
int i;
struct workers work[20];
for (i = 0;i < 20; i++) {
if (work[i].name != "no") {
work[i].pay = 100 * i;
}
}
for (i = 0; i < 20; i++) {
printf_s("%s\t%d\n", work[i].name, work[i].pay);
}
return 0;
}
work[i].name = name;
The above line is where the problem is.
Change as below:
snprintf( work[i].name, sizeof(work[i].name), "%s", name);
What you have done is trying to change the base pointer of the array and not the name.
Also there were few more errors in the code, pls resolve them.
It is not possible to set default values to structure as you have done in C.
You have to write code to init each array instance name variable with "no" in a loop and then use one of the string comparison functions to compare the strings. And then call your addOne.
I have my code below that consits of a structure, a main, and a function. The function is supposed to display two parameters that have certain values, both of which point to the same structure.
The problem I dont know how to add the SECOND parameter onto the following code :
#include<stdio.h>
#define first 500
#define sec 500
struct trial{
int f;
int r;
float what[first][sec];
};
int trialtest(trial *test);
main(){
trial test;
trialtest(&test);
}
int trialtest(trial *test){
int z,x,i;
for(i=0;i<5;i++){
printf("%f,(*test).what[z][x]);
}
return 0;
}
I need to add a new parameter test_2 there (IN THE SAME FUNCTION) using this code :
for(i=0;i<5;i++){
printf("%f,(*test_2).what[z][x]);
How does int trialtest(trial *test) changes ?
and how does it change in main ?
I know that I should declare test_2 as well, like this :
trial test,test_2;
But what about passing the address in the function ? I do not need to edit it right ?
trialtest(&test); --- This will remain the same ?
So please, tell me how would I use test_2 as a parameter pointing to the same structure as test, both in the same function..
Thank you !!
Please tell me if you need more clarification
I think that this is your homework, so I'll just write a different function that may give you an idea of what (I think) you need to do. I read that you don't want to change the trail_test parameter list, so I stuck with a similar parameter list.
struct thing {
/* put some stuff here */
};
typedef struct thing thing; /* because this is C, not C++ */
int how_many_things(thing * thing_list);
int main(void) {
int i;
thing * a;
int count_init = random(); /* let's surprise ourselves and make a random number of these */
count_init %= 128; /* but not too many or it might not work at all */
a = malloc(count_init*sizeof(things)+1);
for (i = 0; i < count_init; i++) {
thing_init(&(a[i]));
}
make_illegal_thing(&(a[count_init]) ); /* like '\0' at the end of a string */
printf("There are %i things in the list\n", how_many_things(a) );
return 0;
}
/* This is very similar to strlen */
int how_many_things(thing * a) {
int count = 0;
while (is_legal_thing(a) ) {
a++;
count++;
}
return count;
}