/* * run.c * * Schedule races according to the strategy, and run them. */ /*** *** Include files ***/ /*lint -e579 */ #include #include #include #include #include #include #include #include "pragmas.h" #include "pinewood.h" /*** *** Local structures ***/ struct race { int racenum; char lane[NLANES][6]; }; /*** *** Local function prototypes ***/ static void award(char *place, FILE *printer); static void latch_averages(void); static int map_to_user(char *str); static bool_t parse_ent(struct race *ent, char *buffer); static void read_race_schedule(void); #if 0 static bool_t den_has_raced(int den, int nraces); static int display_menu(void); static int find_contestant(int lanenum); static int find_short_contestant(int lanenum, int races); static char * find_status(int rank); static bool_t in_race(int user, int rank); static bool_t race_schedule(void); static void race_rank(int rank); static bool_t schedule(void); static void schedule_first_set(void); static bool_t short_schedule(void); static int which_den(int user); #endif /*** *** Local variables ***/ static int Ncontrol = 0; static int Nraces = 0; static char Control[200][30]; static struct race Roster[200]; /*** *** External functions ***/ #if 0 int dump_control(char *title) { FILE *printer; int count; printer = xfopen(PRINTER, "a"); xfprintf(printer, "%s\n", title); for (count = 0; count < Ncontrol; count++) xfprintf(printer, "Control message %d is %s\n", count, Control[count]); fclose(printer); } #endif /* * run_heat * * Run a race. */ void run_heat(void) { char buffer[100]; int car; int ch; int control; int ncars; FILE *printer; char probe[10]; int race; int rank[NLANES]; int rc; int tc; long int times[NLANES]; time_t timeval; char titlebuf[NLANES][100]; char *titles[NLANES]; int tr; int user; /* * Read the schedule */ read_race_schedule(); /* * Ask the user for the starting point. * If empty, start at the beginning. * This really should be done automatically. */ printf("What race do you want to start at: "); fgets(buffer, sizeof(buffer), stdin); rc = atoi(buffer); if (rc == 0) rc = 1; control = -1; for (race = 0; race < Nraces; race++) { if (Roster[race].racenum == -1) control++; else if (Roster[race].racenum == rc) break; } if (race >= Nraces) { xfprintf(stderr, "Cannot find race %d\n", rc); sleep(5); return; } printf("Starting at race %d\n", rc); /* * Run the races to the end of the roster */ for (user = 0; user < Nusers; user++) Database[user].in_race = FALSE; for (; race < Nraces; race++) { if (Roster[race].racenum == -1) { /* * This is a control message. Do what is necessary for * previous control message, and then deal with the next. */ printer = xfopen(PRINTER, "a"); xfprintf(printer, "\n%s is complete\n", Control[control]); if (EQn(Control[control], "Den") || EQn(Control[control], "Runoff")) { award("1st", printer); award("2nd", printer); award("3rd", printer); xfprintf(printer, "\n\n"); } for (user = 0; user < Nusers; user++) Database[user].in_race = FALSE; /* Deal with the new control message */ control++; if (printer != NULL) { if (EQn(Control[control], "Runoff")) { /* Look at the next entry (hope it exists) */ xfprintf(printer, "Starting %s\n", Control[control]); for (ncars = 0; Roster[race + ncars + 1].racenum != -1; ) ncars++; for (car = 0; car < ncars; car++) { tr = race + 1 + (car / NLANES); tc = car % NLANES; user = map_to_user(Roster[tr].lane[tc]); if (user != -1) { xfprintf(printer, " Slot %s is occupied by car: %s %s\n", Roster[tr].lane[tc], Database[user].car, Database[user].name); } else { xfprintf(printer, " Slot %s is not occupied\n", Roster[tr].lane[tc]); } } xfprintf(printer, "\n\n"); } else if (EQn(Control[control], "Final")) { xfprintf(printer, "Starting final run\n"); strcpy(probe, "X-A"); for (car = 0; car < 8; car++) { probe[2] = (char) (car + 'A'); user = map_to_user(probe); if (user != -1) { xfprintf(printer, " Slot %s is occupied by car: %s %s\n", probe, Database[user].car, Database[user].name); } else { xfprintf(printer, " Slot %s is not occupied\n", probe); } } xfprintf(printer, "\n\n"); } } if (printer != NULL) { xfprintf(printer, ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .\n"); xfclose(printer); } continue; } /* * Run the next race. */ do { for (car = 0; car < NLANES; car++) { user = map_to_user(Roster[race].lane[car]); if (user < 0) titles[car] = ""; else { sprintf(titlebuf[car], "%s %s", Database[user].car, Database[user].name); titles[car] = titlebuf[car]; } } clrscr(); if (!run_race(titles, rank, times, Roster[race].racenum)) return; /* * The race has completed. * See if the race controller wants to accept the race, * or rerun the race. */ for (;;) { gotoxy(1, 1); clreol(); highvideo(); cprintf("Do you want to accept the results (A)," " or rerun the race (R): "); normvideo(); ch = getxch(); if (ch == K_ESC) return; if (strchr("AaRr", ch) != NULL) break; highvideo(); gotoxy(1, 2); cprintf("PLEASE USE *A* or *R*"); printf("\a"); } } while (ch != 'A' && ch != 'a'); /* * The race has been accepted. Save the results. */ for (car = 0; car < NLANES; car++) { user = map_to_user(Roster[race].lane[car]); if (user >= 0) { Database[user].racenum = 0; /* Race complete */ for (rc = 0; rc < NRACES && Database[user].run[rc] != 0; ) rc++; Database[user].run[rc] = times[car]; Database[user].lane[rc] = car + 1; Database[user].in_race = TRUE; } } write_database(); /* * Print the results on the log printer */ printer = xfopen(PRINTER, "a"); timeval = time(NULL); xfprintf(printer, "\nResults for race %d, %s\n", Roster[race].racenum, ctime(&timeval)); for (car = 0; car < NLANES; car++) { user = map_to_user(Roster[race].lane[car]); if (user >= 0) { xfprintf(printer, "%s %-30.30s", Database[user].car, Database[user].name); xfprintf(printer, "%s %d", format_time(times[car]), rank[car]); // if (count_races(user) > 1) { xfprintf(printer, " (average %s)", format_time(average(user))); } xfprintf(printer, "\n"); } } xfprintf(printer, "\n\n"); xfprintf(printer, ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .\n"); xfclose(printer); /* This was to allow the results to be printed while * leaving the results on the screen. */ gotoxy(1, 1); clreol(); highvideo(); cprintf("Hit any key to get ready for the next race: "); normvideo(); if (getxch() == K_ESC) return; } /* * Print the winners out */ printer = xfopen(PRINTER, "a"); xfprintf(printer, "\nAll races complete\n"); award("1st", printer); award("2nd", printer); award("3rd", printer); xfprintf(printer, ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .\n"); xfclose(printer); latch_averages(); } /* * print_race_schedule * * Print the race schedule as read in from the table. */ void print_race_schedule(void) { char buffer[100]; FILE *fp; int lane; int race; time_t timeval; int user; clrscr(); printf("Would you like to print the race schedule? "); fgets(buffer, sizeof(buffer), stdin); if (tolower(buffer[0]) != 'y') return; fp = xfopen(PRINTER, "a"); read_race_schedule(); timeval = time(NULL); xfprintf(fp, "\f Race schedule %s\n", ctime(&timeval)); for (race = 0; race < Nraces; race++) { if (Roster[race].racenum == -1) continue; xfprintf(fp, "Race %d\n", Roster[race].racenum); for (lane = 0; lane < NLANES; lane++) { xfprintf(fp, " %d %s ", lane + 1, Roster[race].lane[lane]); if (isdigit(Roster[race].lane[lane][0]) && isdigit(Roster[race].lane[lane][2])) { user = map_to_user(Roster[race].lane[lane]); if (user == -1) xfprintf(fp, "Unknown car\n"); else xfprintf(fp, "%s\n", Database[user].name); } else xfprintf(fp, "Decided at race time\n"); } } xfprintf(fp, "\f"); xfclose(fp); } /*** *** Local functions ***/ /* * award * * Print a message indicating who won which place. * This depends upon a flag being set for cars entering * this set of races. Pick the winners from that set, * and clear the flags. */ static void award(char *place, FILE *printer) { int best; int user; best = -1; for (user = 0; user < Nusers; user++) { if (Database[user].in_race && (best == -1 || average(user) < average(best))) { best = user; } } if (best != -1) { Database[best].in_race = FALSE; xfprintf(printer, " %s place is %s, average time is %s %s\n", place, Database[best].car, format_time(average(best)), Database[best].name); } } /* * latch_averages * * Latch the current average time for all users */ static void latch_averages(void) { int first; int rank; int user; /* Latch the average times of all cars */ for (user = 0; user < Nusers; user++) { Database[user].average = average(user); Database[user].rank = 0; } /* Go through in a horrible sort to assign rankings to the cars */ first = 0; for (rank = 1; first != -1; rank++) { first = -1; for (user = 0; user < Nusers; user++) { if (Database[user].rank == 0 && Database[user].average > 0 && (first == -1 || Database[user].average < Database[first].average)) { first = user; } } if (first != -1) Database[first].rank = rank; } #if 0 { FILE *printer; printer = xfopen(PRINTER, "a"); for (user = 0; user < Nusers; user++) { xfprintf(printer, "%s %d %s %s\n", format_time(Database[user].average), Database[user].rank, Database[user].car, Database[user].name); } xfclose(printer); } #endif } /* * map_to_user * * Map a car string in the schedule file to a particular user. * This isn't too hard for the "normal" entries. However, for * the run-offs and the final races, special code is needed. */ static int map_to_user(char *str) { static bool_t dens_seen[10] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }; static bool_t final_seen = FALSE; char cmp[10]; int first; int second; int user; if (str[1] != '-') { fprintf(stderr, "Invalid car name: %s\n", str); exit(1); } /* Handle the easy case */ if (isdigit(str[0]) && isdigit(str[2])) { cmp[0] = str[0]; cmp[1] = str[2]; cmp[2] = '\0'; for (user = 0; user < Nusers; user++) { if (EQ(cmp, Database[user].car)) return (user); } fprintf(stderr, "Cannot find car %s %s\n", str, cmp); sleep(2); return (-1); } /* Handle runoffs */ if (isdigit(str[0]) && isalpha(str[2])) { /* * If we have not seen this den before, record seeing it, * and latch the current average for all users. */ if (!dens_seen[str[0] - '0']) { dens_seen[str[0] - '0'] = TRUE; latch_averages(); } first = -1; second = -1; for (user = 0; user < Nusers; user++) { if (Database[user].car[0] == str[0]) { if (first == -1 || Database[user].average < Database[first].average) { second = first; first = user; } else if (second == -1 || Database[user].average < Database[second].average) { second = user; } } } return ( (str[2] == 'A' || str[2] == 'F') ? first : second); } /* Handle the final race */ if ((str[0] == 'X' || str[0] == 'P') && isalpha(str[2])) { if (!final_seen) { latch_averages(); final_seen = TRUE; } for (user = 0; user < Nusers; user++) { if (Database[user].rank == str[2] - 'A' + 1) return (user); } } /* Cannot happen */ fprintf(stderr, "Invalid car specifier: %s\n", str); sleep(2); return (-1); } /* * parse_ent * * Parse an entry. * Minimal error checking. */ static bool_t parse_ent(struct race *ent, char *buffer) { char *cptr; int lane; char *to; ent->racenum = (int) strtol(buffer, &cptr, 10); for (lane = 0; lane < NLANES; lane++) ent->lane[lane][0] = '\0'; for (lane = 0; lane < NLANES; lane++) { while (isspace(*cptr)) cptr++; for (to = &ent->lane[lane][0]; *cptr != '\0' && !isspace(*cptr); ) *to++ = *cptr++; *to = '\0'; } return (TRUE); } /* * read_race_schedule * * Read the text description of the race schedule. * Fixed scheduling. Makes it easy to print up race * forms. */ static void read_race_schedule(void) { char buffer[200]; char *cptr; FILE *file; if ((file = fopen(RACESCHED, "r")) == NULL) { fprintf(stderr, "Cannot open race schedule file %s\n", RACESCHED); exit(1); } Nraces = 0; //!!! No limit checking on size of file while (fgets(buffer, sizeof(buffer), file) != NULL) { if ((cptr = strchr(buffer, '\n')) != NULL) *cptr = '\0'; if (buffer[0] == '\0' || buffer[0] == '#') continue; if (EQn(buffer, "Den") || EQn(buffer, "Runoff") || EQn(buffer, "Final")) { Roster[Nraces++].racenum = -1; strcpy(Control[Ncontrol++], buffer); } else if (parse_ent(&Roster[Nraces], buffer)) { Nraces++; } } #if 0 {int i, lane; for (i = 0; i < Nraces; i++) { printf("Race %d: ", Roster[i].racenum); for (lane = 0; lane < NLANES; lane++) printf(" %s ", Roster[i].lane[lane]); printf("\n"); }} #endif } /***************************************************************************** ***************************************************************************** *****************************************************************************/ /*** *** Obsolete code ***/ #if 0 for (;;) { limit = display_menu(); fgets(buffer, sizeof(buffer), stdin); if (buffer[0] == '\n') return; select = atoi(buffer); if (select <= 0 || select > limit) printf("Please pick a number between 1 and %d\n", limit); else race_rank(select - 1); } #endif #if 0 /* * See if there are any races currently in the schedule. * If so, then we want to get those out of the way now. */ if (!race_schedule()) return; /* * See if everybody has caught up in the number of races. * What we will do here is continually scan through the * roster looking for cars that are short, and build a * race schedule for those cars. */ while (short_schedule()) { if (!race_schedule()) return; } /* * All cars are now up to the same number of races. * Schedule a new set of races. */ if (!schedule()) { clrscr(); gotoxy(20, 10); cprintf("ALL RACES HAVE BEEN COMPLETED"); print_results(); return; } /* * Print the new race schedule with current times and such. * Print this list in race order. */ print_race_schedule(); } #endif #if 0 /* * den_has_raced * * See if all members of a den have raced the appropriate number * of times. */ static bool_t den_has_raced(int den, int nraces) { int race; int user; for (user = 0; user < Nusers; user++) { if (which_den(user) == den) { for (race = 0; race < NRACES; race++) { if (Database[user].run[race] == 0) break; } if (race < nraces) return (FALSE); } } return (TRUE); } #endif #if 0 /* * display_menu * * Displays a menu of the ranks and their status. */ static int display_menu(void) { int rank; for (rank = 0; rank < Nranks; rank++) { printf("%d %-10.10s ", rank + 1, Ranks[rank]); printf("%s\n", find_status(rank)); } printf("%d Final\n", rank); printf("\nSelect the number of the rank you want to race,\n"); printf("or a blank line if you are done: "); return (rank); } #endif #if 0 /* * find_contestant * * Find a user who is not currently scheduled with the * worst average time. No runs is the worst average time. * Ensure that the user can use the lane available. * * This isn't an efficient process. But we are saved * by having a small data set. * * lanenum starts at 1. */ static int find_contestant(int lanenum) { long int avg; int car; int user; int worst; long int worst_av; worst = -1; worst_av = 1000000; /* Worst average race time */ for (user = 0; user < Nusers; user++) { if (Database[user].racenum == 0) { /* * If this user has never run, he can run in any lane, and * has the worst possible average time. He wins!! */ if (Database[user].run[0] == 0) return (user); /* * If this user has run in this lane before, we must bow out. * Actually, we really want a more general solution, but that * is the basic idea. */ for (car = 0; car < NRACES; car++) { if (Database[user].lane[car] == lanenum) break; } if (car != NRACES) continue; /* * We are looking for the worst average time. * Calculate the worst, and see if it beats the previous worst. */ avg = 0; for (car = 0; car < NLANES && Database[user].run[car] > 0; car++) avg += Database[user].run[car]; avg /= car; if ((worst == -1) || (avg > worst_av)) { worst_av = avg; worst = user; } } } return (worst); } #endif #if 0 /* * find_short_contestant * * Find a user who is not currently scheduled and is behind in * the number of races. * * Ensure that the user can use the lane available. * * This isn't an efficient process. But we are saved * by having a small data set. * * lanenum starts at 1. */ static int find_short_contestant(int lanenum, int races) { char buffer[10]; int car; int nraces; int user; for (user = 0; user < Nusers; user++) { if (Database[user].scanned) continue; nraces = count_races(user); if (nraces >= races) continue; if (Database[user].racenum == 0) { /* * If this user has run in this lane before, we must bow out. * Actually, we really want a more general solution, but that * is the basic idea. */ for (car = 0; car < NRACES; car++) { if (Database[user].lane[car] == lanenum) break; } if (car != NRACES) continue; /* * We have a candidate here. See if the race controller * wants to race this car or not. */ Database[user].scanned = TRUE; printf("The car for %s has only raced %d time%s." " Most cars have raced %d time%s.\n", Database[user].name, nraces, (nraces != 1) ? "s" : "", races, (races != 1) ? "s" : ""); printf("Do you want to race this car? "); fgets(buffer, sizeof(buffer), stdin); if (tolower(buffer[0]) == 'y') return (user); } } return (-1); } #endif #if 0 /* * find_status * * Find the current status. * * If no user in the given ranks have any time logged, then * that race has never started. * * If some user in the rank has time logged, then the race has * started. * * If every user of the given rank have NHEATS * # dens in rank * runs, then the race is done. */ static char * find_status(int rank) { int max_races; int min_races; int ndens; int nusers; int race; int user; max_races = 0; min_races = 1000; nusers = 0; for (user = 0; user < Nusers; user++) { if (in_race(user, rank)) { nusers++; for (race = 0; race < NRACES; race++) { if (Database[user].run[race] == 0) break; } race--; if (race < min_races) min_races = race; else if (race > max_races) max_races = race; } } for (ndens = 0; Ranks[rank].dens[ndens] != -1; ndens++) ; if (nusers == 0) return ("No users"); else if (max_races == 0) return ("Not started"); else if (min_races == NHEATS * ndens) return ("Done"); else return ("Race in progress"); } #endif #if 0 /* * in_race * * See if this user is in the race for the given rank. !!! Needs to handle final race right */ static bool_t in_race(int user, int rank) { int den; int scan; den = which_den(user); for (scan = 0; Ranks[rank].dens[scan] != -1; scan++) { if (den == Ranks[rank].dens[scan]) return (TRUE); } return (FALSE); } #endif #if 0 /* * print_roster * * Print the current race roster */ static void print_roster(void) { FILE *file; int race; int lane; int user; if ((file = fopen(PRINTER, "a")) == NULL) return; //!!! Change stdout to file for (race = 0; race < Nraces; race++) { fprintf(stdout, "Race %d\n", race + 1); for (lane = 0; lane < NLANES; lane++) { if (Roster[race][lane] != 0) { user = Roster[race][lane] - 1; fprintf(stdout, " %d %s %s\n", lane + 1, Database[user].car, Database[user].name); } } } fclose(file); } #endif #if 0 /* * race_rank * * Race all of the cars in a specific rank */ static void race_rank(int rank) { int den; char *status; int user; printf("We should be racing here: %d %s\n", rank, Ranks[rank]); status = find_status(rank); if (EQ(status, "No users")) { printf("There are no users selected for that race.\n"); return; } if (EQ(status, "Done")) { printf("That race is complete\n"); return; } /* * Make sure that every den in the rank has completed NHEATS races */ for (den = 0; Ranks[rank].dens[den] != -1; den++) { printf("See if den %d needs to race\n", Ranks[rank].dens[den]); if (!den_has_raced(Ranks[rank].dens[den], NHEATS)) { printf("Den %d needs to race\n", Ranks[rank].dens[den]); for (user = 0; user < Nusers; user++) { if (which_den(user) == Ranks[rank].dens[den]) { printf("Mark %s %s\n", Database[user].car, Database[user].name); Database[user].in_race = NHEATS; } else Database[user].in_race = 0; } schedule_first_set(); print_roster(); #if 0 run_race(); #endif } } /* for each den in rank select cars to race schedule all selected cars for the number of races print schedule for den to printer run races print winners of den if more than one den (assume max 2) select cars to race schedule all selected cars for the number of races print schedule for den to printer run races */ } #endif #if 0 /* * race_schedule * * Look through the schedule and run all races. */ /*lint -esym(771,lanes) */ /*lint -esym(644,lanes) */ static bool_t race_schedule(void) { int car; int ch; int lanes[NLANES]; int min_race; FILE *printer; int race; int rank[NLANES]; long int times[NLANES]; char *titles[NLANES]; long int total; int user; for (;;) { /* * Find the next race to run */ min_race = Nusers; for (user = 0; user < Nusers; user++) { if ((Database[user].racenum > 0) && (Database[user].racenum <= min_race)) { if (Database[user].racenum < min_race) { for (car = 0; car < NLANES; car++) lanes[car] = -1; } min_race = Database[user].racenum; for (car = 0; car < NRACES && Database[user].lane[car] != 0; ) car++; lanes[Database[user].lane[car - 1] - 1] = user; } } if (min_race == Nusers) return (TRUE); /* * Go run the selected race */ do { for (car = 0; car < NLANES; car++) { if (lanes[car] < 0) titles[car] = ""; else titles[car] = Database[lanes[car]].name; } clrscr(); if (!run_race(titles, rank, times, -1)) return (FALSE); /* * The race has completed. * See if the race controller wants to accept the race, * or rerun the race. */ for (;;) { gotoxy(1, 1); clreol(); highvideo(); cprintf("Do you want to accept the results (A)," " or rerun the race (R): "); normvideo(); ch = getxch(); if (ch == 'A' || ch == 'a' || ch == 'R' || ch == 'r') break; highvideo(); gotoxy(1, 2); cprintf("PLEASE USE *A* or *R*"); printf("\a"); } } while (ch != 'A' && ch != 'a'); /* * The race has been accepted. Save the results. */ for (car = 0; car < NLANES; car++) { if (lanes[car] >= 0) { user = lanes[car]; Database[user].racenum = 0; /* Race complete */ for (race = 0; race < NRACES && Database[user].lane[race] != 0; ) race++; Database[user].run[race - 1] = times[car]; } } /* * Print the results on the log printer */ if ((printer = fopen(PRINTER, "a")) != NULL) { for (car = 0; car < NLANES; car++) { if (lanes[car] >= 0) { user = lanes[car]; fprintf(printer, "%s %-30.30s", Database[user].car, Database[user].name); fprintf(printer, "%2ld.%03ld %d", times[car] / 1000, times[car] % 1000, rank[car]); total = 0L; for (race = 0; race < NRACES && Database[user].lane[race] != 0; race++) { total += Database[user].run[race]; } if (race > 2) { total /= race; fprintf(printer, "(average %2ld.%03ld)", total / 1000, total % 1000); } fprintf(printer, "\n"); } } fprintf(printer, "\n"); fprintf(printer, "\n"); fclose(printer); } write_database(); } } #endif #if 0 /* * schedule * * Schedule the races. * * There are several constraints to the schedule. Attempt to * schedule such that all of the constraints are fullfilled. * * Do not schedule a car for a lane so that the selected lane * will be used twice more than the least selected lane. * * Race cars with similar average times together. * * Never schedule a car against itself */ static bool_t schedule(void) { int lane; int ncars; int race; int rc; int user; /* We start with no car assigned to a race */ for (user = 0; user < Nusers; user++) Database[user].racenum = 0; /* Go through filling in races */ for (race = 1; ; race++) { ncars = 0; for (lane = 1; lane <= NLANES; lane++) { /* Find a user who is not currently scheduled with the * worst average time. No runs is the worst average time. */ user = find_contestant(lane); if (user != -1) { ncars++; Database[user].racenum = race; for (rc = 0; rc < NRACES; rc++) { if (Database[user].run[rc] == 0) { Database[user].lane[rc] = lane; break; } } } } if (ncars == 0) break; /* No entries */ } return (race > 1); } #endif #if 0 /* * short_schedule * * Schedule catch up races. * * Basically we will build a schedule of those cars which haven't * raced as often as other cars. Other than ensuring that we * use different lanes, don't worry about other constraints. */ static bool_t short_schedule(void) { int lane; int maxraces; int ncars; int race; int rc; int user; /* Find out what the maximum number of races run is */ clrscr(); maxraces = 0; for (user = 0; user < Nusers; user++) { if ((race = count_races(user)) > maxraces) maxraces = race; Database[user].racenum = 0; Database[user].scanned = FALSE; } /* Go through filling in races */ for (race = 1; ; race++) { ncars = 0; for (lane = 1; lane <= NLANES; lane++) { /* Find a user who is not currently scheduled with the * worst average time. No runs is the worst average time. */ user = find_short_contestant(lane, maxraces); if (user != -1) { ncars++; Database[user].racenum = race; for (rc = 0; rc < NRACES; rc++) { if (Database[user].run[rc] == 0) { Database[user].lane[rc] = lane; break; } } } } if (ncars == 0) break; /* No entries */ } return (race > 1); } #endif #if 0 /* * schedule_first_set * * Schedule the first set of races for each car. */ static void schedule_first_set(void) { int car; int heat; int lane; int user; Nraces = 0; Ncontrol = 0; car = 0; /* Car in race */ memset(Roster, '\0', sizeof(Roster)); for (heat = 0; heat < NHEATS; heat++) { for (user = 0; user < Nusers; user++) { if (Database[user].in_race > 0) { if (Database[user].run[heat] == 0) { lane = (car + heat) % NLANES; Database[user].lane[heat] = lane + 1; Roster[Nraces][lane] = user + 1; if (++car >= NLANES) { car = 0; Nraces++; } } } } /* We have scanned the list, clear off the entries. */ if (car != 0) { car = 0; Nraces++; } } } #endif #if 0 /* * which_den * * Generate the den number given a user. */ static int which_den(int user) { return (atoi(Database[user].car) / 10); } #endif