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