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