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