|
|
1.1 ! root 1: /* atc: simulate an air traffic controller at work */ ! 2: ! 3: #define NRAND 1 ! 4: #define die nrand ! 5: ! 6: #include <stdio.h> ! 7: #include <sys/ttyio.h> ! 8: #include <sys/param.h> ! 9: #include <sys/timeb.h> ! 10: #include <ctype.h> ! 11: #include <signal.h> ! 12: #include <pwd.h> ! 13: #include "ahdr.h" ! 14: ! 15: #define SYNTAX "Usage: atc [-s=<seed>] [-a=<airspace>] [-t=<time>]\n" ! 16: ! 17: /* size of terminal capability buffer */ ! 18: #define TCSIZE 1024 ! 19: ! 20: int cmdx; /* command located using same cursor positioning as screen */ ! 21: int cmdy; /* usually will be at 24 lines down */ ! 22: ! 23: char screen[MAXWIDTH][MAXHEIGHT]; /* contents of screen when no planes */ ! 24: ! 25: char *flowfile = 0; /* no default flow patterns */ ! 26: char *airfile = AIRFILE; ! 27: char *airspace = {"Apple1"}; /* default airspace is as on Apple */ ! 28: char *protofile = 0; /* no default protocol file */ ! 29: FILE *proto; /* stays open all the time if protocol */ ! 30: char *moviefile = 0; /* if in movie mode, here's the file */ ! 31: FILE *movie; /* and the file descriptor */ ! 32: int nextmovie; /* next time for a moviefile command */ ! 33: char *mcommand; /* next movie command */ ! 34: int width,height; /* these values set in the airspace file */ ! 35: char *bigname = 0; /* megastatistics file */ ! 36: FILE *bigstatsfile; /* megastatistics stream */ ! 37: ! 38: struct flow fpath[MAXPATHS]; ! 39: int maxflow; ! 40: int npaths; ! 41: ! 42: int nentry = 0; /* number of entries into the board */ ! 43: struct pstruct entry[EMAX]; ! 44: ! 45: int nairport = 0; ! 46: struct pstruct airport[AMAX]; ! 47: ! 48: int nnavaid = 0; ! 49: struct pstruct navaid[NMAX]; ! 50: ! 51: int nplanes = PMAX; ! 52: struct astruct plane[PMAX]; ! 53: ! 54: int initseed,seed,game_time,initgame_time,last_update; ! 55: time_t start_time; /* real time in seconds that game started */ ! 56: ! 57: time_t get_time(); ! 58: struct passwd *getpwuid(); ! 59: FILE *popen(); ! 60: ! 61: #define BUFSIZE 80 /* buffer for message */ ! 62: ! 63: int remain; ! 64: ! 65: int bound = 0; /* number of boundary errors */ ! 66: int system = 0; /* system errors */ ! 67: int crash = 0; /* crashed - out of fuel */ ! 68: int fuel = 0; /* out of fuel on runway - tow truck */ ! 69: int goaround = 0; /* missed an approach */ ! 70: int icmds = 0; /* number of cmds issued (including deferred) */ ! 71: int cmds = 0; /* number of cmds actually executed */ ! 72: ! 73: int fuelused = 0; ! 74: ! 75: int inaptot=0,outaptot=0; /* denominators for random entries/exits */ ! 76: int inawtot=0,outawtot=0; /* for airports and airways */ ! 77: ! 78: char tcbuf[TCSIZE]; ! 79: char cmbuf[100]; /* buffer for cursor motion strings */ ! 80: char clbuf[100]; /* clear screen sequence */ ! 81: ! 82: int rubout = 0; ! 83: ! 84: catchint(n) ! 85: int n; ! 86: { ! 87: rubout = 1; ! 88: signal (n, catchint); ! 89: } ! 90: ! 91: struct sgttyb tty_setting; ! 92: short tty_flags; ! 93: ! 94: main(argc,argv) ! 95: int argc; ! 96: char **argv; ! 97: { register char *arg; ! 98: ! 99: char *ttype; ! 100: char *getenv(); ! 101: ! 102: ttype = getenv("TERM"); ! 103: if (ttype == NULL || *ttype == '\0' || tgetent (tcbuf, ttype) <= 0) { ! 104: fprintf (stderr, "cannot determine terminal type\n"); ! 105: exit (1); ! 106: } ! 107: ! 108: /* get cursor motion and clear screen code into cmbuf and clbuf */ ! 109: { ! 110: char *p; ! 111: p = cmbuf; ! 112: tgetstr ("cm", &p); ! 113: p = clbuf; ! 114: tgetstr ("cl", &p); ! 115: } ! 116: ! 117: ioctl(0, TIOCGETP, &tty_setting); ! 118: tty_flags = tty_setting.sg_flags; ! 119: seed = 0; ! 120: for (arg = *++argv; --argc; arg = *++argv) /* read args 1 at a time */ ! 121: { if (arg[0] == '-') ! 122: switch(arg[1]) ! 123: { case 's': ! 124: if (arg[2] != '=') err(SYNTAX); ! 125: seed = atoi(&arg[3]); ! 126: break; ! 127: case 'S': ! 128: if (arg[2] != '=') err(SYNTAX); ! 129: bigname = &arg[3]; ! 130: break; ! 131: case 'a': ! 132: if (arg[2] != '=') err(SYNTAX); ! 133: airspace = &arg[3]; ! 134: break; ! 135: case 'u': ! 136: if (arg[2] != '=') err(SYNTAX); ! 137: airfile = &arg[3]; ! 138: break; ! 139: case 't': ! 140: if (arg[2] != '=') err(SYNTAX); ! 141: initgame_time = game_time = 59 + 60 * atoi(&arg[3]); ! 142: break; ! 143: case 'f': ! 144: if (arg[2] != '=') err(SYNTAX); ! 145: flowfile = &arg[3]; ! 146: break; ! 147: case 'p': /* run a protocol */ ! 148: if (arg[2] != '=') err(SYNTAX); ! 149: protofile = &arg[3]; ! 150: break; ! 151: case 'm': /* movie mode */ ! 152: if (arg[2] != '=') err(SYNTAX); ! 153: moviefile = &arg[3]; ! 154: break; ! 155: default : ! 156: err("Bad arg: %s\n",arg); ! 157: } ! 158: } ! 159: init(); /* set up flight plans, initialize screen */ ! 160: while (command()); /* get commands from user */ ! 161: done(1); ! 162: exit(0); ! 163: } ! 164: ! 165: #define CMDSIZE 40 ! 166: ! 167: int inter; /* non-zero if an alarm went off */ ! 168: intp() /* process interrupt from alarm */ ! 169: { inter++; ! 170: } ! 171: ! 172: ! 173: command() ! 174: { time_t now; ! 175: char cmd[CMDSIZE]; ! 176: char *c,utype,*d; ! 177: int i,j; ! 178: ! 179: for (utype = i = *(c=cmd) = 0; utype != RETURN; ) ! 180: { ! 181: if (moviefile) game_time--; /* 1 sec at a time? */ ! 182: else ! 183: { now = get_time(); ! 184: game_time = initgame_time - (now - start_time); ! 185: } ! 186: if (remain == 0) return(0); ! 187: if (game_time < 0) ! 188: { report(OUTOFTIME,0,0); ! 189: return(0); ! 190: } ! 191: if (i == 0) /* preserve partial command */ ! 192: { cursor(cmdx,cmdy); ! 193: printf("<%.2d> COMMAND: ",game_time/60); ! 194: } ! 195: if (last_update - game_time >= UPDATE) ! 196: { update(); ! 197: if (c != cmd) {BEEP;} /* cmd may be obsolete */ ! 198: } ! 199: while (moviefile && game_time <= nextmovie) ! 200: { if (bigname) pcmd(bigstatsfile,mcommand); ! 201: if (protofile) pcmd(proto,mcommand); ! 202: i = parse(mcommand); ! 203: if (!i) return i; ! 204: getmcmd(); ! 205: } ! 206: if (moviefile) continue; /* no longer accept inputs */ ! 207: cursor(cmdx+7,cmdy); ! 208: for (j=0; j<i; j++) putchar(cmd[j]); ! 209: signal(SIGALRM,intp);/* catch the alarm if it goes off */ ! 210: inter = 0; /* set to >0 if the alarm goes off */ ! 211: if (rubout) return 0; /* user really wants to quit */ ! 212: alarm(TIMEOUT); /* read for TIMEOUT sec unless he types */ ! 213: utype = getchar() & 0177; ! 214: alarm(0); ! 215: if (inter > 0) continue; /* didn't type anything */ ! 216: delmsg(cmdx,cmdy-1); /* erase previous echo if he types */ ! 217: cursor(cmdx+7,cmdy); ! 218: if (i != 2 || (*(c-1) != '*' && *(c-1) != ':')) ! 219: if (*cmd != '!' || i == 0) /* don't shift CDL filename */ ! 220: if (*cmd != '@'|| i == 0) /* don't shift location descrip */ ! 221: if (utype >= 'a' && utype <= 'z') ! 222: utype = utype - 'a' + 'A'; ! 223: if (utype == INSMODE) utype = RETURN; ! 224: if ((*c++ = utype) != RETURN) ! 225: { if (++i >= CMDSIZE) c--; ! 226: else ! 227: switch(utype) /* echo something reasonable */ ! 228: { ! 229: #ifdef ANNARBOR ! 230: case MIPAGE:/* check cursor controls */ ! 231: putchar(*--c = 'N'); ! 232: putchar(*++c = 'W'); ! 233: c++; i++; ! 234: break; ! 235: case HOME: ! 236: putchar(*--c = 'N'); ! 237: c++; ! 238: break; ! 239: case PLPAGE: ! 240: putchar(*--c = 'N'); ! 241: putchar(*++c = 'E'); ! 242: c++; i++; ! 243: break; ! 244: case MISRCH: ! 245: putchar(*--c = 'W'); ! 246: c++; ! 247: break; ! 248: case UPARROW: ! 249: putchar(*--c = '0'); ! 250: c++; ! 251: break; ! 252: case PLSRCH: ! 253: putchar(*--c = 'E'); ! 254: c++; ! 255: break; ! 256: case LEFTARROW: ! 257: putchar(*--c = 'S'); ! 258: putchar(*++c = 'W'); ! 259: c++; i++; ! 260: break; ! 261: case DOWNARROW: ! 262: putchar(*--c = 'S'); ! 263: c++; ! 264: break; ! 265: case RIGHTARROW: ! 266: putchar(*--c = 'S'); ! 267: putchar(*++c = 'E'); ! 268: c++; i++; ! 269: break; ! 270: case ':': /* like a * */ ! 271: putchar('*'); ! 272: break; ! 273: #endif ! 274: case BS: ! 275: if (i<=0) break; ! 276: if (i==1) { i = 0; break; } ! 277: putchar(BS); ! 278: c--; c--; i--; i--; ! 279: break; ! 280: default: putchar(utype); break; ! 281: } ! 282: } ! 283: } ! 284: *c = 0; ! 285: if (bigname) pcmd(bigstatsfile,cmd); ! 286: if (protofile) pcmd(proto,cmd); ! 287: return(parse(cmd)); ! 288: } ! 289: ! 290: pcmd(file,cmd) /* protocol a command */ ! 291: FILE *file; ! 292: char *cmd; ! 293: { register char *s; ! 294: ! 295: if (file == proto) ! 296: fprintf(file,"%5d: ",game_time); ! 297: else fprintf(file,"%5d: ",initgame_time - game_time); ! 298: for (s = cmd; *s && *s != RETURN; s++) fputc(*s,file); ! 299: fputc('\n',file); ! 300: } ! 301: ! 302: parse(cmd) /* command is terminated by RETURN */ ! 303: register char *cmd; ! 304: { time_t now; ! 305: register int i; ! 306: register struct astruct *pl; ! 307: char dest; ! 308: char *fullcmd; ! 309: char ubuf[10]; ! 310: ! 311: fullcmd = cmd; ! 312: switch(*cmd) /* parse 1 letter at a time */ ! 313: { case ' ': /* time advance */ ! 314: sprintf (ubuf, "%d", UPDATE); ! 315: echo("%s\" - ROGER",ubuf); ! 316: now = get_time(); ! 317: start_time = last_update - UPDATE - 1 - initgame_time + now; ! 318: break; ! 319: case '$': ! 320: return(0); ! 321: case '!': /* read a file of clearance directive lists */ ! 322: readcdl(++cmd); ! 323: break; ! 324: case '@': /* get a monitoring command */ ! 325: getmon(++cmd); ! 326: break; ! 327: default: /* should be airplane id */ ! 328: /* ASSUMPTION HERE: aircraft are A-Z */ ! 329: if (*cmd < 'A' || *cmd > 'Z') ! 330: { echo("%s - UNABLE",fullcmd); ! 331: BEEP; ! 332: break; ! 333: } ! 334: for (pl = &plane[i=0]; i < nplanes; i++,pl++) ! 335: if (pl->a_id == *cmd) break; ! 336: if (i == nplanes) ! 337: { echo("%s - NOT ACTIVE",fullcmd); ! 338: BEEP; ! 339: break; ! 340: } ! 341: ! 342: if (cmd[1] == '?') /* o.k. to cancel plans */ ! 343: { if (pl->a_active != ACTIVE && ! 344: pl->a_active != WAITING) ! 345: { echo("%s - NOT ACTIVE",fullcmd); ! 346: BEEP; ! 347: break; ! 348: } ! 349: } ! 350: else if (cmd[1] == RETURN) /* info request only */ ! 351: { if (pl->a_active != ACTIVE && ! 352: pl->a_active != APPROACHING && ! 353: pl->a_active != WAITING) ! 354: { echo("%s - NOT ACTIVE",fullcmd); ! 355: BEEP; ! 356: break; ! 357: } ! 358: } ! 359: else ! 360: { if (pl->a_active != ACTIVE && pl->a_active != WAITING) ! 361: { echo("%s - NOT ACTIVE",fullcmd); ! 362: BEEP; ! 363: break; ! 364: } ! 365: if (pl->a_active==ACTIVE && pl->a_nextz == 0 && cmd[1]!=RETURN) ! 366: { echo("%s - LANDING",fullcmd); ! 367: BEEP; ! 368: break; ! 369: } ! 370: } ! 371: switch(*++cmd) /* parse second char */ ! 372: { case RETURN: /* info request */ ! 373: strip(pl,cmdy+1,VERBOSE); ! 374: break; ! 375: case 'A': /* change altitude */ ! 376: if (*++cmd < '0' || *cmd > '5') ! 377: { echo("%s - UNABLE",fullcmd); ! 378: BEEP; ! 379: } ! 380: else ! 381: { pl->a_nextz = *cmd - '0'; ! 382: echo("%s - ROGER",fullcmd); ! 383: cmds++; ! 384: icmds++; ! 385: } ! 386: break; ! 387: case 'H': /* hold at beacon */ ! 388: pl->a_hold = 1; ! 389: pl->a_clear = 0; ! 390: echo("%s - ROGER",fullcmd); ! 391: cmds++; ! 392: icmds++; ! 393: break; ! 394: case 'L': /* left turn */ ! 395: rdturn(pl,'L',++cmd,fullcmd); ! 396: break; ! 397: case 'R': /* right turn */ ! 398: rdturn(pl,'R',++cmd,fullcmd); ! 399: break; ! 400: case 'T': /* shortest turn */ ! 401: rdturn(pl,'T',++cmd,fullcmd); ! 402: break; ! 403: case '*': /* clearance at navaid */ ! 404: case ':': ! 405: dest = *++cmd; ! 406: for (i=0; i<nentry; i++) /* vector to entry? */ ! 407: if (dest == entry[i].p_sym) break; ! 408: if (pl->a_hold == 1) pl->a_hold = 0; ! 409: if (i<nentry) ! 410: { echo("%s - ROGER",fullcmd); ! 411: pl->a_clear = dest; ! 412: cmds++; ! 413: icmds++; ! 414: break; ! 415: } ! 416: for (i=0; i<nairport; i++) ! 417: if (dest == airport[i].p_sym) break; ! 418: if (i<nairport) ! 419: { echo("%s - ROGER",fullcmd); ! 420: pl->a_clear = dest; ! 421: cmds++; ! 422: icmds++; ! 423: break; ! 424: } ! 425: echo("%s - UNABLE",fullcmd); ! 426: BEEP; ! 427: break; ! 428: case '?': /* delete delayed commands */ ! 429: ddelay(pl); ! 430: echo("%s - ROGER",fullcmd); ! 431: cmds++; ! 432: icmds++; ! 433: break; ! 434: default: /* airport id? - maybe cursor motions? */ ! 435: echo("%s - UNABLE",fullcmd); ! 436: BEEP; ! 437: break; ! 438: } ! 439: } ! 440: return(1); ! 441: } ! 442: ! 443: getmon(cmd) /* get monitor command from command line */ ! 444: register char *cmd; ! 445: { int x,y; ! 446: register char *start; ! 447: ! 448: start = cmd; ! 449: if (getloc(cmd,&x,&y) == 0) /* where did you say? */ ! 450: { echo("%s - BAD LOC SPEC",cmd); ! 451: BEEP; ! 452: return; ! 453: } ! 454: while (*cmd) /* pick up each command that happens here */ ! 455: { while (*cmd && *cmd != ',') cmd++; ! 456: if (*cmd == 0) return; /* read last command */ ! 457: putlist(start,x,y,++cmd); /* put the next command on a list */ ! 458: } ! 459: } ! 460: ! 461: ddelay(pl) /* delete any delayed commands from this plane's list */ ! 462: struct astruct *pl; ! 463: { struct list *l,*next; ! 464: ! 465: if (pl->a_plan == 0) return; ! 466: for (l = pl->a_plan; l; l = next) ! 467: { next = l->l_next; ! 468: free(l); ! 469: } ! 470: pl->a_plan = 0; ! 471: } ! 472: ! 473: putlist(start,x,y,cmd) /* put some commands on the list for a plane */ ! 474: char *start; ! 475: int x,y; ! 476: char *cmd; ! 477: { register struct list *l; ! 478: register struct astruct *p; ! 479: register char *c,*d; ! 480: int i; ! 481: ! 482: d = cmd; ! 483: for (i = 0; cmd[i] != ',' && cmd[i] != 0 && cmd[i] != RETURN; i++) ! 484: if (i != 2 || (cmd[i-1] != '*' && cmd[i-1] != ':')) ! 485: if (cmd[i] >= 'a' && cmd[i] <= 'z') cmd[i] += 'A' - 'a'; ! 486: for (p = &plane[i = 0]; i < nplanes; i++,p++) ! 487: if (p->a_id == *cmd) break; ! 488: if (i == nplanes) ! 489: { echo("BAD PLANE SPEC: %s",cmd); ! 490: BEEP; ! 491: return; ! 492: } ! 493: l = p->a_plan; /* go to the CDL for this plane */ ! 494: if (p->a_plan == 0) ! 495: l = p->a_plan = (struct list *) malloc(sizeof (struct list)); ! 496: else ! 497: { for (l = p->a_plan; l->l_next != 0; l = l->l_next); /* eol */ ! 498: l->l_next = (struct list *) malloc(sizeof (struct list)); ! 499: l = l->l_next; ! 500: } ! 501: l->l_next = 0; ! 502: l->l_x = x; ! 503: l->l_y = y; ! 504: c = l->l_cmd; ! 505: while (*cmd != ',' && *cmd != 0 && *cmd != RETURN) ! 506: *c++ = *cmd++; ! 507: *c++ = RETURN; ! 508: *c = 0; ! 509: for (c = d; *c; c++) if (*c == RETURN) *c = 0; /* return damages dspla*/ ! 510: echo("%s - WILCO",d); ! 511: icmds++; ! 512: /* copy the verbatim direction used by the guy */ ! 513: for (c = start, d = l->l_loc; *c != ','; *d++ = *c++); ! 514: *d = 0; ! 515: } ! 516: ! 517: ! 518: getloc(cmd,px,py) /* get location description from a monitor command */ ! 519: char *cmd; ! 520: int *px,*py; ! 521: { register char l,*m; /* location */ ! 522: register int i; ! 523: register struct pstruct *p; ! 524: int dx,dy; ! 525: char buf[300]; ! 526: ! 527: l = *(m = cmd); ! 528: p = 0; ! 529: for (i = 0; i < nentry; i++) ! 530: if (entry[i].p_sym == l) p = &entry[i]; ! 531: for (i = 0; i < nairport; i++) ! 532: if (airport[i].p_sym == l) p = &airport[i]; ! 533: for (i = 0; i < nnavaid; i++) ! 534: if (navaid[i].p_sym == l) p = &navaid[i]; ! 535: if (p == 0) return 0; ! 536: *px = p->p_x; ! 537: *py = p->p_y; ! 538: m++; ! 539: while (*m != ',') /* read through the other directions */ ! 540: { dx = dy = 0; ! 541: switch(*m) /* NSEW */ ! 542: { case 'n': dy = -1; break; ! 543: case 's': dy = 1; break; ! 544: case 'e': dx = 1; break; ! 545: case 'w': dx = -1; break; ! 546: default: ! 547: sprintf(buf,"Got %c instead of n,s,e,w",*m); ! 548: msg(cmdx,cmdy+3,buf); ! 549: return 0; ! 550: } ! 551: if (*++m == 'w') { dx = -1; m++;} /* NW or SW */ ! 552: else if (*m == 'e') { dx = 1; m++;} /* NE or SE */ ! 553: if (*m < '0' || *m > '9') ! 554: { sprintf(buf,"Got %c instead of digit",*m); ! 555: msg(cmdx,cmdy+3,buf); ! 556: return 0; ! 557: } ! 558: for (i = 0; *m >= '0' && *m <= '9'; m++) ! 559: i = 10 * i + *m - '0'; ! 560: *px += i * dx; ! 561: *py += i * dy; ! 562: } ! 563: return 1; ! 564: } ! 565: ! 566: readcdl(fname) /* fname points at CDL filename, \r-terminated */ ! 567: char *fname; ! 568: { FILE *cdlfile; ! 569: char *p; ! 570: ! 571: while (*fname == ' ') fname++; /* skip initial blanks */ ! 572: for (p = fname; *p && *p != RETURN; p++); /* remove newline */ ! 573: *p = 0; ! 574: if ((cdlfile = fopen(fname,"r")) == NULL) ! 575: { echo("Cannot open %s",fname); ! 576: return; ! 577: } ! 578: echo("Reading CDL file...",0); ! 579: fclose(cdlfile); ! 580: } ! 581: ! 582: ! 583: rdturn(pl,dir,cmd,fullcmd) ! 584: struct astruct *pl; ! 585: char dir; ! 586: char *cmd,*fullcmd; ! 587: { int i,ok,newx,newy,turncount; ! 588: ! 589: if (pl->a_nextz == 0) ! 590: { echo("%s - WRONG WAY",fullcmd); ! 591: BEEP; ! 592: return; ! 593: } ! 594: ok = 1; /* check whether this is a legal command */ ! 595: newx = newy = 0; ! 596: for (i=0; i<2; i++) /* look at next 2 chars */ ! 597: switch(cmd[i]) ! 598: { case RETURN: ! 599: if (i == 0) ! 600: { echo("%s - WHICH WAY?",fullcmd); ! 601: BEEP; ! 602: return; ! 603: } ! 604: break; ! 605: case '0': ! 606: if (i == 1) /* can't be second char */ ! 607: { ok = 0; ! 608: break; ! 609: } ! 610: pl->a_dxnew = 0; ! 611: pl->a_dynew = 0; ! 612: pl->a_turn = 0; ! 613: pl->a_clear = 0; ! 614: pl->a_hold = 0; ! 615: echo("%s - ROGER",fullcmd); ! 616: cmds++; ! 617: icmds++; ! 618: return; ! 619: case 'N': ! 620: newy = -1; ! 621: break; ! 622: case 'S': ! 623: newy = 1; ! 624: break; ! 625: case 'E': ! 626: newx = 1; ! 627: break; ! 628: case 'W': ! 629: newx = -1; ! 630: break; ! 631: default: /* numbers (e.g.) no longer acceptable */ ! 632: ok = 0; ! 633: break; ! 634: } ! 635: if (ok) ! 636: { echo("%s - ROGER",fullcmd); ! 637: cmds++; ! 638: icmds++; ! 639: pl->a_turn = dir; /* will replace 'T' with 'L' or 'R' */ ! 640: pl->a_dxnew = newx; pl->a_dynew = newy; ! 641: pl->a_hold = pl->a_clear = 0; ! 642: if (dir == 'T') ! 643: { newx = pl->a_dx; /* start with this direction */ ! 644: newy = pl->a_dy; /* and turn until done */ ! 645: for (turncount = 1; turncount < 9; turncount++) ! 646: if (turn(&newx,&newy,'L',pl->a_dxnew,pl->a_dynew)) ! 647: break; ! 648: if (turncount <= 4) pl->a_turn = 'L'; ! 649: else pl->a_turn = 'R'; ! 650: } ! 651: } ! 652: else ! 653: { echo("%s - UNABLE",fullcmd); ! 654: BEEP; ! 655: } ! 656: } ! 657: ! 658: echo(format,cmd) ! 659: char *format,*cmd; ! 660: { char *c; ! 661: char mbuf[BUFSIZE]; ! 662: ! 663: for (c=cmd; *c; c++) if (*c == RETURN) *c = 0; ! 664: sprintf(mbuf,format,cmd); ! 665: msg(cmdx,cmdy-1,mbuf); ! 666: } ! 667: ! 668: int parity = 0; /* props move every other update */ ! 669: ! 670: update() ! 671: { parity = 1 - parity; ! 672: last_update -= UPDATE; /* must average out to every UPDATE secs */ ! 673: moveplanes(); ! 674: printplans(); ! 675: if (bigname) activity(); ! 676: } ! 677: ! 678: activity() /* number of active planes to megastats file */ ! 679: { register int i,active,waiting,approaching,planned; ! 680: struct astruct *p; ! 681: ! 682: for (i=active=waiting=approaching=planned=0; i < nplanes; i++) ! 683: { p = &plane[i]; ! 684: switch(p->a_active) ! 685: { case ACTIVE: ! 686: active++; ! 687: break; ! 688: case WAITING: ! 689: waiting++; ! 690: break; ! 691: case APPROACHING: ! 692: approaching++; ! 693: break; ! 694: } ! 695: if (p->a_plan && p->a_active != DONE) planned++; ! 696: } ! 697: fprintf(bigstatsfile,"%5d: %d active, %d approaching, %d waiting. ", ! 698: initgame_time - game_time, active,approaching,waiting); ! 699: fprintf(bigstatsfile,"%d planned.\n",planned); ! 700: for (i = 0; i < nplanes; i++) ! 701: { int a; ! 702: ! 703: p = &plane[i]; ! 704: a = p->a_active; ! 705: if (a == ACTIVE || a == APPROACHING || a == WAITING) ! 706: { p->a_load += active; ! 707: p->a_ticks++; ! 708: p->a_planned += planned; ! 709: } ! 710: if (a == APPROACHING || a == WAITING) ! 711: { p->a_aprev += active; ! 712: p->a_prev++; ! 713: p->a_pprev += planned; ! 714: p->a_pplanned = (p->a_plan? YES : NO); ! 715: } ! 716: } ! 717: } ! 718: ! 719: moveplanes() ! 720: { register struct astruct *pl; ! 721: register int i,j; ! 722: register int nextx,nexty; ! 723: int ax,ay,oldx,oldy; ! 724: struct pstruct *dst; ! 725: ! 726: for (pl = &plane[i = 0]; i < PMAX; i++, pl++) ! 727: { if (parity && pl->a_type == PROP) ! 728: { pl->a_lastz = pl->a_z; ! 729: if (pl->a_active == LANDING) pl->a_active = DONE; ! 730: continue; ! 731: } ! 732: switch(pl->a_active) ! 733: { case INACTIVE: ! 734: if (initgame_time - game_time + FPTHRESH>= pl->a_stime ! 735: && !pl->a_sair) ! 736: pl->a_active = APPROACHING; ! 737: ! 738: case APPROACHING: ! 739: if (initgame_time - game_time>= pl->a_stime) ! 740: { pl->a_active = ACTIVE; ! 741: if (pl->a_sair) pl->a_active = WAITING; ! 742: nextx = pl->a_x; ! 743: nexty = pl->a_y; ! 744: } ! 745: break; ! 746: ! 747: case LANDING: /* to allow for conflicts */ ! 748: pl->a_active = DONE; ! 749: break; ! 750: ! 751: case ACTIVE: ! 752: pl->a_dist++; /* increment distance traveled */ ! 753: nextx = pl->a_x + pl->a_dx; ! 754: nexty = pl->a_y + pl->a_dy; ! 755: if (nextx < 0 || nexty < 0 || ! 756: nextx >= width || nexty >= height) ! 757: { leavescreen(pl); ! 758: break; ! 759: } ! 760: ! 761: /* turning? */ ! 762: if (pl->a_turn) /* turn 1 tick in right direction */ ! 763: if (turn(&pl->a_dx,&pl->a_dy, ! 764: pl->a_turn,pl->a_dxnew,pl->a_dynew)) ! 765: pl->a_turn = pl->a_dxnew = pl->a_dynew = 0; ! 766: ! 767: ! 768: if (pl->a_dair) /* landing? */ ! 769: { dst = &airport[pl->a_dest]; ! 770: ax = dst->p_x; ! 771: ay = dst->p_y; ! 772: if (ax == nextx && ay == nexty) ! 773: if (pl->a_z == 0 && ! 774: pl->a_dx == dst->p_dx && ! 775: pl->a_dy == dst->p_dy) ! 776: { pl->a_active = LANDING; /* landed */ ! 777: erase(pl->a_x,pl->a_y); ! 778: pl->a_x = nextx; ! 779: pl->a_y = nexty; ! 780: remain--; ! 781: } ! 782: else if (pl->a_nextz == 0) /* flyby */ ! 783: { pl->a_nextz = 1; /* down too late*/ ! 784: goaround++; ! 785: report(GOAROUND,pl); ! 786: } ! 787: } ! 788: ! 789: /* changing altitude? */ ! 790: if (pl->a_z > pl->a_nextz) ! 791: pl->a_lastz = pl->a_z--; ! 792: else if (pl->a_z < pl->a_nextz) ! 793: pl->a_lastz = pl->a_z++; ! 794: else pl->a_lastz = pl->a_z; ! 795: ! 796: /* out of fuel? */ ! 797: if (--pl->a_fuel <= 0) ! 798: { crash++; ! 799: report(CRASH,pl); ! 800: pl->a_active = DONE; ! 801: remain--; ! 802: erase(pl->a_x,pl->a_y); ! 803: } ! 804: if (pl->a_type == JET) fuelused += 5; ! 805: else fuelused += 1; ! 806: break; ! 807: ! 808: case WAITING: /* waiting for takeoff */ ! 809: if (--pl->a_fuel <= 0) /* out of fuel on ground? */ ! 810: { fuel++; ! 811: if (bigname) freport(pl); ! 812: report(FUEL,pl); ! 813: pl->a_active = DONE; ! 814: remain--; ! 815: } ! 816: if (pl->a_nextz != 0) ! 817: { pl->a_z++; /* take off */ ! 818: pl->a_active = ACTIVE; ! 819: pl->a_dist++; ! 820: } ! 821: nextx = pl->a_x + pl->a_dx; ! 822: nexty = pl->a_y + pl->a_dy; ! 823: ! 824: /* turning? */ ! 825: if (pl->a_turn) /* turn 1 tick in right direction */ ! 826: if (turn(&pl->a_dx,&pl->a_dy, ! 827: pl->a_turn,pl->a_dxnew,pl->a_dynew)) ! 828: pl->a_turn = pl->a_dxnew = pl->a_dynew = 0; ! 829: ! 830: if (pl->a_type == JET) fuelused += 5; ! 831: else fuelused += 1; ! 832: break; ! 833: ! 834: case DONE: /* off the screen */ ! 835: break; ! 836: } ! 837: if (pl->a_active != ACTIVE) continue; ! 838: oldx = pl->a_x; ! 839: oldy = pl->a_y; ! 840: pl->a_x = nextx; ! 841: pl->a_y = nexty; ! 842: cursor(nextx,nexty); ! 843: printf("%c%c",pl->a_id,(pl->a_z>9? '^' : pl->a_z+'0')); ! 844: erase(oldx,oldy); ! 845: if (pl->a_hold || pl->a_clear) ! 846: for (j = 0; j < nnavaid; j++) /* at a navaid? */ ! 847: if (screen[nextx][nexty] == navaid[j].p_sym) ! 848: { donavaid(pl); /* right navaid? */ ! 849: break; ! 850: } ! 851: } ! 852: conflict(); ! 853: delays(); /* execute any applicable delayed commands */ ! 854: } ! 855: ! 856: freport(pl) /* report to big stats file about tow truck */ ! 857: struct astruct *pl; ! 858: { ! 859: fprintf(bigstatsfile,"%5d: %c out of fuel on runway.\n", ! 860: initgame_time - game_time,pl->a_id); ! 861: } ! 862: ! 863: delays() /* execute any applicable delayed actions */ ! 864: { register struct astruct *p; ! 865: register int i; ! 866: register struct list *l,*last; ! 867: ! 868: /* for each plane, if it is active and if it has a command pending, ! 869: * and if it is at the right place for the command, then execute it. ! 870: */ ! 871: for (i = 0; i < PMAX; i++) ! 872: { p = &plane[i]; ! 873: if (p->a_active != ACTIVE) continue; ! 874: if (p->a_plan == 0) continue; ! 875: last = 0; ! 876: for (l = p->a_plan; l; ) ! 877: { if (p->a_x != l->l_x || p->a_y != l->l_y) ! 878: { ! 879: last = l; ! 880: l = l->l_next; ! 881: } ! 882: else /* it matched */ ! 883: { ! 884: parse(l->l_cmd); /* execute the command */ ! 885: ! 886: /* now delete the command from the list */ ! 887: if (last == 0) /* it was the first one */ ! 888: { p->a_plan = l->l_next; ! 889: free(l); ! 890: l = p->a_plan; ! 891: /* last stays at 0 */ ! 892: } ! 893: else ! 894: { last->l_next = l->l_next; ! 895: free(l); ! 896: l = last->l_next; ! 897: /* last stays where it was */ ! 898: } ! 899: } ! 900: } ! 901: } ! 902: } ! 903: ! 904: donavaid(pl) /* take appropriate action at navaid */ ! 905: struct astruct *pl; /* the plane has either been vectored or told to hold */ ! 906: { register struct pstruct *d; ! 907: register int i; ! 908: ! 909: if (pl->a_hold) ! 910: { pl->a_hold = 2; /* will be holding now */ ! 911: pl->a_turn = 'L'; /* and turning continuously to the left */ ! 912: pl->a_dxnew = pl->a_dx; /* until it reaches this heading agn*/ ! 913: pl->a_dynew = pl->a_dy; ! 914: } ! 915: if (pl->a_clear) ! 916: { pl->a_turn = pl->a_dxnew = pl->a_dynew = pl->a_hold = 0; ! 917: /* see what we're vectoring to */ ! 918: for (d = &entry[i=0]; i < nentry; i++,d++) ! 919: if (d->p_sym == pl->a_clear) break; ! 920: if (i != nentry) /* yes, it was a navaid */ ! 921: { pl->a_dx = -d->p_dx; /* opposite of entry heading*/ ! 922: pl->a_dy = -d->p_dy; ! 923: pl->a_clear = 0; ! 924: return; ! 925: } ! 926: for (d = &airport[i=0]; i < nairport; i++,d++) ! 927: if (d->p_sym == pl->a_clear) break; ! 928: if (i == nairport) return; /* program bug - cleared to ?? */ ! 929: pl->a_dx = d->p_dx; /* assume landing heading for airport */ ! 930: pl->a_dy = d->p_dy; ! 931: pl->a_clear = 0; ! 932: ! 933: if (pl->a_hold == 1) ! 934: pl->a_hold = pl->a_dxnew = pl->a_dynew = 0; ! 935: else if (pl->a_hold == 0) ! 936: pl->a_dxnew = pl->a_dynew = 0; ! 937: return; ! 938: } ! 939: } ! 940: ! 941: turn(newx,newy,direc,dx,dy) /* messy - enumeration of all cases */ ! 942: int *newx,*newy; /* returned values of new heading */ ! 943: char direc; ! 944: int dx,dy; ! 945: { int x,y; ! 946: ! 947: x = *newx; ! 948: y = *newy; ! 949: switch(direc) ! 950: { case 'L': /* cases would be more efficient, but this is clearer*/ ! 951: if (x== -1 && y== -1) {*newx= -1; *newy= 0; break;} ! 952: if (x== -1 && y== 0) {*newx= -1; *newy= 1; break;} ! 953: if (x== -1 && y== 1) {*newx= 0; *newy= 1; break;} ! 954: if (x== 0 && y== -1) {*newx= -1; *newy= -1; break;} ! 955: if (x== 0 && y== 1) {*newx= 1; *newy= 1; break;} ! 956: if (x== 1 && y== -1) {*newx= 0; *newy= -1; break;} ! 957: if (x== 1 && y== 0) {*newx= 1; *newy= -1; break;} ! 958: if (x== 1 && y== 1) {*newx= 1; *newy= 0; break;} ! 959: break; ! 960: case 'R': ! 961: if (x== -1 && y== -1) {*newx= 0; *newy= -1; break;} ! 962: if (x== -1 && y== 0) {*newx= -1; *newy= -1; break;} ! 963: if (x== -1 && y== 1) {*newx= -1; *newy= 0; break;} ! 964: if (x== 0 && y== -1) {*newx= 1; *newy= -1; break;} ! 965: if (x== 0 && y== 1) {*newx= -1; *newy= 1; break;} ! 966: if (x== 1 && y== -1) {*newx= 1; *newy= 0; break;} ! 967: if (x== 1 && y== 0) {*newx= 1; *newy= 1; break;} ! 968: if (x== 1 && y== 1) {*newx= 0; *newy= 1; break;} ! 969: break; ! 970: } ! 971: if (*newx == dx && *newy == dy) return(1); /* finished turn */ ! 972: else return(0); ! 973: } ! 974: ! 975: ! 976: report(error,plane1,plane2) ! 977: int error; ! 978: struct astruct *plane1,*plane2; ! 979: { char mbuf[BUFSIZE]; ! 980: int i; ! 981: ! 982: putchar(BELL); ! 983: switch(error) ! 984: { case FUEL: ! 985: sprintf(mbuf,"Tow truck called for %c (%c)", ! 986: plane1->a_id,airport[plane1->a_start].p_sym); ! 987: break; ! 988: case CRASH: ! 989: sprintf(mbuf,"PLANE %c OUT OF GAS",plane1->a_id); ! 990: break; ! 991: case BOUND: ! 992: sprintf(mbuf,"Boundary error - %c",plane1->a_id); ! 993: break; ! 994: case SYSTEM: ! 995: sprintf(mbuf,"%c AND %c: SYSTEM ERROR", ! 996: plane1->a_id, plane2->a_id); ! 997: break; ! 998: case GOAROUND: ! 999: sprintf(mbuf,"%c missed approach",plane1->a_id); ! 1000: break; ! 1001: case OUTOFTIME: ! 1002: sprintf(mbuf,"Out of time: %d remain",remain); ! 1003: break; ! 1004: } ! 1005: msg(cmdx,cmdy+2,mbuf); ! 1006: } ! 1007: ! 1008: ! 1009: ! 1010: leavescreen(pl) ! 1011: struct astruct *pl; ! 1012: { struct pstruct *e; ! 1013: ! 1014: pl->a_active = DONE; ! 1015: pl->a_dist++; ! 1016: erase(pl->a_x,pl->a_y); ! 1017: remain--; ! 1018: e = &entry[pl->a_dest]; ! 1019: if (pl->a_z == 5 && !pl->a_dair && /* leaving at non-airport, 5K' */ ! 1020: screen[pl->a_x][pl->a_y] == e->p_sym && /* right exit */ ! 1021: pl->a_dx == -e->p_dx && pl->a_dy == -e->p_dy && /* right direc */ ! 1022: pl->a_turn == 0) /* and not turning */ ! 1023: return(0); ! 1024: bound++; ! 1025: if (bigname) ! 1026: { fprintf(bigstatsfile,"%5d: Boundary error - plane %c ", ! 1027: initgame_time - game_time,pl->a_id); ! 1028: fprintf(bigstatsfile,"left at %d000' ",pl->a_z); ! 1029: if (pl->a_nextz > pl->a_z) ! 1030: fprintf(bigstatsfile,"climbing to %d000'",pl->a_nextz); ! 1031: if (pl->a_nextz < pl->a_z) ! 1032: fprintf(bigstatsfile,"descending to %d000'",pl->a_nextz); ! 1033: fprintf(bigstatsfile, ! 1034: "\n\tPosition: (%d,%d) Bearing: ",pl->a_x,pl->a_y); ! 1035: if (pl->a_dy < 0) fprintf(bigstatsfile,"N"); ! 1036: else if (pl->a_dy > 0) fprintf(bigstatsfile,"S"); ! 1037: if (pl->a_dx > 0) fprintf(bigstatsfile,"E"); ! 1038: else if (pl->a_dx < 0) fprintf(bigstatsfile,"W"); ! 1039: if (pl->a_turn) ! 1040: { fprintf(bigstatsfile," turning %c to ",pl->a_turn); ! 1041: if (pl->a_dynew < 0) fprintf(bigstatsfile,"N"); ! 1042: else if (pl->a_dynew > 0) fprintf(bigstatsfile,"S"); ! 1043: if (pl->a_dxnew > 0) fprintf(bigstatsfile,"E"); ! 1044: else if (pl->a_dxnew < 0) fprintf(bigstatsfile,"W"); ! 1045: } ! 1046: fprintf(bigstatsfile,".\n"); ! 1047: } ! 1048: report(BOUND,pl); ! 1049: return(0); ! 1050: } ! 1051: ! 1052: conflict() /* check each pair of planes for problems */ ! 1053: { register struct astruct *q,*p; ! 1054: register int i,j,k; ! 1055: register int miss; ! 1056: ! 1057: for (p = &plane[k=1]; k < nplanes; k++,p++) ! 1058: { if (p->a_active != ACTIVE && p->a_active != LANDING) continue; ! 1059: for (q = &plane[i=0]; i < k; i++,q++) ! 1060: { if (q->a_active != ACTIVE) continue; ! 1061: if (q->a_z != p->a_z && q->a_z != p->a_lastz && ! 1062: q->a_lastz != p->a_z && q->a_lastz != p->a_lastz) ! 1063: continue; ! 1064: miss = abs(q->a_x - p->a_x); ! 1065: j = abs(q->a_y - p->a_y); ! 1066: if (j>miss) miss=j; ! 1067: if (miss < 3) /* too close - system error */ ! 1068: { system++; ! 1069: if (bigname) bigsyserr(p,q); ! 1070: report(SYSTEM,p,q); ! 1071: break; ! 1072: } ! 1073: } ! 1074: } ! 1075: } ! 1076: ! 1077: bigsyserr(p,q) /* spew sys err info into the big stats file */ ! 1078: struct astruct *p,*q; ! 1079: { ! 1080: fprintf(bigstatsfile, ! 1081: "%5d: System error between %c (%d,%d,%d000) and %c (%d,%d,%d000)\n", ! 1082: initgame_time - game_time,p->a_id,p->a_x,p->a_y,p->a_z, ! 1083: q->a_id,q->a_x,q->a_y,q->a_z); ! 1084: } ! 1085: ! 1086: erase(x,y) ! 1087: int x,y; ! 1088: { register struct astruct *p; ! 1089: register int i; ! 1090: ! 1091: if (x<0 || y < 0) return; ! 1092: if (x>=width || y>=height) return; ! 1093: cursor(x,y); ! 1094: printf("%c ",screen[x][y]); ! 1095: for (p = &plane[i=0]; i < nplanes; i++,p++) ! 1096: if (p->a_active == ACTIVE && x == p->a_x && y == p->a_y) ! 1097: { cursor(x,y); ! 1098: printf("%c%c",p->a_id,(p->a_z>9?'^':p->a_z+'0')); ! 1099: } ! 1100: } ! 1101: ! 1102: ! 1103: int msglen[MAXHEIGHT]; /* length of message string on this row */ ! 1104: ! 1105: init() ! 1106: { int i,j; ! 1107: char c,mbuf[BUFSIZE]; ! 1108: int pcompare(); ! 1109: FILE *statfile; ! 1110: struct passwd *pw; ! 1111: time_t now; ! 1112: char *p,*ct; ! 1113: extern char *ctime(); ! 1114: int nearlies; ! 1115: ! 1116: if ((statfile = fopen(STATSFILE,"a")) != NULL) ! 1117: { pw = getpwuid(getuid()); ! 1118: now = get_time(); ! 1119: ct = ctime(&now); ! 1120: for (p= &ct[4]; p <= &ct[16]; p++) fputc(*p,statfile); ! 1121: fprintf(statfile,"%8s\n",pw->pw_name); ! 1122: fclose(statfile); ! 1123: } ! 1124: ! 1125: /* go into raw mode, no echo */ ! 1126: if (!moviefile) ! 1127: { ioctl(0, TIOCGETP, &tty_setting); ! 1128: tty_flags = tty_setting.sg_flags; ! 1129: #ifdef CBREAK ! 1130: tty_setting.sg_flags |= CBREAK; ! 1131: tty_setting.sg_flags &= ~CRMOD; ! 1132: #else ! 1133: tty_setting.sg_flags |= RAW; ! 1134: #endif ! 1135: tty_setting.sg_flags &= ~ECHO; ! 1136: ioctl(0, TIOCSETP, &tty_setting); ! 1137: if (signal (SIGINT, SIG_IGN) != SIG_IGN) ! 1138: signal (SIGINT, catchint); ! 1139: if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) ! 1140: signal (SIGQUIT, catchint); ! 1141: } ! 1142: ! 1143: for (i = 0; i < MAXHEIGHT; i++) ! 1144: msglen[i] = 0; ! 1145: ! 1146: for (i=0; i<MAXWIDTH; i++) for (j=0; j<MAXHEIGHT; j++) ! 1147: screen[i][j] = '.'; ! 1148: ! 1149: if (moviefile) ! 1150: { if ((movie = fopen(moviefile,"r")) == NULL) ! 1151: err("Cannot open %s for reading.\n",moviefile); ! 1152: minit(); /* initialize from movie file */ ! 1153: } ! 1154: ! 1155: if (seed == 0) seed = get_time(); ! 1156: initseed = seed; ! 1157: #ifdef vax ! 1158: srand(seed); ! 1159: #else ! 1160: srandom(seed); /* initialize random number generator */ ! 1161: #endif ! 1162: ! 1163: clearscreen(); ! 1164: readspace(); ! 1165: ! 1166: ! 1167: cmdx = width; /* start command just to right of display */ ! 1168: cmdy = height-4; /* and a ways from the bottom */ ! 1169: display(); /* initial display */ ! 1170: for (i=0; i<nairport; i++) ! 1171: { sprintf(mbuf,"%c : %c%c", ! 1172: screen[airport[i].p_x][airport[i].p_y], ! 1173: (j = airport[i].p_dy) == 1 ? 'S' : j == -1 ? 'N' : ' ', ! 1174: (j = airport[i].p_dx) == 1 ? 'E' : j == -1 ? 'W' : ' '); ! 1175: msg(cmdx,cmdy-2-i,mbuf); ! 1176: } ! 1177: ! 1178: cdltop.c_next = 0; /* initially no clearance directive lists */ ! 1179: cdltop.c_list = 0; ! 1180: ! 1181: while (game_time < 16*60 || game_time > 99*60+59) /*get time from user */ ! 1182: { char buf[100]; ! 1183: char *p; ! 1184: cursor(cmdx,cmdy); ! 1185: printf("< >"); ! 1186: cursor(cmdx,cmdy); ! 1187: ! 1188: /* move the cursor one space to the right */ ! 1189: p = buf; ! 1190: tgetstr ("nd", &p); ! 1191: fwrite (buf, sizeof (*buf), p-buf, stdout); ! 1192: ! 1193: game_time = getdigit()*10; /* get the time as 2 digits */ ! 1194: game_time += getdigit(); ! 1195: initgame_time = game_time = game_time*60+59; ! 1196: } ! 1197: ! 1198: if (protofile) /* keeping a protocol of the whole game */ ! 1199: { if ((proto = fopen(protofile,"w")) == NULL) ! 1200: err("Cannot open %s for writing.\n",protofile); ! 1201: protostats(proto); ! 1202: } ! 1203: ! 1204: if (bigname) /* megastatistics requested */ ! 1205: { if ((bigstatsfile = fopen(bigname,"w")) == NULL) ! 1206: err("Cannot open %s for writing.\n",bigname); ! 1207: protostats(bigstatsfile); ! 1208: if (protofile) ! 1209: fprintf(bigstatsfile,"Protocol from %s\n",protofile); ! 1210: } ! 1211: ! 1212: last_update = initgame_time+UPDATE; /* force early update */ ! 1213: if (moviefile) last_update += OFFSET; ! 1214: ! 1215: for (i=nearlies=0; i<nplanes; i++) /* construct 26 flight plans */ ! 1216: { plane[i].a_id = 'A'+i; ! 1217: flightplan(&plane[i],0); ! 1218: if (plane[i].a_stime < FPTHRESH) nearlies++; ! 1219: } ! 1220: for (i=nearlies; i < NEARLY; i++) /* ensure 2 or so planes in 1st minute */ ! 1221: flightplan(&plane[die(nplanes)],1); ! 1222: qsort(plane,nplanes,sizeof (struct astruct),pcompare); ! 1223: remain = nplanes; ! 1224: if (bigname) ! 1225: for (i = 0; i < nplanes; i++) ! 1226: strip(&plane[i],-1,TERSE); ! 1227: ! 1228: for (i=0; i<nairport; i++) /* erase the approaches */ ! 1229: delmsg(cmdx,cmdy-2-i); ! 1230: start_time = get_time(); ! 1231: } ! 1232: ! 1233: protostats(proto) /* bunch of statistics for protocols and stuff */ ! 1234: FILE *proto; ! 1235: { char wd[100]; /* result of a "pwd" command */ ! 1236: FILE *pwd; ! 1237: char *s,*t,*u; ! 1238: int c; ! 1239: ! 1240: if ((pwd = popen("pwd","r")) == NULL) ! 1241: err("Cannot open a pipe to pwd.\n"); ! 1242: for (s = wd; (c = getc(pwd)) != EOF;) ! 1243: if (c != '\n') *s++ = c; ! 1244: t = s; /* here's where to put the filename */ ! 1245: *s = 0; ! 1246: fclose(pwd); ! 1247: if (*airfile != '/') /* relative airspace file */ ! 1248: { s = t; ! 1249: *s++ = '/'; ! 1250: for (u = airfile; *s++ = *u++; ); ! 1251: fprintf(proto,"Airspace file: %s\n",wd); ! 1252: } ! 1253: else fprintf(proto,"Airspace file: %s\n",airfile); ! 1254: fprintf(proto,"Airspace: %s\n",airspace); ! 1255: if (flowfile) ! 1256: { if (*flowfile != '/') /* relative flowfile */ ! 1257: { s = t; ! 1258: *s++ = '/'; ! 1259: for (u = flowfile; *s++ = *u++; ); ! 1260: fprintf(proto,"Flow file: %s\n",wd); ! 1261: } ! 1262: else fprintf(proto,"Flow file: %s\n",flowfile); ! 1263: } ! 1264: else fprintf(proto,"Flow file: \n"); ! 1265: fprintf(proto,"Seed: %d\n",seed); ! 1266: fprintf(proto,"Time: %d seconds\n",game_time); ! 1267: } ! 1268: ! 1269: minit() /* initialize the game from a protocol file */ ! 1270: { /* the file is open on stream "movie" */ ! 1271: char buffer[80]; ! 1272: static char airfilebuf[80]; ! 1273: static char airbuf[80]; ! 1274: static char flowbuf[80]; ! 1275: char *s,*t; ! 1276: ! 1277: if (fgets(buffer,80,movie) == 0) /* airspace file line */ ! 1278: err("Unexpected EOF on movie file.\n"); ! 1279: for (s = buffer; *s != ':' && *s; s++); /* scan to colon */ ! 1280: if (*s == 0) err("Bad airspace file line.\n"); ! 1281: s++; s++; /* skip colon and space */ ! 1282: for (t = airfilebuf; (*t++ = *s++) != '\n';); /* copy airspace file */ ! 1283: *--t = 0; ! 1284: airfile = airfilebuf; /* and dummy the pointer */ ! 1285: if (fgets(buffer,80,movie) == 0) /* airspace line */ ! 1286: err("Unexpected EOF on movie file.\n"); ! 1287: for (s = buffer; *s != ':' && *s; s++); /* scan to colon */ ! 1288: if (*s == 0) err("Bad airspace line.\n"); ! 1289: s++; s++; /* skip colon and space */ ! 1290: for (t = airbuf; (*t++ = *s++) != '\n';); /* copy airspace name */ ! 1291: *--t = 0; ! 1292: airspace = airbuf; /* and dummy the pointer */ ! 1293: if (fgets(buffer,80,movie) == 0) /* flowfile line */ ! 1294: err("Unexpected EOF on movie file.\n"); ! 1295: for (s = buffer; *s != ':' && *s; s++); /* scan to colon */ ! 1296: if (*s == 0) err("Bad flowfile line.\n"); ! 1297: s++; s++; /* skip colon and space */ ! 1298: if (*s == '\n') flowfile = 0; ! 1299: else ! 1300: { for (t = flowbuf; (*t++ = *s++) != '\n';); /* copy flowfile */ ! 1301: *--t = 0; ! 1302: flowfile = flowbuf; /* and dummy the pointer */ ! 1303: } ! 1304: if (fgets(buffer,80,movie) == 0) /* seed */ ! 1305: err("Unexpected EOF on movie file.\n"); ! 1306: for (s = buffer; *s != ':' && *s; s++); /* scan to colon */ ! 1307: if (*s == 0) err("Bad seed line.\n"); ! 1308: s++; s++; /* skip colon and space */ ! 1309: seed = atoi(s); ! 1310: if (fgets(buffer,80,movie) == 0) /* time line */ ! 1311: err("Unexpected EOF on movie file.\n"); ! 1312: for (s = buffer; *s != ':' && *s; s++); /* scan to colon */ ! 1313: if (*s == 0) err("Bad time line.\n"); ! 1314: s++; s++; /* skip colon and space */ ! 1315: initgame_time = game_time = atoi(s); ! 1316: getmcmd(); /* get the first command from movie mode */ ! 1317: } ! 1318: ! 1319: getmcmd() /* read a command and store time and command */ ! 1320: { static char buff[80]; ! 1321: char *s; ! 1322: ! 1323: if (fgets(buff,80,movie) == 0) ! 1324: { mcommand = ""; ! 1325: nextmovie = -20; ! 1326: fclose(movie); ! 1327: return; ! 1328: } ! 1329: for (s = buff; *s == ' '; s++); /* skip initial blanks */ ! 1330: nextmovie = atoi(s); ! 1331: while (*s++ != ' '); /* skip to the command */ ! 1332: mcommand = s; /* and save it in a global */ ! 1333: for (; *s; s++) if (*s == '\n') *s = RETURN; ! 1334: } ! 1335: ! 1336: pcompare(p1,p2) /* compare start times for sorting the plane list */ ! 1337: struct astruct *p1,*p2; ! 1338: { if ((p1)->a_stime < (p2)->a_stime) return(-1); ! 1339: else if ((p1)->a_stime == (p2)->a_stime) return(0); ! 1340: else return(1); ! 1341: } ! 1342: ! 1343: ! 1344: printplans() /* flight plans for active and near-active planes */ ! 1345: { register int ctr; /* can only keep cmdy-2 planes on the screen */ ! 1346: register struct astruct *p; ! 1347: register int i; ! 1348: ! 1349: for (i = ctr = 0, p = &plane[0]; i < nplanes && ctr < cmdy - 2; i++,p++) ! 1350: if (p->a_active == APPROACHING || p->a_active == WAITING) ! 1351: strip(p,ctr++,TERSE); ! 1352: delmsg(cmdx,ctr++); /* blank line between approaching and active*/ ! 1353: for (p = &plane[i=0]; i < nplanes && ctr < cmdy - 2; i++,p++) ! 1354: if (p->a_active == ACTIVE) ! 1355: strip(p,ctr++,TERSE); ! 1356: while (ctr < cmdy - 2) delmsg(cmdx,ctr++); /* delete any msg on line*/ ! 1357: } ! 1358: ! 1359: strip(p,y,outstyle) /* display flight strip for this plane on cmd row y */ ! 1360: register struct astruct *p; ! 1361: int y,outstyle; ! 1362: { char mbuf[80]; /* plan message to appear */ ! 1363: int pfuel; ! 1364: struct list *l; ! 1365: char *s; ! 1366: ! 1367: if (p->a_active == WAITING) sprintf(mbuf," "); ! 1368: else if (p->a_active == APPROACHING) ! 1369: sprintf(mbuf,"%d ", ! 1370: (p->a_stime - initgame_time + game_time + 14) / 15); ! 1371: else mbuf[0] = 0; ! 1372: sprintf(&mbuf[strlen(mbuf)],"%c%c %c->%c ", ! 1373: p->a_id, ! 1374: (p->a_type? 'j': 'p'), ! 1375: screen[p->a_x][p->a_y], ! 1376: (p->a_dair? airport[p->a_dest].p_sym : ! 1377: entry[p->a_dest].p_sym)); ! 1378: sprintf(&mbuf[strlen(mbuf)],"%d%c%c ", ! 1379: p->a_z, ! 1380: (p->a_nextz > p->a_z ? '^' : ! 1381: p->a_nextz < p->a_z ? 'v' : ' '), ! 1382: (p->a_nextz != p->a_z ? p->a_nextz + '0' : ' ')); ! 1383: if (p->a_dy>0) sprintf(&mbuf[strlen(mbuf)],"S"); ! 1384: else if (p->a_dy<0) sprintf(&mbuf[strlen(mbuf)],"N"); ! 1385: if (p->a_dx>0) sprintf(&mbuf[strlen(mbuf)],"E"); ! 1386: else if (p->a_dx<0) sprintf(&mbuf[strlen(mbuf)],"W"); ! 1387: if (p->a_dy == 0) sprintf(&mbuf[strlen(mbuf)]," "); ! 1388: switch(p->a_hold) ! 1389: { case 2: sprintf(&mbuf[strlen(mbuf)]," h "); break; ! 1390: case 1: sprintf(&mbuf[strlen(mbuf)]," * "); break; ! 1391: case 0: sprintf(&mbuf[strlen(mbuf)]," %c ",p->a_turn-'A'+'a'); ! 1392: break; ! 1393: } ! 1394: if (p->a_clear) ! 1395: sprintf(&mbuf[strlen(mbuf)],"* %c",p->a_clear); ! 1396: if (p->a_dynew>0) sprintf(&mbuf[strlen(mbuf)],"S"); ! 1397: else if (p->a_dynew<0) sprintf(&mbuf[strlen(mbuf)],"N"); ! 1398: if (p->a_dxnew>0) sprintf(&mbuf[strlen(mbuf)],"E"); ! 1399: else if (p->a_dxnew<0) sprintf(&mbuf[strlen(mbuf)],"W"); ! 1400: if (p->a_dynew == 0) sprintf(&mbuf[strlen(mbuf)]," "); ! 1401: pfuel = (p->a_type == JET? p->a_fuel/4 : p->a_fuel/2); ! 1402: sprintf(&mbuf[strlen(mbuf)]," %c",pfuel>=10?'+':pfuel+'0'); ! 1403: if (p->a_plan) ! 1404: sprintf(&mbuf[strlen(mbuf)]," P"); ! 1405: if (y < 0) /* flight strip to file, not screen */ ! 1406: { if (bigname) ! 1407: { int st; ! 1408: ! 1409: st = p->a_stime; ! 1410: if (p->a_type == JET) ! 1411: { st = st / 15; ! 1412: st = st * 15; ! 1413: } ! 1414: else ! 1415: { st = (st + 45) / 30; ! 1416: st = (st * 30) - 15; ! 1417: } ! 1418: if (st < FIRST_TIME) st = FIRST_TIME; ! 1419: fprintf(bigstatsfile,"%5d: ",st); ! 1420: fprintf(bigstatsfile,"%s\n",mbuf); ! 1421: } ! 1422: } ! 1423: else ! 1424: { msg(cmdx,y,mbuf); /* display the string */ ! 1425: if (outstyle == VERBOSE && p->a_plan) ! 1426: { for (l = p->a_plan; l; l = l->l_next) ! 1427: { sprintf(mbuf,"%s %s",l->l_loc,l->l_cmd); ! 1428: for (s = mbuf; *s; s++) if (*s == RETURN) *s = 0; ! 1429: msg(cmdx,++y,mbuf); ! 1430: } ! 1431: } ! 1432: while (++y < MAXHEIGHT && msglen[y]) msg(cmdx,y,"");/* clr old plans*/ ! 1433: } ! 1434: } ! 1435: ! 1436: msg(x,y,string) /* put up a message at cursor position x,y */ ! 1437: int x,y; ! 1438: char *string; ! 1439: { int i,l; ! 1440: ! 1441: cursor(x,y); ! 1442: printf("%s",string); ! 1443: l = strlen(string); ! 1444: for (i=l; i<msglen[y]; i++) putchar(' '); ! 1445: msglen[y] = l; ! 1446: } ! 1447: ! 1448: delmsg(x,y) /* delete any message starting at cursor posn x,y */ ! 1449: int x,y; ! 1450: { int i; ! 1451: ! 1452: if (msglen[y] <= 0) return; ! 1453: cursor(x,y); ! 1454: for (i=0; i<msglen[y]; i++) putchar(' '); ! 1455: msglen[y] = 0; ! 1456: } ! 1457: ! 1458: ! 1459: flightplan(p,early) ! 1460: struct astruct *p; ! 1461: int early; /* 1 if this plane should be rescheduled for early arrival */ ! 1462: { int i,r,cum; ! 1463: struct astruct *q; ! 1464: struct pstruct *loc; ! 1465: ! 1466: p->a_type = die(2); ! 1467: /* starting time: no planes in last 15 minutes; pretend interval ! 1468: * extends negatively from 0 by FUDGE seconds to make it more likely ! 1469: * that there will be planes available soon. On the other hand, no ! 1470: * plane can come on for the first FIRST_TIME seconds. ! 1471: */ ! 1472: p->a_stime = die(FUDGE + game_time - 15*60) - FUDGE; ! 1473: if (early) p->a_stime = die(FPTHRESH); ! 1474: if (p->a_stime <FIRST_TIME) p->a_stime = FIRST_TIME; ! 1475: if (flowfile) /* flows have been specified */ ! 1476: { r = die(maxflow); ! 1477: for (i = cum = 0; i < npaths; i++) ! 1478: { cum += fpath[i].f_freq; ! 1479: if (cum >= r) break; ! 1480: } ! 1481: if (i >= npaths) i = 0; /* shouldn't ever do this */ ! 1482: p->a_sair = fpath[i].f_fair; ! 1483: p->a_dair = fpath[i].f_tair; ! 1484: p->a_hold = (p->a_dair && !p->a_sair? 1 : 0); ! 1485: p->a_start = fpath[i].f_from; ! 1486: p->a_dest = fpath[i].f_to; ! 1487: ! 1488: if (p->a_sair) loc = &airport[p->a_start]; ! 1489: else loc = &entry[p->a_start]; ! 1490: } ! 1491: else ! 1492: { p->a_sair = (die(inaptot+inawtot) <= inaptot? 1 : 0); ! 1493: p->a_dair = (die(outaptot+outawtot) <= outaptot? 1 : 0); ! 1494: ! 1495: p->a_hold = (p->a_dair? 1 : 0); ! 1496: if (p->a_sair) ! 1497: { p->a_start =pick(die(inaptot),&airport[0],nairport,1); ! 1498: loc = &airport[p->a_start]; ! 1499: p->a_hold = 0; ! 1500: if (p->a_dair) p->a_dest = pick(die(inaptot), ! 1501: &airport[0],nairport,0); ! 1502: else p->a_dest = pick(die(inawtot), ! 1503: &entry[0],nentry,0); ! 1504: } ! 1505: else ! 1506: { p->a_start = pick(die(inawtot),&entry[0],nentry,0); ! 1507: loc = &entry[p->a_start]; ! 1508: if (p->a_dair) p->a_dest = pick(die(inaptot), ! 1509: &airport[0],nairport,0); ! 1510: else do p->a_dest = pick(die(inawtot), ! 1511: &entry[0],nentry,0); ! 1512: while (p->a_dest == p->a_start); ! 1513: } ! 1514: } ! 1515: p->a_active = INACTIVE; ! 1516: p->a_z = (p->a_sair? 0 : 6); ! 1517: if (!p->a_sair) /* separate planes by 1000' altitude */ ! 1518: for (q = &plane[0]; q != &plane[PMAX]; q++) ! 1519: { if (q == p && !early) break; ! 1520: if (q == p) continue; ! 1521: if (p->a_start == q->a_start) ! 1522: if (abs(q->a_stime - p->a_stime) < SAFETY) ! 1523: if (q->a_z >= p->a_z) ! 1524: p->a_z = q->a_z + 1; ! 1525: } ! 1526: if (flowfile && p->a_z < NALT) ! 1527: { p->a_opt = fpath[i].f_dist[p->a_z]; ! 1528: p->a_cmds = fpath[i].f_cmds; ! 1529: } ! 1530: p->a_prev = p->a_pprev = p->a_aprev = 0; ! 1531: p->a_x = loc->p_x; ! 1532: p->a_y = loc->p_y; ! 1533: p->a_dx = loc->p_dx; ! 1534: p->a_dy = loc->p_dy; ! 1535: p->a_dxnew = p->a_dynew = 0; ! 1536: p->a_lastz = p->a_nextz = p->a_z; ! 1537: p->a_turn = 0; ! 1538: p->a_fuel = (p->a_type == JET ? JETFUEL : PROPFUEL); ! 1539: p->a_clear = 0; /* not cleared for any approach */ ! 1540: p->a_plan = 0; /* no monitor points on the flight plan */ ! 1541: p->a_load = p->a_ticks = p->a_planned = p->a_dist = 0; ! 1542: } ! 1543: ! 1544: pick(draw,point,num,in) ! 1545: int draw; ! 1546: struct pstruct *point; ! 1547: int num,in; ! 1548: { register int i,cum; ! 1549: ! 1550: for (i = cum = 0; i<num; i++,point++) ! 1551: { if (in) cum += point->p_inprop; ! 1552: else cum += point->p_outprop; ! 1553: if (cum >= draw) return(i); ! 1554: } ! 1555: return(0); /* should never get here */ ! 1556: } ! 1557: ! 1558: #if !NRAND ! 1559: die(n) /* throw an n-sided die (sides 0 thru n-1) */ ! 1560: int n; ! 1561: { int r; ! 1562: ! 1563: #ifdef vax ! 1564: r = rand() >> 10; /* rightmost bits are not very random */ ! 1565: #else ! 1566: r = random(); /* rightmost bits are not very random */ ! 1567: #endif ! 1568: return(r % n); /* enough resolution to make this o.k. */ ! 1569: } ! 1570: #endif ! 1571: ! 1572: getdigit() /* keep reading chars from terminal until get a digit */ ! 1573: { int c; /* returns digit - '0' */ ! 1574: ! 1575: do { ! 1576: if (rubout) return 9; ! 1577: c = getchar() & 0177; ! 1578: } while (c < '0' || c > '9'); ! 1579: putchar(c); ! 1580: return(c-'0'); ! 1581: } ! 1582: ! 1583: time_t ! 1584: get_time() /* returns time in seconds since 1970 */ ! 1585: { ! 1586: time_t t; ! 1587: ! 1588: time(&t); ! 1589: return(t); /* seconds since 1970 */ ! 1590: } ! 1591: ! 1592: ! 1593: display() /* put up initial screen */ ! 1594: { int i,j; ! 1595: ! 1596: for (j=0; j<height; j++) ! 1597: { cursor(0,j); /* general enough to extend to graphics */ ! 1598: for (i=0; i<width; i++) ! 1599: { putchar(screen[i][j]); ! 1600: putchar(' '); ! 1601: } ! 1602: } ! 1603: } ! 1604: ! 1605: ! 1606: cursor(x,y) /* move to location x,y on WIDTHxHEIGHT screen */ ! 1607: char x,y; /* this is in terms of screen, i.e. with x's 2 chars wide */ ! 1608: { ! 1609: poscur(2*x,y); ! 1610: } ! 1611: ! 1612: ! 1613: poscur(x,y) /* position cursor at this absolute location on screen */ ! 1614: char x,y; ! 1615: { ! 1616: char *tgoto(); ! 1617: printf ("%s", tgoto (cmbuf, x, y)); ! 1618: } ! 1619: ! 1620: ! 1621: clearscreen() ! 1622: { ! 1623: printf ("%s", clbuf); ! 1624: } ! 1625: ! 1626: char * ! 1627: plural(n) /* returns "s" unless n=1 */ ! 1628: int n; ! 1629: { static char s[2] = "s"; ! 1630: ! 1631: if (n != 1) return(s); ! 1632: else return(""); ! 1633: } ! 1634: ! 1635: done(flag) /* clean up */ ! 1636: int flag; ! 1637: { FILE *statfile; ! 1638: struct passwd *pw; ! 1639: time_t now; ! 1640: char *c,*ct; ! 1641: extern char *ctime(); ! 1642: ! 1643: if (!moviefile) ! 1644: { tty_setting.sg_flags = tty_flags;/* put terminal back the way it was*/ ! 1645: ioctl(0, TIOCSETP, &tty_setting); ! 1646: } ! 1647: if (flag) cursor(LEFT,height+1); ! 1648: ! 1649: if ((statfile = fopen(STATSFILE,"a")) != NULL) ! 1650: { pw = getpwuid(getuid()); ! 1651: now = get_time(); ! 1652: ct = ctime(&now); ! 1653: for (c= &ct[4]; c <= &ct[16]; c++) fputc(*c,statfile); ! 1654: if (!flag) fprintf(statfile,"%8s: aborted\n",pw->pw_name); ! 1655: else ! 1656: { fprintf(statfile,"%8s: %2d %3d %2d %2d %3d %5d %3d %2d", ! 1657: pw->pw_name,crash,system,fuel,bound,goaround, ! 1658: fuelused,cmds,remain); ! 1659: fprintf(statfile,". %d %2d %s\n", ! 1660: initseed,initgame_time/60,airspace); ! 1661: fclose(statfile); ! 1662: } ! 1663: } ! 1664: if (!flag) return; ! 1665: ttystats(stdout); ! 1666: if (bigname) ! 1667: { int i; ! 1668: float load,ticks,plans,route,d,stripped; ! 1669: ! 1670: for (i = 0; i < nplanes; i++) ! 1671: { load = plane[i].a_load; ! 1672: ticks = plane[i].a_ticks; ! 1673: plans = plane[i].a_planned; ! 1674: route = plane[i].a_opt; ! 1675: stripped = plane[i].a_prev; ! 1676: d = plane[i].a_dist; ! 1677: fprintf(bigstatsfile, ! 1678: "%c: %2d tks, %2d/%2d=%1.2f, %d, %.2f a/tk, %.2f p/tk, %.2f a/ptk, %.2f p/ptk, %c, %s\n", ! 1679: plane[i].a_id,plane[i].a_ticks, ! 1680: plane[i].a_dist, ! 1681: plane[i].a_opt, ! 1682: d/route, ! 1683: plane[i].a_cmds, ! 1684: load/ticks, ! 1685: plans/ticks, ! 1686: plane[i].a_aprev/stripped, ! 1687: plane[i].a_pprev/stripped, ! 1688: plane[i].a_sair? 'W' : 'A', ! 1689: plane[i].a_pplanned? "+P" : "-P" ! 1690: ); ! 1691: } ! 1692: } ! 1693: if (bigname) ttystats(bigstatsfile); ! 1694: if (protofile) fclose(proto); ! 1695: if (bigname) fclose(bigstatsfile); ! 1696: } ! 1697: ! 1698: ttystats(file) ! 1699: FILE *file; ! 1700: { char *eol; ! 1701: ! 1702: if (file == bigstatsfile) eol = "\n"; ! 1703: else { ! 1704: clearscreen(); ! 1705: eol = "\n\r"; ! 1706: } ! 1707: if (crash) fprintf(file,"%d plane%s out of fuel, crashed%s", ! 1708: crash,plural(crash),eol); ! 1709: if (system) fprintf(file,"%d system error%s%s", ! 1710: system,plural(system),eol); ! 1711: if (fuel) fprintf(file,"%d tow truck%s called%s", ! 1712: fuel,plural(fuel),eol); ! 1713: if (bound) fprintf(file,"%d boundary error%s%s", ! 1714: bound,plural(bound),eol); ! 1715: if (goaround) fprintf(file,"%d go-around%s%s", ! 1716: goaround,plural(goaround),eol); ! 1717: if (crash+system+fuel+bound+remain == 0) ! 1718: { fprintf(file,"GREAT JOB!! Have you considered a career in ATC?\n"); ! 1719: fprintf(file,"Now try %d minutes...\n",initgame_time/60-5); ! 1720: } ! 1721: fprintf(file,"Fuel used: %d\n",fuelused); ! 1722: fprintf(file,"Commands issued (including deferred): %d\n",icmds); ! 1723: fprintf(file,"Commands executed: %d\n",cmds); ! 1724: fprintf(file,"Airspace: %s; seed: %d; time=%d; %d remaining.%s", ! 1725: airspace,initseed,initgame_time/60,remain,eol); ! 1726: if (file == bigstatsfile) fprintf(file,"\f"); ! 1727: } ! 1728: ! 1729: err(msg,arg1,arg2) ! 1730: char *msg; ! 1731: { fprintf(stderr,msg,arg1,arg2); ! 1732: done(0); ! 1733: exit(1); ! 1734: } ! 1735:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.