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