1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)canfield.c 5.10 (Berkeley) 06/01/90"; 16 #endif /* not lint */ 17 18 /* 19 * The canfield program 20 * 21 * Authors: 22 * Originally written: Steve Levine 23 * Converted to use curses and debugged: Steve Feldman 24 * Card counting: Kirk McKusick and Mikey Olson 25 * User interface cleanups: Eric Allman and Kirk McKusick 26 * Betting by Kirk McKusick 27 */ 28 29 #include <sys/types.h> 30 #include <sys/signal.h> 31 #include <curses.h> 32 #include <ctype.h> 33 #include "pathnames.h" 34 35 #define decksize 52 36 #define originrow 0 37 #define origincol 0 38 #define basecol 1 39 #define boxcol 42 40 #define tboxrow 2 41 #define bboxrow 17 42 #define movecol 43 43 #define moverow 16 44 #define msgcol 43 45 #define msgrow 15 46 #define titlecol 30 47 #define titlerow 0 48 #define sidecol 1 49 #define ottlrow 6 50 #define foundcol 11 51 #define foundrow 3 52 #define stockcol 2 53 #define stockrow 8 54 #define fttlcol 10 55 #define fttlrow 1 56 #define taloncol 2 57 #define talonrow 13 58 #define tabrow 8 59 #define ctoprow 21 60 #define cbotrow 23 61 #define cinitcol 14 62 #define cheightcol 1 63 #define cwidthcol 4 64 #define handstatrow 21 65 #define handstatcol 7 66 #define talonstatrow 22 67 #define talonstatcol 7 68 #define stockstatrow 23 69 #define stockstatcol 7 70 #define Ace 1 71 #define Jack 11 72 #define Queen 12 73 #define King 13 74 #define atabcol 11 75 #define btabcol 18 76 #define ctabcol 25 77 #define dtabcol 32 78 79 #define spades 's' 80 #define clubs 'c' 81 #define hearts 'h' 82 #define diamonds 'd' 83 #define black 'b' 84 #define red 'r' 85 86 #define stk 1 87 #define tal 2 88 #define tab 3 89 #define INCRHAND(row, col) {\ 90 row -= cheightcol;\ 91 if (row < ctoprow) {\ 92 row = cbotrow;\ 93 col += cwidthcol;\ 94 }\ 95 } 96 #define DECRHAND(row, col) {\ 97 row += cheightcol;\ 98 if (row > cbotrow) {\ 99 row = ctoprow;\ 100 col -= cwidthcol;\ 101 }\ 102 } 103 104 105 struct cardtype { 106 char suit; 107 char color; 108 bool visible; 109 bool paid; 110 int rank; 111 struct cardtype *next; 112 }; 113 114 #define NIL ((struct cardtype *) -1) 115 116 struct cardtype *deck[decksize]; 117 struct cardtype cards[decksize]; 118 struct cardtype *bottom[4], *found[4], *tableau[4]; 119 struct cardtype *talon, *hand, *stock, *basecard; 120 int length[4]; 121 int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru; 122 char suitmap[4] = {spades, clubs, hearts, diamonds}; 123 char colormap[4] = {black, black, red, red}; 124 char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol}; 125 char srcpile, destpile; 126 int mtforigin, tempbase; 127 int coldcol, cnewcol, coldrow, cnewrow; 128 bool errmsg, done; 129 bool mtfdone, Cflag = FALSE; 130 #define INSTRUCTIONBOX 1 131 #define BETTINGBOX 2 132 #define NOBOX 3 133 int status = INSTRUCTIONBOX; 134 int uid; 135 136 /* 137 * Basic betting costs 138 */ 139 #define costofhand 13 140 #define costofinspection 13 141 #define costofgame 26 142 #define costofrunthroughhand 5 143 #define costofinformation 1 144 #define secondsperdollar 60 145 #define maxtimecharge 3 146 #define valuepercardup 5 147 /* 148 * Variables associated with betting 149 */ 150 struct betinfo { 151 long hand; /* cost of dealing hand */ 152 long inspection; /* cost of inspecting hand */ 153 long game; /* cost of buying game */ 154 long runs; /* cost of running through hands */ 155 long information; /* cost of information */ 156 long thinktime; /* cost of thinking time */ 157 long wins; /* total winnings */ 158 long worth; /* net worth after costs */ 159 }; 160 struct betinfo this, game, total; 161 bool startedgame = FALSE, infullgame = FALSE; 162 time_t acctstart; 163 int dbfd = -1; 164 165 /* 166 * The following procedures print the board onto the screen using the 167 * addressible cursor. The end of these procedures will also be 168 * separated from the rest of the program. 169 * 170 * procedure to set the move command box 171 */ 172 movebox() 173 { 174 switch (status) { 175 case BETTINGBOX: 176 printtopbettingbox(); 177 break; 178 case NOBOX: 179 clearabovemovebox(); 180 break; 181 case INSTRUCTIONBOX: 182 printtopinstructions(); 183 break; 184 } 185 move(moverow, boxcol); 186 printw("| |"); 187 move(msgrow, boxcol); 188 printw("| |"); 189 switch (status) { 190 case BETTINGBOX: 191 printbottombettingbox(); 192 break; 193 case NOBOX: 194 clearbelowmovebox(); 195 break; 196 case INSTRUCTIONBOX: 197 printbottominstructions(); 198 break; 199 } 200 refresh(); 201 } 202 203 /* 204 * print directions above move box 205 */ 206 printtopinstructions() 207 { 208 move(tboxrow, boxcol); 209 printw("*----------------------------------*"); 210 move(tboxrow + 1, boxcol); 211 printw("| MOVES |"); 212 move(tboxrow + 2, boxcol); 213 printw("|s# = stock to tableau |"); 214 move(tboxrow + 3, boxcol); 215 printw("|sf = stock to foundation |"); 216 move(tboxrow + 4, boxcol); 217 printw("|t# = talon to tableau |"); 218 move(tboxrow + 5, boxcol); 219 printw("|tf = talon to foundation |"); 220 move(tboxrow + 6, boxcol); 221 printw("|## = tableau to tableau |"); 222 move(tboxrow + 7, boxcol); 223 printw("|#f = tableau to foundation |"); 224 move(tboxrow + 8, boxcol); 225 printw("|ht = hand to talon |"); 226 move(tboxrow + 9, boxcol); 227 printw("|c = toggle card counting |"); 228 move(tboxrow + 10, boxcol); 229 printw("|b = present betting information |"); 230 move(tboxrow + 11, boxcol); 231 printw("|q = quit to end the game |"); 232 move(tboxrow + 12, boxcol); 233 printw("|==================================|"); 234 } 235 236 /* 237 * Print the betting box. 238 */ 239 printtopbettingbox() 240 { 241 242 move(tboxrow, boxcol); 243 printw("*----------------------------------*"); 244 move(tboxrow + 1, boxcol); 245 printw("|Costs Hand Game Total |"); 246 move(tboxrow + 2, boxcol); 247 printw("| Hands |"); 248 move(tboxrow + 3, boxcol); 249 printw("| Inspections |"); 250 move(tboxrow + 4, boxcol); 251 printw("| Games |"); 252 move(tboxrow + 5, boxcol); 253 printw("| Runs |"); 254 move(tboxrow + 6, boxcol); 255 printw("| Information |"); 256 move(tboxrow + 7, boxcol); 257 printw("| Think time |"); 258 move(tboxrow + 8, boxcol); 259 printw("|Total Costs |"); 260 move(tboxrow + 9, boxcol); 261 printw("|Winnings |"); 262 move(tboxrow + 10, boxcol); 263 printw("|Net Worth |"); 264 move(tboxrow + 11, boxcol); 265 printw("|Return |"); 266 move(tboxrow + 12, boxcol); 267 printw("|==================================|"); 268 } 269 270 /* 271 * clear info above move box 272 */ 273 clearabovemovebox() 274 { 275 int i; 276 277 for (i = 0; i <= 11; i++) { 278 move(tboxrow + i, boxcol); 279 printw(" "); 280 } 281 move(tboxrow + 12, boxcol); 282 printw("*----------------------------------*"); 283 } 284 285 /* 286 * print instructions below move box 287 */ 288 printbottominstructions() 289 { 290 move(bboxrow, boxcol); 291 printw("|Replace # with the number of the |"); 292 move(bboxrow + 1, boxcol); 293 printw("|tableau you want. |"); 294 move(bboxrow + 2, boxcol); 295 printw("*----------------------------------*"); 296 } 297 298 /* 299 * print betting information below move box 300 */ 301 printbottombettingbox() 302 { 303 move(bboxrow, boxcol); 304 printw("|x = toggle information box |"); 305 move(bboxrow + 1, boxcol); 306 printw("|i = list playing instructions |"); 307 move(bboxrow + 2, boxcol); 308 printw("*----------------------------------*"); 309 } 310 311 /* 312 * clear info below move box 313 */ 314 clearbelowmovebox() 315 { 316 int i; 317 318 move(bboxrow, boxcol); 319 printw("*----------------------------------*"); 320 for (i = 1; i <= 2; i++) { 321 move(bboxrow + i, boxcol); 322 printw(" "); 323 } 324 } 325 326 /* 327 * procedure to put the board on the screen using addressable cursor 328 */ 329 makeboard() 330 { 331 clear(); 332 refresh(); 333 move(titlerow, titlecol); 334 printw("=-> CANFIELD <-="); 335 move(fttlrow, fttlcol); 336 printw("foundation"); 337 move(foundrow - 1, fttlcol); 338 printw("=---= =---= =---= =---="); 339 move(foundrow, fttlcol); 340 printw("| | | | | | | |"); 341 move(foundrow + 1, fttlcol); 342 printw("=---= =---= =---= =---="); 343 move(ottlrow, sidecol); 344 printw("stock tableau"); 345 move(stockrow - 1, sidecol); 346 printw("=---="); 347 move(stockrow, sidecol); 348 printw("| |"); 349 move(stockrow + 1, sidecol); 350 printw("=---="); 351 move(talonrow - 2, sidecol); 352 printw("talon"); 353 move(talonrow - 1, sidecol); 354 printw("=---="); 355 move(talonrow, sidecol); 356 printw("| |"); 357 move(talonrow + 1, sidecol); 358 printw("=---="); 359 move(tabrow - 1, atabcol); 360 printw("-1- -2- -3- -4-"); 361 movebox(); 362 } 363 364 /* 365 * clean up the board for another game 366 */ 367 cleanupboard() 368 { 369 int cnt, row, col; 370 struct cardtype *ptr; 371 372 if (Cflag) { 373 clearstat(); 374 for(ptr = stock, row = stockrow; 375 ptr != NIL; 376 ptr = ptr->next, row++) { 377 move(row, sidecol); 378 printw(" "); 379 } 380 move(row, sidecol); 381 printw(" "); 382 move(stockrow + 1, sidecol); 383 printw("=---="); 384 move(talonrow - 2, sidecol); 385 printw("talon"); 386 move(talonrow - 1, sidecol); 387 printw("=---="); 388 move(talonrow + 1, sidecol); 389 printw("=---="); 390 } 391 move(stockrow, sidecol); 392 printw("| |"); 393 move(talonrow, sidecol); 394 printw("| |"); 395 move(foundrow, fttlcol); 396 printw("| | | | | | | |"); 397 for (cnt = 0; cnt < 4; cnt++) { 398 switch(cnt) { 399 case 0: 400 col = atabcol; 401 break; 402 case 1: 403 col = btabcol; 404 break; 405 case 2: 406 col = ctabcol; 407 break; 408 case 3: 409 col = dtabcol; 410 break; 411 } 412 for(ptr = tableau[cnt], row = tabrow; 413 ptr != NIL; 414 ptr = ptr->next, row++) 415 removecard(col, row); 416 } 417 } 418 419 /* 420 * procedure to create a deck of cards 421 */ 422 initdeck(deck) 423 struct cardtype *deck[]; 424 { 425 int i; 426 int scnt; 427 char s; 428 int r; 429 430 i = 0; 431 for (scnt=0; scnt<4; scnt++) { 432 s = suitmap[scnt]; 433 for (r=Ace; r<=King; r++) { 434 deck[i] = &cards[i]; 435 cards[i].rank = r; 436 cards[i].suit = s; 437 cards[i].color = colormap[scnt]; 438 cards[i].next = NIL; 439 i++; 440 } 441 } 442 } 443 444 /* 445 * procedure to shuffle the deck 446 */ 447 shuffle(deck) 448 struct cardtype *deck[]; 449 { 450 int i,j; 451 struct cardtype *temp; 452 453 for (i=0; i<decksize; i++) { 454 deck[i]->visible = FALSE; 455 deck[i]->paid = FALSE; 456 } 457 for (i = decksize-1; i>=0; i--) { 458 j = random() % decksize; 459 if (i != j) { 460 temp = deck[i]; 461 deck[i] = deck[j]; 462 deck[j] = temp; 463 } 464 } 465 } 466 467 /* 468 * procedure to remove the card from the board 469 */ 470 removecard(a, b) 471 { 472 move(b, a); 473 printw(" "); 474 } 475 476 /* 477 * procedure to print the cards on the board 478 */ 479 printrank(a, b, cp, inverse) 480 struct cardtype *cp; 481 bool inverse; 482 { 483 move(b, a); 484 if (cp->rank != 10) 485 addch(' '); 486 if (inverse) 487 standout(); 488 switch (cp->rank) { 489 case 2: case 3: case 4: case 5: case 6: case 7: 490 case 8: case 9: case 10: 491 printw("%d", cp->rank); 492 break; 493 case Ace: 494 addch('A'); 495 break; 496 case Jack: 497 addch('J'); 498 break; 499 case Queen: 500 addch('Q'); 501 break; 502 case King: 503 addch('K'); 504 } 505 if (inverse) 506 standend(); 507 } 508 509 /* 510 * procedure to print out a card 511 */ 512 printcard(a, b, cp) 513 int a,b; 514 struct cardtype *cp; 515 { 516 if (cp == NIL) 517 removecard(a, b); 518 else if (cp->visible == FALSE) { 519 move(b, a); 520 printw(" ? "); 521 } else { 522 bool inverse = (cp->suit == 'd' || cp->suit == 'h'); 523 524 printrank(a, b, cp, inverse); 525 if (inverse) 526 standout(); 527 addch(cp->suit); 528 if (inverse) 529 standend(); 530 } 531 } 532 533 /* 534 * procedure to move the top card from one location to the top 535 * of another location. The pointers always point to the top 536 * of the piles. 537 */ 538 transit(source, dest) 539 struct cardtype **source, **dest; 540 { 541 struct cardtype *temp; 542 543 temp = *source; 544 *source = (*source)->next; 545 temp->next = *dest; 546 *dest = temp; 547 } 548 549 /* 550 * Procedure to set the cards on the foundation base when available. 551 * Note that it is only called on a foundation pile at the beginning of 552 * the game, so the pile will have exactly one card in it. 553 */ 554 fndbase(cp, column, row) 555 struct cardtype **cp; 556 { 557 bool nomore; 558 559 if (*cp != NIL) 560 do { 561 if ((*cp)->rank == basecard->rank) { 562 base++; 563 printcard(pilemap[base], foundrow, *cp); 564 if (*cp == tableau[0]) 565 length[0] = length[0] - 1; 566 if (*cp == tableau[1]) 567 length[1] = length[1] - 1; 568 if (*cp == tableau[2]) 569 length[2] = length[2] - 1; 570 if (*cp == tableau[3]) 571 length[3] = length[3] - 1; 572 transit(cp, &found[base]); 573 if (cp == &talon) 574 usedtalon(); 575 if (cp == &stock) 576 usedstock(); 577 if (*cp != NIL) { 578 printcard(column, row, *cp); 579 nomore = FALSE; 580 } else { 581 removecard(column, row); 582 nomore = TRUE; 583 } 584 cardsoff++; 585 if (infullgame) { 586 this.wins += valuepercardup; 587 game.wins += valuepercardup; 588 total.wins += valuepercardup; 589 } 590 } else 591 nomore = TRUE; 592 } while (nomore == FALSE); 593 } 594 595 /* 596 * procedure to initialize the things necessary for the game 597 */ 598 initgame() 599 { 600 register i; 601 602 for (i=0; i<18; i++) { 603 deck[i]->visible = TRUE; 604 deck[i]->paid = TRUE; 605 } 606 stockcnt = 13; 607 stock = deck[12]; 608 for (i=12; i>=1; i--) 609 deck[i]->next = deck[i - 1]; 610 deck[0]->next = NIL; 611 found[0] = deck[13]; 612 deck[13]->next = NIL; 613 for (i=1; i<4; i++) 614 found[i] = NIL; 615 basecard = found[0]; 616 for (i=14; i<18; i++) { 617 tableau[i - 14] = deck[i]; 618 deck[i]->next = NIL; 619 } 620 for (i=0; i<4; i++) { 621 bottom[i] = tableau[i]; 622 length[i] = tabrow; 623 } 624 hand = deck[18]; 625 for (i=18; i<decksize-1; i++) 626 deck[i]->next = deck[i + 1]; 627 deck[decksize-1]->next = NIL; 628 talon = NIL; 629 base = 0; 630 cinhand = 34; 631 taloncnt = 0; 632 timesthru = 0; 633 cardsoff = 1; 634 coldrow = ctoprow; 635 coldcol = cinitcol; 636 cnewrow = ctoprow; 637 cnewcol = cinitcol + cwidthcol; 638 } 639 640 /* 641 * procedure to print the beginning cards and to start each game 642 */ 643 startgame() 644 { 645 register int j; 646 647 shuffle(deck); 648 initgame(); 649 this.hand = costofhand; 650 game.hand += costofhand; 651 total.hand += costofhand; 652 this.inspection = 0; 653 this.game = 0; 654 this.runs = 0; 655 this.information = 0; 656 this.wins = 0; 657 this.thinktime = 0; 658 infullgame = FALSE; 659 startedgame = FALSE; 660 printcard(foundcol, foundrow, found[0]); 661 printcard(stockcol, stockrow, stock); 662 printcard(atabcol, tabrow, tableau[0]); 663 printcard(btabcol, tabrow, tableau[1]); 664 printcard(ctabcol, tabrow, tableau[2]); 665 printcard(dtabcol, tabrow, tableau[3]); 666 printcard(taloncol, talonrow, talon); 667 move(foundrow - 2, basecol); 668 printw("Base"); 669 move(foundrow - 1, basecol); 670 printw("Rank"); 671 printrank(basecol, foundrow, found[0], 0); 672 for (j=0; j<=3; j++) 673 fndbase(&tableau[j], pilemap[j], tabrow); 674 fndbase(&stock, stockcol, stockrow); 675 showstat(); /* show card counting info to cheaters */ 676 movetotalon(); 677 updatebettinginfo(); 678 } 679 680 /* 681 * procedure to clear the message printed from an error 682 */ 683 clearmsg() 684 { 685 int i; 686 687 if (errmsg == TRUE) { 688 errmsg = FALSE; 689 move(msgrow, msgcol); 690 for (i=0; i<25; i++) 691 addch(' '); 692 refresh(); 693 } 694 } 695 696 /* 697 * procedure to print an error message if the move is not listed 698 */ 699 dumberror() 700 { 701 errmsg = TRUE; 702 move(msgrow, msgcol); 703 printw("Not a proper move "); 704 } 705 706 /* 707 * procedure to print an error message if the move is not possible 708 */ 709 destinerror() 710 { 711 errmsg = TRUE; 712 move(msgrow, msgcol); 713 printw("Error: Can't move there"); 714 } 715 716 /* 717 * function to see if the source has cards in it 718 */ 719 bool 720 notempty(cp) 721 struct cardtype *cp; 722 { 723 if (cp == NIL) { 724 errmsg = TRUE; 725 move(msgrow, msgcol); 726 printw("Error: no cards to move"); 727 return (FALSE); 728 } else 729 return (TRUE); 730 } 731 732 /* 733 * function to see if the rank of one card is less than another 734 */ 735 bool 736 ranklower(cp1, cp2) 737 struct cardtype *cp1, *cp2; 738 { 739 if (cp2->rank == Ace) 740 if (cp1->rank == King) 741 return (TRUE); 742 else 743 return (FALSE); 744 else if (cp1->rank + 1 == cp2->rank) 745 return (TRUE); 746 else 747 return (FALSE); 748 } 749 750 /* 751 * function to check the cardcolor for moving to a tableau 752 */ 753 bool 754 diffcolor(cp1, cp2) 755 struct cardtype *cp1, *cp2; 756 { 757 if (cp1->color == cp2->color) 758 return (FALSE); 759 else 760 return (TRUE); 761 } 762 763 /* 764 * function to see if the card can move to the tableau 765 */ 766 bool 767 tabok(cp, des) 768 struct cardtype *cp; 769 { 770 if ((cp == stock) && (tableau[des] == NIL)) 771 return (TRUE); 772 else if (tableau[des] == NIL) 773 if (stock == NIL && 774 cp != bottom[0] && cp != bottom[1] && 775 cp != bottom[2] && cp != bottom[3]) 776 return (TRUE); 777 else 778 return (FALSE); 779 else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des])) 780 return (TRUE); 781 else 782 return (FALSE); 783 } 784 785 /* 786 * procedure to turn the cards onto the talon from the deck 787 */ 788 movetotalon() 789 { 790 int i, fin; 791 792 if (cinhand <= 3 && cinhand > 0) { 793 move(msgrow, msgcol); 794 printw("Hand is now empty "); 795 } 796 if (cinhand >= 3) 797 fin = 3; 798 else if (cinhand > 0) 799 fin = cinhand; 800 else if (talon != NIL) { 801 timesthru++; 802 errmsg = TRUE; 803 move(msgrow, msgcol); 804 if (timesthru != 4) { 805 printw("Talon is now the new hand"); 806 this.runs += costofrunthroughhand; 807 game.runs += costofrunthroughhand; 808 total.runs += costofrunthroughhand; 809 while (talon != NIL) { 810 transit(&talon, &hand); 811 cinhand++; 812 } 813 if (cinhand >= 3) 814 fin = 3; 815 else 816 fin = cinhand; 817 taloncnt = 0; 818 coldrow = ctoprow; 819 coldcol = cinitcol; 820 cnewrow = ctoprow; 821 cnewcol = cinitcol + cwidthcol; 822 clearstat(); 823 showstat(); 824 } else { 825 fin = 0; 826 done = TRUE; 827 printw("I believe you have lost"); 828 refresh(); 829 sleep(5); 830 } 831 } else { 832 errmsg = TRUE; 833 move(msgrow, msgcol); 834 printw("Talon and hand are empty"); 835 fin = 0; 836 } 837 for (i=0; i<fin; i++) { 838 transit(&hand, &talon); 839 INCRHAND(cnewrow, cnewcol); 840 INCRHAND(coldrow, coldcol); 841 removecard(cnewcol, cnewrow); 842 if (i == fin - 1) 843 talon->visible = TRUE; 844 if (Cflag) { 845 if (talon->paid == FALSE && talon->visible == TRUE) { 846 this.information += costofinformation; 847 game.information += costofinformation; 848 total.information += costofinformation; 849 talon->paid = TRUE; 850 } 851 printcard(coldcol, coldrow, talon); 852 } 853 } 854 if (fin != 0) { 855 printcard(taloncol, talonrow, talon); 856 cinhand -= fin; 857 taloncnt += fin; 858 if (Cflag) { 859 move(handstatrow, handstatcol); 860 printw("%3d", cinhand); 861 move(talonstatrow, talonstatcol); 862 printw("%3d", taloncnt); 863 } 864 fndbase(&talon, taloncol, talonrow); 865 } 866 } 867 868 869 /* 870 * procedure to print card counting info on screen 871 */ 872 showstat() 873 { 874 int row, col; 875 register struct cardtype *ptr; 876 877 if (!Cflag) 878 return; 879 move(talonstatrow, talonstatcol - 7); 880 printw("Talon: %3d", taloncnt); 881 move(handstatrow, handstatcol - 7); 882 printw("Hand: %3d", cinhand); 883 move(stockstatrow, stockstatcol - 7); 884 printw("Stock: %3d", stockcnt); 885 for ( row = coldrow, col = coldcol, ptr = talon; 886 ptr != NIL; 887 ptr = ptr->next ) { 888 if (ptr->paid == FALSE && ptr->visible == TRUE) { 889 ptr->paid = TRUE; 890 this.information += costofinformation; 891 game.information += costofinformation; 892 total.information += costofinformation; 893 } 894 printcard(col, row, ptr); 895 DECRHAND(row, col); 896 } 897 for ( row = cnewrow, col = cnewcol, ptr = hand; 898 ptr != NIL; 899 ptr = ptr->next ) { 900 if (ptr->paid == FALSE && ptr->visible == TRUE) { 901 ptr->paid = TRUE; 902 this.information += costofinformation; 903 game.information += costofinformation; 904 total.information += costofinformation; 905 } 906 INCRHAND(row, col); 907 printcard(col, row, ptr); 908 } 909 } 910 911 /* 912 * procedure to clear card counting info from screen 913 */ 914 clearstat() 915 { 916 int row; 917 918 move(talonstatrow, talonstatcol - 7); 919 printw(" "); 920 move(handstatrow, handstatcol - 7); 921 printw(" "); 922 move(stockstatrow, stockstatcol - 7); 923 printw(" "); 924 for ( row = ctoprow ; row <= cbotrow ; row++ ) { 925 move(row, cinitcol); 926 printw("%56s", " "); 927 } 928 } 929 930 /* 931 * procedure to update card counting base 932 */ 933 usedtalon() 934 { 935 removecard(coldcol, coldrow); 936 DECRHAND(coldrow, coldcol); 937 if (talon != NIL && (talon->visible == FALSE)) { 938 talon->visible = TRUE; 939 if (Cflag) { 940 this.information += costofinformation; 941 game.information += costofinformation; 942 total.information += costofinformation; 943 talon->paid = TRUE; 944 printcard(coldcol, coldrow, talon); 945 } 946 } 947 taloncnt--; 948 if (Cflag) { 949 move(talonstatrow, talonstatcol); 950 printw("%3d", taloncnt); 951 } 952 } 953 954 /* 955 * procedure to update stock card counting base 956 */ 957 usedstock() 958 { 959 stockcnt--; 960 if (Cflag) { 961 move(stockstatrow, stockstatcol); 962 printw("%3d", stockcnt); 963 } 964 } 965 966 /* 967 * let 'em know how they lost! 968 */ 969 showcards() 970 { 971 register struct cardtype *ptr; 972 int row; 973 974 if (!Cflag || cardsoff == 52) 975 return; 976 for (ptr = talon; ptr != NIL; ptr = ptr->next) { 977 ptr->visible = TRUE; 978 ptr->paid = TRUE; 979 } 980 for (ptr = hand; ptr != NIL; ptr = ptr->next) { 981 ptr->visible = TRUE; 982 ptr->paid = TRUE; 983 } 984 showstat(); 985 move(stockrow + 1, sidecol); 986 printw(" "); 987 move(talonrow - 2, sidecol); 988 printw(" "); 989 move(talonrow - 1, sidecol); 990 printw(" "); 991 move(talonrow, sidecol); 992 printw(" "); 993 move(talonrow + 1, sidecol); 994 printw(" "); 995 for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) { 996 move(row, stockcol - 1); 997 printw("| |"); 998 printcard(stockcol, row, ptr); 999 } 1000 if (stock == NIL) { 1001 move(row, stockcol - 1); 1002 printw("| |"); 1003 row++; 1004 } 1005 move(handstatrow, handstatcol - 7); 1006 printw(" "); 1007 move(row, stockcol - 1); 1008 printw("=---="); 1009 if ( cardsoff == 52 ) 1010 getcmd(moverow, movecol, "Hit return to exit"); 1011 } 1012 1013 /* 1014 * procedure to update the betting values 1015 */ 1016 updatebettinginfo() 1017 { 1018 long thiscosts, gamecosts, totalcosts; 1019 double thisreturn, gamereturn, totalreturn; 1020 time_t now; 1021 register long dollars; 1022 1023 time(&now); 1024 dollars = (now - acctstart) / secondsperdollar; 1025 if (dollars > 0) { 1026 acctstart += dollars * secondsperdollar; 1027 if (dollars > maxtimecharge) 1028 dollars = maxtimecharge; 1029 this.thinktime += dollars; 1030 game.thinktime += dollars; 1031 total.thinktime += dollars; 1032 } 1033 thiscosts = this.hand + this.inspection + this.game + 1034 this.runs + this.information + this.thinktime; 1035 gamecosts = game.hand + game.inspection + game.game + 1036 game.runs + game.information + game.thinktime; 1037 totalcosts = total.hand + total.inspection + total.game + 1038 total.runs + total.information + total.thinktime; 1039 this.worth = this.wins - thiscosts; 1040 game.worth = game.wins - gamecosts; 1041 total.worth = total.wins - totalcosts; 1042 thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0; 1043 gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0; 1044 totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0; 1045 if (status != BETTINGBOX) 1046 return; 1047 move(tboxrow + 2, boxcol + 13); 1048 printw("%4d%8d%9d", this.hand, game.hand, total.hand); 1049 move(tboxrow + 3, boxcol + 13); 1050 printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection); 1051 move(tboxrow + 4, boxcol + 13); 1052 printw("%4d%8d%9d", this.game, game.game, total.game); 1053 move(tboxrow + 5, boxcol + 13); 1054 printw("%4d%8d%9d", this.runs, game.runs, total.runs); 1055 move(tboxrow + 6, boxcol + 13); 1056 printw("%4d%8d%9d", this.information, game.information, 1057 total.information); 1058 move(tboxrow + 7, boxcol + 13); 1059 printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime); 1060 move(tboxrow + 8, boxcol + 13); 1061 printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts); 1062 move(tboxrow + 9, boxcol + 13); 1063 printw("%4d%8d%9d", this.wins, game.wins, total.wins); 1064 move(tboxrow + 10, boxcol + 13); 1065 printw("%4d%8d%9d", this.worth, game.worth, total.worth); 1066 move(tboxrow + 11, boxcol + 13); 1067 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn); 1068 } 1069 1070 /* 1071 * procedure to move a card from the stock or talon to the tableau 1072 */ 1073 simpletableau(cp, des) 1074 struct cardtype **cp; 1075 { 1076 int origin; 1077 1078 if (notempty(*cp)) { 1079 if (tabok(*cp, des)) { 1080 if (*cp == stock) 1081 origin = stk; 1082 else 1083 origin = tal; 1084 if (tableau[des] == NIL) 1085 bottom[des] = *cp; 1086 transit(cp, &tableau[des]); 1087 length[des]++; 1088 printcard(pilemap[des], length[des], tableau[des]); 1089 timesthru = 0; 1090 if (origin == stk) { 1091 usedstock(); 1092 printcard(stockcol, stockrow, stock); 1093 } else { 1094 usedtalon(); 1095 printcard(taloncol, talonrow, talon); 1096 } 1097 } else 1098 destinerror(); 1099 } 1100 } 1101 1102 /* 1103 * print the tableau 1104 */ 1105 tabprint(sour, des) 1106 { 1107 int dlength, slength, i; 1108 struct cardtype *tempcard; 1109 1110 for (i=tabrow; i<=length[sour]; i++) 1111 removecard(pilemap[sour], i); 1112 dlength = length[des] + 1; 1113 slength = length[sour]; 1114 if (slength == tabrow) 1115 printcard(pilemap[des], dlength, tableau[sour]); 1116 else 1117 while (slength != tabrow - 1) { 1118 tempcard = tableau[sour]; 1119 for (i=1; i<=slength-tabrow; i++) 1120 tempcard = tempcard->next; 1121 printcard(pilemap[des], dlength, tempcard); 1122 slength--; 1123 dlength++; 1124 } 1125 } 1126 1127 /* 1128 * procedure to move from the tableau to the tableau 1129 */ 1130 tabtotab(sour, des) 1131 register int sour, des; 1132 { 1133 struct cardtype *temp; 1134 1135 if (notempty(tableau[sour])) { 1136 if (tabok(bottom[sour], des)) { 1137 tabprint(sour, des); 1138 temp = bottom[sour]; 1139 bottom[sour] = NIL; 1140 if (bottom[des] == NIL) 1141 bottom[des] = temp; 1142 temp->next = tableau[des]; 1143 tableau[des] = tableau[sour]; 1144 tableau[sour] = NIL; 1145 length[des] = length[des] + (length[sour] - (tabrow - 1)); 1146 length[sour] = tabrow - 1; 1147 timesthru = 0; 1148 } else 1149 destinerror(); 1150 } 1151 } 1152 1153 /* 1154 * functions to see if the card can go onto the foundation 1155 */ 1156 bool 1157 rankhigher(cp, let) 1158 struct cardtype *cp; 1159 { 1160 if (found[let]->rank == King) 1161 if (cp->rank == Ace) 1162 return(TRUE); 1163 else 1164 return(FALSE); 1165 else if (cp->rank - 1 == found[let]->rank) 1166 return(TRUE); 1167 else 1168 return(FALSE); 1169 } 1170 1171 /* 1172 * function to determine if two cards are the same suit 1173 */ 1174 samesuit(cp, let) 1175 struct cardtype *cp; 1176 { 1177 if (cp->suit == found[let]->suit) 1178 return (TRUE); 1179 else 1180 return (FALSE); 1181 } 1182 1183 /* 1184 * procedure to move a card to the correct foundation pile 1185 */ 1186 movetofound(cp, source) 1187 struct cardtype **cp; 1188 { 1189 tempbase = 0; 1190 mtfdone = FALSE; 1191 if (notempty(*cp)) { 1192 do { 1193 if (found[tempbase] != NIL) 1194 if (rankhigher(*cp, tempbase) 1195 && samesuit(*cp, tempbase)) { 1196 if (*cp == stock) 1197 mtforigin = stk; 1198 else if (*cp == talon) 1199 mtforigin = tal; 1200 else 1201 mtforigin = tab; 1202 transit(cp, &found[tempbase]); 1203 printcard(pilemap[tempbase], 1204 foundrow, found[tempbase]); 1205 timesthru = 0; 1206 if (mtforigin == stk) { 1207 usedstock(); 1208 printcard(stockcol, stockrow, stock); 1209 } else if (mtforigin == tal) { 1210 usedtalon(); 1211 printcard(taloncol, talonrow, talon); 1212 } else { 1213 removecard(pilemap[source], length[source]); 1214 length[source]--; 1215 } 1216 cardsoff++; 1217 if (infullgame) { 1218 this.wins += valuepercardup; 1219 game.wins += valuepercardup; 1220 total.wins += valuepercardup; 1221 } 1222 mtfdone = TRUE; 1223 } else 1224 tempbase++; 1225 else 1226 tempbase++; 1227 } while ((tempbase != 4) && !mtfdone); 1228 if (!mtfdone) 1229 destinerror(); 1230 } 1231 } 1232 1233 /* 1234 * procedure to get a command 1235 */ 1236 getcmd(row, col, cp) 1237 int row, col; 1238 char *cp; 1239 { 1240 char cmd[2], ch; 1241 int i; 1242 1243 i = 0; 1244 move(row, col); 1245 printw("%-24s", cp); 1246 col += 1 + strlen(cp); 1247 move(row, col); 1248 refresh(); 1249 do { 1250 ch = getch() & 0177; 1251 if (ch >= 'A' && ch <= 'Z') 1252 ch += ('a' - 'A'); 1253 if (ch == '\f') { 1254 wrefresh(curscr); 1255 refresh(); 1256 } else if (i >= 2 && ch != _tty.sg_erase && ch != _tty.sg_kill) { 1257 if (ch != '\n' && ch != '\r' && ch != ' ') 1258 write(1, "\007", 1); 1259 } else if (ch == _tty.sg_erase && i > 0) { 1260 printw("\b \b"); 1261 refresh(); 1262 i--; 1263 } else if (ch == _tty.sg_kill && i > 0) { 1264 while (i > 0) { 1265 printw("\b \b"); 1266 i--; 1267 } 1268 refresh(); 1269 } else if (ch == '\032') { /* Control-Z */ 1270 suspend(); 1271 move(row, col + i); 1272 refresh(); 1273 } else if (isprint(ch)) { 1274 cmd[i++] = ch; 1275 addch(ch); 1276 refresh(); 1277 } 1278 } while (ch != '\n' && ch != '\r' && ch != ' '); 1279 srcpile = cmd[0]; 1280 destpile = cmd[1]; 1281 } 1282 1283 /* 1284 * Suspend the game (shell escape if no process control on system) 1285 */ 1286 suspend() 1287 { 1288 #ifndef SIGTSTP 1289 char *sh; 1290 #endif 1291 1292 updatebettinginfo(); 1293 move(21, 0); 1294 refresh(); 1295 if (dbfd != -1) { 1296 lseek(dbfd, uid * sizeof(struct betinfo), 0); 1297 write(dbfd, (char *)&total, sizeof(total)); 1298 } 1299 kill(getpid(), SIGTSTP); 1300 raw(); 1301 noecho(); 1302 } 1303 1304 /* 1305 * procedure to evaluate and make the specific moves 1306 */ 1307 movecard() 1308 { 1309 int source, dest; 1310 char osrcpile, odestpile; 1311 1312 done = FALSE; 1313 errmsg = FALSE; 1314 do { 1315 if (talon == NIL && hand != NIL) 1316 movetotalon(); 1317 if (cardsoff == 52) { 1318 refresh(); 1319 srcpile = 'q'; 1320 } else if (!startedgame) { 1321 move(msgrow, msgcol); 1322 errmsg = TRUE; 1323 switch (34 - taloncnt - cinhand) { 1324 default: 1325 errmsg = FALSE; 1326 break; 1327 case 1: 1328 printw("One card used from talon "); 1329 break; 1330 case 2: 1331 printw("Two cards used from talon "); 1332 break; 1333 case 3: 1334 printw(">3< cards used from talon "); 1335 break; 1336 } 1337 getcmd(moverow, movecol, "Move:"); 1338 } else 1339 getcmd(moverow, movecol, "Move:"); 1340 clearmsg(); 1341 if (srcpile >= '1' && srcpile <= '4') 1342 source = (int) (srcpile - '1'); 1343 if (destpile >= '1' && destpile <= '4') 1344 dest = (int) (destpile - '1'); 1345 if (!startedgame && 1346 (srcpile == 't' || srcpile == 's' || srcpile == 'h' || 1347 srcpile == '1' || srcpile == '2' || srcpile == '3' || 1348 srcpile == '4')) { 1349 startedgame = TRUE; 1350 osrcpile = srcpile; 1351 odestpile = destpile; 1352 if (status != BETTINGBOX) 1353 srcpile = 'y'; 1354 else do { 1355 getcmd(moverow, movecol, "Inspect game?"); 1356 } while (srcpile != 'y' && srcpile != 'n'); 1357 if (srcpile == 'n') { 1358 srcpile = 'q'; 1359 } else { 1360 this.inspection += costofinspection; 1361 game.inspection += costofinspection; 1362 total.inspection += costofinspection; 1363 srcpile = osrcpile; 1364 destpile = odestpile; 1365 } 1366 } 1367 switch (srcpile) { 1368 case 't': 1369 if (destpile == 'f' || destpile == 'F') 1370 movetofound(&talon, source); 1371 else if (destpile >= '1' && destpile <= '4') 1372 simpletableau(&talon, dest); 1373 else 1374 dumberror(); 1375 break; 1376 case 's': 1377 if (destpile == 'f' || destpile == 'F') 1378 movetofound(&stock, source); 1379 else if (destpile >= '1' && destpile <= '4') 1380 simpletableau(&stock, dest); 1381 else dumberror(); 1382 break; 1383 case 'h': 1384 if (destpile != 't' && destpile != 'T') { 1385 dumberror(); 1386 break; 1387 } 1388 if (infullgame) { 1389 movetotalon(); 1390 break; 1391 } 1392 if (status == BETTINGBOX) { 1393 do { 1394 getcmd(moverow, movecol, 1395 "Buy game?"); 1396 } while (srcpile != 'y' && 1397 srcpile != 'n'); 1398 if (srcpile == 'n') { 1399 showcards(); 1400 done = TRUE; 1401 break; 1402 } 1403 } 1404 infullgame = TRUE; 1405 this.wins += valuepercardup * cardsoff; 1406 game.wins += valuepercardup * cardsoff; 1407 total.wins += valuepercardup * cardsoff; 1408 this.game += costofgame; 1409 game.game += costofgame; 1410 total.game += costofgame; 1411 movetotalon(); 1412 break; 1413 case 'q': 1414 showcards(); 1415 done = TRUE; 1416 break; 1417 case 'b': 1418 printtopbettingbox(); 1419 printbottombettingbox(); 1420 status = BETTINGBOX; 1421 break; 1422 case 'x': 1423 clearabovemovebox(); 1424 clearbelowmovebox(); 1425 status = NOBOX; 1426 break; 1427 case 'i': 1428 printtopinstructions(); 1429 printbottominstructions(); 1430 status = INSTRUCTIONBOX; 1431 break; 1432 case 'c': 1433 Cflag = !Cflag; 1434 if (Cflag) 1435 showstat(); 1436 else 1437 clearstat(); 1438 break; 1439 case '1': case '2': case '3': case '4': 1440 if (destpile == 'f' || destpile == 'F') 1441 movetofound(&tableau[source], source); 1442 else if (destpile >= '1' && destpile <= '4') 1443 tabtotab(source, dest); 1444 else dumberror(); 1445 break; 1446 default: 1447 dumberror(); 1448 } 1449 fndbase(&stock, stockcol, stockrow); 1450 fndbase(&talon, taloncol, talonrow); 1451 updatebettinginfo(); 1452 } while (!done); 1453 } 1454 1455 char *basicinstructions[] = { 1456 "Here are brief instuctions to the game of Canfield:\n\n", 1457 " If you have never played solitaire before, it is recom-\n", 1458 "mended that you consult a solitaire instruction book. In\n", 1459 "Canfield, tableau cards may be built on each other downward\n", 1460 "in alternate colors. An entire pile must be moved as a unit\n", 1461 "in building. Top cards of the piles are available to be able\n", 1462 "to be played on foundations, but never into empty spaces.\n\n", 1463 " Spaces must be filled from the stock. The top card of\n", 1464 "the stock also is available to be played on foundations or\n", 1465 "built on tableau piles. After the stock is exhausted, ta-\n", 1466 "bleau spaces may be filled from the talon and the player may\n", 1467 "keep them open until he wishes to use them.\n\n", 1468 " Cards are dealt from the hand to the talon by threes\n", 1469 "and this repeats until there are no more cards in the hand\n", 1470 "or the player quits. To have cards dealt onto the talon the\n", 1471 "player types 'ht' for his move. Foundation base cards are\n", 1472 "also automatically moved to the foundation when they become\n", 1473 "available.\n\n", 1474 "push any key when you are finished: ", 1475 0 }; 1476 1477 char *bettinginstructions[] = { 1478 " The rules for betting are somewhat less strict than\n", 1479 "those used in the official version of the game. The initial\n", 1480 "deal costs $13. You may quit at this point or inspect the\n", 1481 "game. Inspection costs $13 and allows you to make as many\n", 1482 "moves as is possible without moving any cards from your hand\n", 1483 "to the talon. (the initial deal places three cards on the\n", 1484 "talon; if all these cards are used, three more are made\n", 1485 "available) Finally, if the game seems interesting, you must\n", 1486 "pay the final installment of $26. At this point you are\n", 1487 "credited at the rate of $5 for each card on the foundation;\n", 1488 "as the game progresses you are credited with $5 for each\n", 1489 "card that is moved to the foundation. Each run through the\n", 1490 "hand after the first costs $5. The card counting feature\n", 1491 "costs $1 for each unknown card that is identified. If the\n", 1492 "information is toggled on, you are only charged for cards\n", 1493 "that became visible since it was last turned on. Thus the\n", 1494 "maximum cost of information is $34. Playing time is charged\n", 1495 "at a rate of $1 per minute.\n\n", 1496 "push any key when you are finished: ", 1497 0 }; 1498 1499 /* 1500 * procedure to printout instructions 1501 */ 1502 instruct() 1503 { 1504 register char **cp; 1505 1506 move(originrow, origincol); 1507 printw("This is the game of solitaire called Canfield. Do\n"); 1508 printw("you want instructions for the game?"); 1509 do { 1510 getcmd(originrow + 3, origincol, "y or n?"); 1511 } while (srcpile != 'y' && srcpile != 'n'); 1512 if (srcpile == 'n') 1513 return; 1514 clear(); 1515 for (cp = basicinstructions; *cp != 0; cp++) 1516 printw(*cp); 1517 refresh(); 1518 getch(); 1519 clear(); 1520 move(originrow, origincol); 1521 printw("Do you want instructions for betting?"); 1522 do { 1523 getcmd(originrow + 2, origincol, "y or n?"); 1524 } while (srcpile != 'y' && srcpile != 'n'); 1525 if (srcpile == 'n') 1526 return; 1527 clear(); 1528 for (cp = bettinginstructions; *cp != 0; cp++) 1529 printw(*cp); 1530 refresh(); 1531 getch(); 1532 } 1533 1534 /* 1535 * procedure to initialize the game 1536 */ 1537 initall() 1538 { 1539 int i; 1540 1541 srandom(getpid()); 1542 time(&acctstart); 1543 initdeck(deck); 1544 uid = getuid(); 1545 if (uid < 0) 1546 uid = 0; 1547 dbfd = open(_PATH_SCORE, 2); 1548 if (dbfd < 0) 1549 return; 1550 i = lseek(dbfd, uid * sizeof(struct betinfo), 0); 1551 if (i < 0) { 1552 close(dbfd); 1553 dbfd = -1; 1554 return; 1555 } 1556 i = read(dbfd, (char *)&total, sizeof(total)); 1557 if (i < 0) { 1558 close(dbfd); 1559 dbfd = -1; 1560 return; 1561 } 1562 } 1563 1564 /* 1565 * procedure to end the game 1566 */ 1567 bool 1568 finish() 1569 { 1570 int row, col; 1571 1572 if (cardsoff == 52) { 1573 getcmd(moverow, movecol, "Hit return to exit"); 1574 clear(); 1575 refresh(); 1576 move(originrow, origincol); 1577 printw("CONGRATULATIONS!\n"); 1578 printw("You won the game. That is a feat to be proud of.\n"); 1579 row = originrow + 5; 1580 col = origincol; 1581 } else { 1582 move(msgrow, msgcol); 1583 printw("You got %d card", cardsoff); 1584 if (cardsoff > 1) 1585 printw("s"); 1586 printw(" off "); 1587 move(msgrow, msgcol); 1588 row = moverow; 1589 col = movecol; 1590 } 1591 do { 1592 getcmd(row, col, "Play again (y or n)?"); 1593 } while (srcpile != 'y' && srcpile != 'n'); 1594 errmsg = TRUE; 1595 clearmsg(); 1596 if (srcpile == 'y') 1597 return (FALSE); 1598 else 1599 return (TRUE); 1600 } 1601 1602 /* 1603 * Field an interrupt. 1604 */ 1605 askquit() 1606 { 1607 move(msgrow, msgcol); 1608 printw("Really wish to quit? "); 1609 do { 1610 getcmd(moverow, movecol, "y or n?"); 1611 } while (srcpile != 'y' && srcpile != 'n'); 1612 clearmsg(); 1613 if (srcpile == 'y') 1614 cleanup(); 1615 signal(SIGINT, askquit); 1616 } 1617 1618 /* 1619 * procedure to clean up and exit 1620 */ 1621 cleanup() 1622 { 1623 1624 total.thinktime += 1; 1625 status = NOBOX; 1626 updatebettinginfo(); 1627 if (dbfd != -1) { 1628 lseek(dbfd, uid * sizeof(struct betinfo), 0); 1629 write(dbfd, (char *)&total, sizeof(total)); 1630 close(dbfd); 1631 } 1632 clear(); 1633 move(22,0); 1634 refresh(); 1635 endwin(); 1636 exit(0); 1637 /* NOTREACHED */ 1638 } 1639 1640 /* 1641 * Can you tell that this used to be a Pascal program? 1642 */ 1643 main(argc, argv) 1644 int argc; 1645 char *argv[]; 1646 { 1647 #ifdef MAXLOAD 1648 double vec[3]; 1649 1650 loadav(vec); 1651 if (vec[2] >= MAXLOAD) { 1652 puts("The system load is too high. Try again later."); 1653 exit(0); 1654 } 1655 #endif 1656 signal(SIGINT, askquit); 1657 signal(SIGHUP, cleanup); 1658 signal(SIGTERM, cleanup); 1659 initscr(); 1660 raw(); 1661 noecho(); 1662 initall(); 1663 instruct(); 1664 makeboard(); 1665 for (;;) { 1666 startgame(); 1667 movecard(); 1668 if (finish()) 1669 break; 1670 if (cardsoff == 52) 1671 makeboard(); 1672 else 1673 cleanupboard(); 1674 } 1675 cleanup(); 1676 /* NOTREACHED */ 1677 } 1678