1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)move.c 8.1 (Berkeley) 05/31/93"; 10 #endif /* not lint */ 11 12 #include <termios.h> 13 14 #include "mille.h" 15 #ifndef unctrl 16 #include "unctrl.h" 17 #endif 18 19 # ifdef attron 20 # include <term.h> 21 # define _tty cur_term->Nttyb 22 # endif attron 23 24 /* 25 * @(#)move.c 1.2 (Berkeley) 3/28/83 26 */ 27 28 #undef CTRL 29 #define CTRL(c) (c - 'A' + 1) 30 31 char *Movenames[] = { 32 "M_DISCARD", "M_DRAW", "M_PLAY", "M_ORDER" 33 }; 34 35 domove() 36 { 37 reg PLAY *pp; 38 reg int i, j; 39 reg bool goodplay; 40 41 pp = &Player[Play]; 42 if (Play == PLAYER) 43 getmove(); 44 else 45 calcmove(); 46 Next = FALSE; 47 goodplay = TRUE; 48 switch (Movetype) { 49 case M_DISCARD: 50 if (haspicked(pp)) { 51 if (pp->hand[Card_no] == C_INIT) 52 if (Card_no == 6) 53 Finished = TRUE; 54 else 55 error("no card there"); 56 else { 57 if (issafety(pp->hand[Card_no])) { 58 error("discard a safety?"); 59 goodplay = FALSE; 60 break; 61 } 62 Discard = pp->hand[Card_no]; 63 pp->hand[Card_no] = C_INIT; 64 Next = TRUE; 65 if (Play == PLAYER) 66 account(Discard); 67 } 68 } 69 else 70 error("must pick first"); 71 break; 72 case M_PLAY: 73 goodplay = playcard(pp); 74 break; 75 case M_DRAW: 76 Card_no = 0; 77 if (Topcard <= Deck) 78 error("no more cards"); 79 else if (haspicked(pp)) 80 error("already picked"); 81 else { 82 pp->hand[0] = *--Topcard; 83 #ifdef DEBUG 84 if (Debug) 85 fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]); 86 #endif 87 acc: 88 if (Play == COMP) { 89 account(*Topcard); 90 if (issafety(*Topcard)) 91 pp->safety[*Topcard-S_CONV] = S_IN_HAND; 92 } 93 if (pp->hand[1] == C_INIT && Topcard > Deck) { 94 Card_no = 1; 95 pp->hand[1] = *--Topcard; 96 #ifdef DEBUG 97 if (Debug) 98 fprintf(outf, "DOMOVE: Draw %s\n", C_name[*Topcard]); 99 #endif 100 goto acc; 101 } 102 pp->new_battle = FALSE; 103 pp->new_speed = FALSE; 104 } 105 break; 106 107 case M_ORDER: 108 break; 109 } 110 /* 111 * move blank card to top by one of two methods. If the 112 * computer's hand was sorted, the randomness for picking 113 * between equally valued cards would be lost 114 */ 115 if (Order && Movetype != M_DRAW && goodplay && pp == &Player[PLAYER]) 116 sort(pp->hand); 117 else 118 for (i = 1; i < HAND_SZ; i++) 119 if (pp->hand[i] == C_INIT) { 120 for (j = 0; pp->hand[j] == C_INIT; j++) 121 if (j >= HAND_SZ) { 122 j = 0; 123 break; 124 } 125 pp->hand[i] = pp->hand[j]; 126 pp->hand[j] = C_INIT; 127 } 128 if (Topcard <= Deck) 129 check_go(); 130 if (Next) 131 nextplay(); 132 } 133 134 /* 135 * Check and see if either side can go. If they cannot, 136 * the game is over 137 */ 138 check_go() { 139 140 reg CARD card; 141 reg PLAY *pp, *op; 142 reg int i; 143 144 for (pp = Player; pp < &Player[2]; pp++) { 145 op = (pp == &Player[COMP] ? &Player[PLAYER] : &Player[COMP]); 146 for (i = 0; i < HAND_SZ; i++) { 147 card = pp->hand[i]; 148 if (issafety(card) || canplay(pp, op, card)) { 149 #ifdef DEBUG 150 if (Debug) { 151 fprintf(outf, "CHECK_GO: can play %s (%d), ", C_name[card], card); 152 fprintf(outf, "issafety(card) = %d, ", issafety(card)); 153 fprintf(outf, "canplay(pp, op, card) = %d\n", canplay(pp, op, card)); 154 } 155 #endif 156 return; 157 } 158 #ifdef DEBUG 159 else if (Debug) 160 fprintf(outf, "CHECK_GO: cannot play %s\n", 161 C_name[card]); 162 #endif 163 } 164 } 165 Finished = TRUE; 166 } 167 168 playcard(pp) 169 reg PLAY *pp; 170 { 171 reg int v; 172 reg CARD card; 173 174 /* 175 * check and see if player has picked 176 */ 177 switch (pp->hand[Card_no]) { 178 default: 179 if (!haspicked(pp)) 180 mustpick: 181 return error("must pick first"); 182 case C_GAS_SAFE: case C_SPARE_SAFE: 183 case C_DRIVE_SAFE: case C_RIGHT_WAY: 184 break; 185 } 186 187 card = pp->hand[Card_no]; 188 #ifdef DEBUG 189 if (Debug) 190 fprintf(outf, "PLAYCARD: Card = %s\n", C_name[card]); 191 #endif 192 Next = FALSE; 193 switch (card) { 194 case C_200: 195 if (pp->nummiles[C_200] == 2) 196 return error("only two 200's per hand"); 197 case C_100: case C_75: 198 if (pp->speed == C_LIMIT) 199 return error("limit of 50"); 200 case C_50: 201 if (pp->mileage + Value[card] > End) 202 return error("puts you over %d", End); 203 case C_25: 204 if (!pp->can_go) 205 return error("cannot move now"); 206 pp->nummiles[card]++; 207 v = Value[card]; 208 pp->total += v; 209 pp->hand_tot += v; 210 if ((pp->mileage += v) == End) 211 check_ext(FALSE); 212 break; 213 214 case C_GAS: case C_SPARE: case C_REPAIRS: 215 if (pp->battle != opposite(card)) 216 return error("can't play \"%s\"", C_name[card]); 217 pp->battle = card; 218 if (pp->safety[S_RIGHT_WAY] == S_PLAYED) 219 pp->can_go = TRUE; 220 break; 221 222 case C_GO: 223 if (pp->battle != C_INIT && pp->battle != C_STOP 224 && !isrepair(pp->battle)) 225 return error("cannot play \"Go\" on a \"%s\"", 226 C_name[pp->battle]); 227 pp->battle = C_GO; 228 pp->can_go = TRUE; 229 break; 230 231 case C_END_LIMIT: 232 if (pp->speed != C_LIMIT) 233 return error("not limited"); 234 pp->speed = C_END_LIMIT; 235 break; 236 237 case C_EMPTY: case C_FLAT: case C_CRASH: 238 case C_STOP: 239 pp = &Player[other(Play)]; 240 if (!pp->can_go) 241 return error("opponent cannot go"); 242 else if (pp->safety[safety(card) - S_CONV] == S_PLAYED) 243 protected: 244 return error("opponent is protected"); 245 pp->battle = card; 246 pp->new_battle = TRUE; 247 pp->can_go = FALSE; 248 pp = &Player[Play]; 249 break; 250 251 case C_LIMIT: 252 pp = &Player[other(Play)]; 253 if (pp->speed == C_LIMIT) 254 return error("opponent has limit"); 255 if (pp->safety[S_RIGHT_WAY] == S_PLAYED) 256 goto protected; 257 pp->speed = C_LIMIT; 258 pp->new_speed = TRUE; 259 pp = &Player[Play]; 260 break; 261 262 case C_GAS_SAFE: case C_SPARE_SAFE: 263 case C_DRIVE_SAFE: case C_RIGHT_WAY: 264 if (pp->battle == opposite(card) 265 || (card == C_RIGHT_WAY && pp->speed == C_LIMIT)) { 266 if (!(card == C_RIGHT_WAY && !isrepair(pp->battle))) { 267 pp->battle = C_GO; 268 pp->can_go = TRUE; 269 } 270 if (card == C_RIGHT_WAY && pp->speed == C_LIMIT) 271 pp->speed = C_INIT; 272 if (pp->new_battle 273 || (pp->new_speed && card == C_RIGHT_WAY)) { 274 pp->coups[card - S_CONV] = TRUE; 275 pp->total += SC_COUP; 276 pp->hand_tot += SC_COUP; 277 pp->coupscore += SC_COUP; 278 } 279 } 280 /* 281 * if not coup, must pick first 282 */ 283 else if (pp->hand[0] == C_INIT && Topcard > Deck) 284 goto mustpick; 285 pp->safety[card - S_CONV] = S_PLAYED; 286 pp->total += SC_SAFETY; 287 pp->hand_tot += SC_SAFETY; 288 if ((pp->safescore += SC_SAFETY) == NUM_SAFE * SC_SAFETY) { 289 pp->total += SC_ALL_SAFE; 290 pp->hand_tot += SC_ALL_SAFE; 291 } 292 if (card == C_RIGHT_WAY) { 293 if (pp->speed == C_LIMIT) 294 pp->speed = C_INIT; 295 if (pp->battle == C_STOP || pp->battle == C_INIT) { 296 pp->can_go = TRUE; 297 pp->battle = C_INIT; 298 } 299 if (!pp->can_go && isrepair(pp->battle)) 300 pp->can_go = TRUE; 301 } 302 Next = -1; 303 break; 304 305 case C_INIT: 306 error("no card there"); 307 Next = -1; 308 break; 309 } 310 if (pp == &Player[PLAYER]) 311 account(card); 312 pp->hand[Card_no] = C_INIT; 313 Next = (Next == -1 ? FALSE : TRUE); 314 return TRUE; 315 } 316 317 getmove() 318 { 319 reg char c, *sp; 320 #ifdef EXTRAP 321 static bool last_ex = FALSE; /* set if last command was E */ 322 323 if (last_ex) { 324 undoex(); 325 prboard(); 326 last_ex = FALSE; 327 } 328 #endif 329 for (;;) { 330 prompt(MOVEPROMPT); 331 leaveok(Board, FALSE); 332 refresh(); 333 while ((c = readch()) == killchar() || c == erasechar()) 334 continue; 335 if (islower(c)) 336 c = toupper(c); 337 if (isprint(c) && !isspace(c)) { 338 addch(c); 339 refresh(); 340 } 341 switch (c) { 342 case 'P': /* Pick */ 343 Movetype = M_DRAW; 344 goto ret; 345 case 'U': /* Use Card */ 346 case 'D': /* Discard Card */ 347 if ((Card_no = getcard()) < 0) 348 break; 349 Movetype = (c == 'U' ? M_PLAY : M_DISCARD); 350 goto ret; 351 case 'O': /* Order */ 352 Order = !Order; 353 if (Window == W_SMALL) { 354 if (!Order) 355 mvwaddstr(Score, 12, 21, 356 "o: order hand"); 357 else 358 mvwaddstr(Score, 12, 21, 359 "o: stop ordering"); 360 wclrtoeol(Score); 361 } 362 Movetype = M_ORDER; 363 goto ret; 364 case 'Q': /* Quit */ 365 rub(); /* Same as a rubout */ 366 break; 367 case 'W': /* Window toggle */ 368 Window = nextwin(Window); 369 newscore(); 370 prscore(TRUE); 371 wrefresh(Score); 372 break; 373 case 'R': /* Redraw screen */ 374 case CTRL('L'): 375 wrefresh(curscr); 376 break; 377 case 'S': /* Save game */ 378 On_exit = FALSE; 379 save(); 380 break; 381 case 'E': /* Extrapolate */ 382 #ifdef EXTRAP 383 if (last_ex) 384 break; 385 Finished = TRUE; 386 if (Window != W_FULL) 387 newscore(); 388 prscore(FALSE); 389 wrefresh(Score); 390 last_ex = TRUE; 391 Finished = FALSE; 392 #else 393 error("%c: command not implemented", c); 394 #endif 395 break; 396 case '\r': /* Ignore RETURNs and */ 397 case '\n': /* Line Feeds */ 398 case ' ': /* Spaces */ 399 case '\0': /* and nulls */ 400 break; 401 #ifdef DEBUG 402 case 'Z': /* Debug code */ 403 if (!Debug && outf == NULL) { 404 char buf[MAXPATHLEN]; 405 406 prompt(FILEPROMPT); 407 leaveok(Board, FALSE); 408 refresh(); 409 sp = buf; 410 while ((*sp = readch()) != '\n') { 411 if (*sp == killchar()) 412 goto over; 413 else if (*sp == erasechar()) { 414 if (--sp < buf) 415 sp = buf; 416 else { 417 addch('\b'); 418 if (*sp < ' ') 419 addch('\b'); 420 clrtoeol(); 421 } 422 } 423 else 424 addstr(unctrl(*sp++)); 425 refresh(); 426 } 427 *sp = '\0'; 428 leaveok(Board, TRUE); 429 if ((outf = fopen(buf, "w")) == NULL) 430 perror(buf); 431 setbuf(outf, (char *)NULL); 432 } 433 Debug = !Debug; 434 break; 435 #endif 436 default: 437 error("unknown command: %s", unctrl(c)); 438 break; 439 } 440 } 441 ret: 442 leaveok(Board, TRUE); 443 } 444 /* 445 * return whether or not the player has picked 446 */ 447 haspicked(pp) 448 reg PLAY *pp; { 449 450 reg int card; 451 452 if (Topcard <= Deck) 453 return TRUE; 454 switch (pp->hand[Card_no]) { 455 case C_GAS_SAFE: case C_SPARE_SAFE: 456 case C_DRIVE_SAFE: case C_RIGHT_WAY: 457 card = 1; 458 break; 459 default: 460 card = 0; 461 break; 462 } 463 return (pp->hand[card] != C_INIT); 464 } 465 466 account(card) 467 reg CARD card; { 468 469 reg CARD oppos; 470 471 if (card == C_INIT) 472 return; 473 ++Numseen[card]; 474 if (Play == COMP) 475 switch (card) { 476 case C_GAS_SAFE: 477 case C_SPARE_SAFE: 478 case C_DRIVE_SAFE: 479 oppos = opposite(card); 480 Numgos += Numcards[oppos] - Numseen[oppos]; 481 break; 482 case C_CRASH: 483 case C_FLAT: 484 case C_EMPTY: 485 case C_STOP: 486 Numgos++; 487 break; 488 } 489 } 490 491 prompt(promptno) 492 int promptno; 493 { 494 static char *names[] = { 495 ">>:Move:", 496 "Really?", 497 "Another hand?", 498 "Another game?", 499 "Save game?", 500 "Same file?", 501 "file:", 502 "Extension?", 503 "Overwrite file?", 504 }; 505 static int last_prompt = -1; 506 507 if (promptno == last_prompt) 508 move(MOVE_Y, MOVE_X + strlen(names[promptno]) + 1); 509 else { 510 move(MOVE_Y, MOVE_X); 511 if (promptno == MOVEPROMPT) 512 standout(); 513 addstr(names[promptno]); 514 if (promptno == MOVEPROMPT) 515 standend(); 516 addch(' '); 517 last_prompt = promptno; 518 } 519 clrtoeol(); 520 } 521 522 sort(hand) 523 reg CARD *hand; 524 { 525 reg CARD *cp, *tp; 526 reg CARD temp; 527 528 cp = hand; 529 hand += HAND_SZ; 530 for ( ; cp < &hand[-1]; cp++) 531 for (tp = cp + 1; tp < hand; tp++) 532 if (*cp > *tp) { 533 temp = *cp; 534 *cp = *tp; 535 *tp = temp; 536 } 537 } 538 539