games: Massive style(9) cleanup commit. Reduces differences to NetBSD.
[dragonfly.git] / games / canfield / canfield / canfield.c
blobfd91c7f993ccef1a0b22e43ffec0330a07299835
1 /*-
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
29 * @(#) Copyright (c) 1980, 1993 The Regents of the University of California. All rights reserved.
30 * @(#)canfield.c 8.1 (Berkeley) 5/31/93
31 * $FreeBSD: src/games/canfield/canfield/canfield.c,v 1.11 1999/12/12 07:25:13 billf Exp $
32 * $DragonFly: src/games/canfield/canfield/canfield.c,v 1.4 2005/11/19 09:50:30 swildner Exp $
36 * The canfield program
38 * Authors:
39 * Originally written: Steve Levine
40 * Converted to use curses and debugged: Steve Feldman
41 * Card counting: Kirk McKusick and Mikey Olson
42 * User interface cleanups: Eric Allman and Kirk McKusick
43 * Betting by Kirk McKusick
46 #include <sys/types.h>
48 #include <ctype.h>
49 #include <curses.h>
50 #include <fcntl.h>
51 #include <signal.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <time.h>
55 #include <unistd.h>
57 #include "pathnames.h"
59 #define decksize 52
60 #define originrow 0
61 #define origincol 0
62 #define basecol 1
63 #define boxcol 42
64 #define tboxrow 2
65 #define bboxrow 17
66 #define movecol 43
67 #define moverow 16
68 #define msgcol 43
69 #define msgrow 15
70 #define titlecol 30
71 #define titlerow 0
72 #define sidecol 1
73 #define ottlrow 6
74 #define foundcol 11
75 #define foundrow 3
76 #define stockcol 2
77 #define stockrow 8
78 #define fttlcol 10
79 #define fttlrow 1
80 #define taloncol 2
81 #define talonrow 13
82 #define tabrow 8
83 #define ctoprow 21
84 #define cbotrow 23
85 #define cinitcol 14
86 #define cheightcol 1
87 #define cwidthcol 4
88 #define handstatrow 21
89 #define handstatcol 7
90 #define talonstatrow 22
91 #define talonstatcol 7
92 #define stockstatrow 23
93 #define stockstatcol 7
94 #define Ace 1
95 #define Jack 11
96 #define Queen 12
97 #define King 13
98 #define atabcol 11
99 #define btabcol 18
100 #define ctabcol 25
101 #define dtabcol 32
103 #define spades 's'
104 #define clubs 'c'
105 #define hearts 'h'
106 #define diamonds 'd'
107 #define black 'b'
108 #define red 'r'
110 #define stk 1
111 #define tal 2
112 #define tab 3
113 #define INCRHAND(row, col) {\
114 row -= cheightcol;\
115 if (row < ctoprow) {\
116 row = cbotrow;\
117 col += cwidthcol;\
120 #define DECRHAND(row, col) {\
121 row += cheightcol;\
122 if (row > cbotrow) {\
123 row = ctoprow;\
124 col -= cwidthcol;\
129 struct cardtype {
130 char suit;
131 char color;
132 bool visible;
133 bool paid;
134 int rank;
135 struct cardtype *next;
138 #define NIL ((struct cardtype *) -1)
140 struct cardtype *deck[decksize];
141 struct cardtype cards[decksize];
142 struct cardtype *bottom[4], *found[4], *tableau[4];
143 struct cardtype *talon, *hand, *stock, *basecard;
144 int length[4];
145 int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru;
146 char suitmap[4] = {spades, clubs, hearts, diamonds};
147 char colormap[4] = {black, black, red, red};
148 char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol};
149 char srcpile, destpile;
150 int mtforigin, tempbase;
151 int coldcol, cnewcol, coldrow, cnewrow;
152 bool errmsg, done;
153 bool mtfdone, Cflag = FALSE;
154 #define INSTRUCTIONBOX 1
155 #define BETTINGBOX 2
156 #define NOBOX 3
157 int status = INSTRUCTIONBOX;
158 int uid;
161 * Basic betting costs
163 #define costofhand 13
164 #define costofinspection 13
165 #define costofgame 26
166 #define costofrunthroughhand 5
167 #define costofinformation 1
168 #define secondsperdollar 60
169 #define maxtimecharge 3
170 #define valuepercardup 5
172 * Variables associated with betting
174 struct betinfo {
175 long hand; /* cost of dealing hand */
176 long inspection; /* cost of inspecting hand */
177 long game; /* cost of buying game */
178 long runs; /* cost of running through hands */
179 long information; /* cost of information */
180 long thinktime; /* cost of thinking time */
181 long wins; /* total winnings */
182 long worth; /* net worth after costs */
184 struct betinfo this, game, total;
185 bool startedgame = FALSE, infullgame = FALSE;
186 time_t acctstart;
187 int dbfd = -1;
189 static void askquit(int);
190 static void cleanup(int);
191 static void cleanupboard(void);
192 static void clearabovemovebox(void);
193 static void clearbelowmovebox(void);
194 static void clearmsg(void);
195 static void clearstat(void);
196 static void destinerror(void);
197 static bool diffcolor(struct cardtype *, struct cardtype *);
198 static void dumberror(void);
199 static bool finish(void);
200 static void fndbase(struct cardtype **, int, int);
201 static void getcmd(int, int, const char *);
202 static void initall(void);
203 static void initdeck(struct cardtype *[]);
204 static void initgame(void);
205 static void instruct(void);
206 static void makeboard(void);
207 static void movebox(void);
208 static void movecard(void);
209 static void movetofound(struct cardtype **, int);
210 static void movetotalon(void);
211 static bool notempty(struct cardtype *);
212 static void printbottombettingbox(void);
213 static void printbottominstructions(void);
214 static void printcard(int, int, struct cardtype *);
215 static void printrank(int, int, struct cardtype *, bool);
216 static void printtopbettingbox(void);
217 static void printtopinstructions(void);
218 static bool rankhigher(struct cardtype *, int);
219 static bool ranklower(struct cardtype *, struct cardtype *);
220 static void removecard(int, int);
221 static bool samesuit(struct cardtype *, int);
222 static void showcards(void);
223 static void showstat(void);
224 static void shuffle(struct cardtype *[]);
225 static void simpletableau(struct cardtype **, int);
226 static void startgame(void);
227 static void suspend(void);
228 static bool tabok(struct cardtype *, int);
229 static void tabprint(int, int);
230 static void tabtotab(int, int);
231 static void transit(struct cardtype **, struct cardtype **);
232 static void updatebettinginfo(void);
233 static void usedstock(void);
234 static void usedtalon(void);
237 * The following procedures print the board onto the screen using the
238 * addressible cursor. The end of these procedures will also be
239 * separated from the rest of the program.
241 * procedure to set the move command box
243 static void
244 movebox(void)
246 switch (status) {
247 case BETTINGBOX:
248 printtopbettingbox();
249 break;
250 case NOBOX:
251 clearabovemovebox();
252 break;
253 case INSTRUCTIONBOX:
254 printtopinstructions();
255 break;
257 move(moverow, boxcol);
258 printw("| |");
259 move(msgrow, boxcol);
260 printw("| |");
261 switch (status) {
262 case BETTINGBOX:
263 printbottombettingbox();
264 break;
265 case NOBOX:
266 clearbelowmovebox();
267 break;
268 case INSTRUCTIONBOX:
269 printbottominstructions();
270 break;
272 refresh();
276 * print directions above move box
278 static void
279 printtopinstructions(void)
281 move(tboxrow, boxcol);
282 printw("*----------------------------------*");
283 move(tboxrow + 1, boxcol);
284 printw("| MOVES |");
285 move(tboxrow + 2, boxcol);
286 printw("|s# = stock to tableau |");
287 move(tboxrow + 3, boxcol);
288 printw("|sf = stock to foundation |");
289 move(tboxrow + 4, boxcol);
290 printw("|t# = talon to tableau |");
291 move(tboxrow + 5, boxcol);
292 printw("|tf = talon to foundation |");
293 move(tboxrow + 6, boxcol);
294 printw("|## = tableau to tableau |");
295 move(tboxrow + 7, boxcol);
296 printw("|#f = tableau to foundation |");
297 move(tboxrow + 8, boxcol);
298 printw("|ht = hand to talon |");
299 move(tboxrow + 9, boxcol);
300 printw("|c = toggle card counting |");
301 move(tboxrow + 10, boxcol);
302 printw("|b = present betting information |");
303 move(tboxrow + 11, boxcol);
304 printw("|q = quit to end the game |");
305 move(tboxrow + 12, boxcol);
306 printw("|==================================|");
310 * Print the betting box.
312 static void
313 printtopbettingbox(void)
316 move(tboxrow, boxcol);
317 printw("*----------------------------------*");
318 move(tboxrow + 1, boxcol);
319 printw("|Costs Hand Game Total |");
320 move(tboxrow + 2, boxcol);
321 printw("| Hands |");
322 move(tboxrow + 3, boxcol);
323 printw("| Inspections |");
324 move(tboxrow + 4, boxcol);
325 printw("| Games |");
326 move(tboxrow + 5, boxcol);
327 printw("| Runs |");
328 move(tboxrow + 6, boxcol);
329 printw("| Information |");
330 move(tboxrow + 7, boxcol);
331 printw("| Think time |");
332 move(tboxrow + 8, boxcol);
333 printw("|Total Costs |");
334 move(tboxrow + 9, boxcol);
335 printw("|Winnings |");
336 move(tboxrow + 10, boxcol);
337 printw("|Net Worth |");
338 move(tboxrow + 11, boxcol);
339 printw("|Return |");
340 move(tboxrow + 12, boxcol);
341 printw("|==================================|");
345 * clear info above move box
347 static void
348 clearabovemovebox(void)
350 int i;
352 for (i = 0; i <= 11; i++) {
353 move(tboxrow + i, boxcol);
354 printw(" ");
356 move(tboxrow + 12, boxcol);
357 printw("*----------------------------------*");
361 * print instructions below move box
363 static void
364 printbottominstructions(void)
366 move(bboxrow, boxcol);
367 printw("|Replace # with the number of the |");
368 move(bboxrow + 1, boxcol);
369 printw("|tableau you want. |");
370 move(bboxrow + 2, boxcol);
371 printw("*----------------------------------*");
375 * print betting information below move box
377 static void
378 printbottombettingbox(void)
380 move(bboxrow, boxcol);
381 printw("|x = toggle information box |");
382 move(bboxrow + 1, boxcol);
383 printw("|i = list playing instructions |");
384 move(bboxrow + 2, boxcol);
385 printw("*----------------------------------*");
389 * clear info below move box
391 static void
392 clearbelowmovebox(void)
394 int i;
396 move(bboxrow, boxcol);
397 printw("*----------------------------------*");
398 for (i = 1; i <= 2; i++) {
399 move(bboxrow + i, boxcol);
400 printw(" ");
405 * procedure to put the board on the screen using addressable cursor
407 static void
408 makeboard(void)
410 clear();
411 refresh();
412 move(titlerow, titlecol);
413 printw("=-> CANFIELD <-=");
414 move(fttlrow, fttlcol);
415 printw("foundation");
416 move(foundrow - 1, fttlcol);
417 printw("=---= =---= =---= =---=");
418 move(foundrow, fttlcol);
419 printw("| | | | | | | |");
420 move(foundrow + 1, fttlcol);
421 printw("=---= =---= =---= =---=");
422 move(ottlrow, sidecol);
423 printw("stock tableau");
424 move(stockrow - 1, sidecol);
425 printw("=---=");
426 move(stockrow, sidecol);
427 printw("| |");
428 move(stockrow + 1, sidecol);
429 printw("=---=");
430 move(talonrow - 2, sidecol);
431 printw("talon");
432 move(talonrow - 1, sidecol);
433 printw("=---=");
434 move(talonrow, sidecol);
435 printw("| |");
436 move(talonrow + 1, sidecol);
437 printw("=---=");
438 move(tabrow - 1, atabcol);
439 printw("-1- -2- -3- -4-");
440 movebox();
444 * clean up the board for another game
446 static void
447 cleanupboard(void)
449 int cnt, row, col;
450 struct cardtype *ptr;
452 col = 0;
453 if (Cflag) {
454 clearstat();
455 for(ptr = stock, row = stockrow;
456 ptr != NIL;
457 ptr = ptr->next, row++) {
458 move(row, sidecol);
459 printw(" ");
461 move(row, sidecol);
462 printw(" ");
463 move(stockrow + 1, sidecol);
464 printw("=---=");
465 move(talonrow - 2, sidecol);
466 printw("talon");
467 move(talonrow - 1, sidecol);
468 printw("=---=");
469 move(talonrow + 1, sidecol);
470 printw("=---=");
472 move(stockrow, sidecol);
473 printw("| |");
474 move(talonrow, sidecol);
475 printw("| |");
476 move(foundrow, fttlcol);
477 printw("| | | | | | | |");
478 for (cnt = 0; cnt < 4; cnt++) {
479 switch(cnt) {
480 case 0:
481 col = atabcol;
482 break;
483 case 1:
484 col = btabcol;
485 break;
486 case 2:
487 col = ctabcol;
488 break;
489 case 3:
490 col = dtabcol;
491 break;
493 for(ptr = tableau[cnt], row = tabrow;
494 ptr != NIL;
495 ptr = ptr->next, row++)
496 removecard(col, row);
501 * procedure to create a deck of cards
503 static void
504 initdeck(struct cardtype *ideck[])
506 int i;
507 int scnt;
508 char s;
509 int r;
511 i = 0;
512 for (scnt=0; scnt<4; scnt++) {
513 s = suitmap[scnt];
514 for (r=Ace; r<=King; r++) {
515 ideck[i] = &cards[i];
516 cards[i].rank = r;
517 cards[i].suit = s;
518 cards[i].color = colormap[scnt];
519 cards[i].next = NIL;
520 i++;
526 * procedure to shuffle the deck
528 static void
529 shuffle(struct cardtype *ideck[])
531 int i,j;
532 struct cardtype *temp;
534 for (i=0; i<decksize; i++) {
535 ideck[i]->visible = FALSE;
536 ideck[i]->paid = FALSE;
538 for (i = decksize-1; i>=0; i--) {
539 j = random() % decksize;
540 if (i != j) {
541 temp = ideck[i];
542 ideck[i] = ideck[j];
543 ideck[j] = temp;
549 * procedure to remove the card from the board
551 static void
552 removecard(int a, int b)
554 move(b, a);
555 printw(" ");
559 * procedure to print the cards on the board
561 static void
562 printrank(int a, int b, struct cardtype *cp, bool inverse)
564 move(b, a);
565 if (cp->rank != 10)
566 addch(' ');
567 if (inverse)
568 standout();
569 switch (cp->rank) {
570 case 2: case 3: case 4: case 5: case 6: case 7:
571 case 8: case 9: case 10:
572 printw("%d", cp->rank);
573 break;
574 case Ace:
575 addch('A');
576 break;
577 case Jack:
578 addch('J');
579 break;
580 case Queen:
581 addch('Q');
582 break;
583 case King:
584 addch('K');
586 if (inverse)
587 standend();
591 * procedure to print out a card
593 static void
594 printcard(int a, int b, struct cardtype *cp)
596 if (cp == NIL)
597 removecard(a, b);
598 else if (cp->visible == FALSE) {
599 move(b, a);
600 printw(" ? ");
601 } else {
602 bool inverse = (cp->suit == 'd' || cp->suit == 'h');
604 printrank(a, b, cp, inverse);
605 if (inverse)
606 standout();
607 addch(cp->suit);
608 if (inverse)
609 standend();
614 * procedure to move the top card from one location to the top
615 * of another location. The pointers always point to the top
616 * of the piles.
618 static void
619 transit(struct cardtype **source, struct cardtype **dest)
621 struct cardtype *temp;
623 temp = *source;
624 *source = (*source)->next;
625 temp->next = *dest;
626 *dest = temp;
630 * Procedure to set the cards on the foundation base when available.
631 * Note that it is only called on a foundation pile at the beginning of
632 * the game, so the pile will have exactly one card in it.
634 static void
635 fndbase(struct cardtype **cp, int column, int row)
637 bool nomore;
639 if (*cp != NIL)
640 do {
641 if ((*cp)->rank == basecard->rank) {
642 base++;
643 printcard(pilemap[base], foundrow, *cp);
644 if (*cp == tableau[0])
645 length[0] = length[0] - 1;
646 if (*cp == tableau[1])
647 length[1] = length[1] - 1;
648 if (*cp == tableau[2])
649 length[2] = length[2] - 1;
650 if (*cp == tableau[3])
651 length[3] = length[3] - 1;
652 transit(cp, &found[base]);
653 if (cp == &talon)
654 usedtalon();
655 if (cp == &stock)
656 usedstock();
657 if (*cp != NIL) {
658 printcard(column, row, *cp);
659 nomore = FALSE;
660 } else {
661 removecard(column, row);
662 nomore = TRUE;
664 cardsoff++;
665 if (infullgame) {
666 this.wins += valuepercardup;
667 game.wins += valuepercardup;
668 total.wins += valuepercardup;
670 } else
671 nomore = TRUE;
672 } while (nomore == FALSE);
676 * procedure to initialize the things necessary for the game
678 static void
679 initgame(void)
681 int i;
683 for (i=0; i<18; i++) {
684 deck[i]->visible = TRUE;
685 deck[i]->paid = TRUE;
687 stockcnt = 13;
688 stock = deck[12];
689 for (i=12; i>=1; i--)
690 deck[i]->next = deck[i - 1];
691 deck[0]->next = NIL;
692 found[0] = deck[13];
693 deck[13]->next = NIL;
694 for (i=1; i<4; i++)
695 found[i] = NIL;
696 basecard = found[0];
697 for (i=14; i<18; i++) {
698 tableau[i - 14] = deck[i];
699 deck[i]->next = NIL;
701 for (i=0; i<4; i++) {
702 bottom[i] = tableau[i];
703 length[i] = tabrow;
705 hand = deck[18];
706 for (i=18; i<decksize-1; i++)
707 deck[i]->next = deck[i + 1];
708 deck[decksize-1]->next = NIL;
709 talon = NIL;
710 base = 0;
711 cinhand = 34;
712 taloncnt = 0;
713 timesthru = 0;
714 cardsoff = 1;
715 coldrow = ctoprow;
716 coldcol = cinitcol;
717 cnewrow = ctoprow;
718 cnewcol = cinitcol + cwidthcol;
722 * procedure to print the beginning cards and to start each game
724 static void
725 startgame(void)
727 int j;
729 shuffle(deck);
730 initgame();
731 this.hand = costofhand;
732 game.hand += costofhand;
733 total.hand += costofhand;
734 this.inspection = 0;
735 this.game = 0;
736 this.runs = 0;
737 this.information = 0;
738 this.wins = 0;
739 this.thinktime = 0;
740 infullgame = FALSE;
741 startedgame = FALSE;
742 printcard(foundcol, foundrow, found[0]);
743 printcard(stockcol, stockrow, stock);
744 printcard(atabcol, tabrow, tableau[0]);
745 printcard(btabcol, tabrow, tableau[1]);
746 printcard(ctabcol, tabrow, tableau[2]);
747 printcard(dtabcol, tabrow, tableau[3]);
748 printcard(taloncol, talonrow, talon);
749 move(foundrow - 2, basecol);
750 printw("Base");
751 move(foundrow - 1, basecol);
752 printw("Rank");
753 printrank(basecol, foundrow, found[0], 0);
754 for (j=0; j<=3; j++)
755 fndbase(&tableau[j], pilemap[j], tabrow);
756 fndbase(&stock, stockcol, stockrow);
757 showstat(); /* show card counting info to cheaters */
758 movetotalon();
759 updatebettinginfo();
763 * procedure to clear the message printed from an error
765 static void
766 clearmsg(void)
768 int i;
770 if (errmsg == TRUE) {
771 errmsg = FALSE;
772 move(msgrow, msgcol);
773 for (i=0; i<25; i++)
774 addch(' ');
775 refresh();
780 * procedure to print an error message if the move is not listed
782 static void
783 dumberror(void)
785 errmsg = TRUE;
786 move(msgrow, msgcol);
787 printw("Not a proper move ");
791 * procedure to print an error message if the move is not possible
793 static void
794 destinerror(void)
796 errmsg = TRUE;
797 move(msgrow, msgcol);
798 printw("Error: Can't move there");
802 * function to see if the source has cards in it
804 static bool
805 notempty(struct cardtype *cp)
807 if (cp == NIL) {
808 errmsg = TRUE;
809 move(msgrow, msgcol);
810 printw("Error: no cards to move");
811 return (FALSE);
812 } else
813 return (TRUE);
817 * function to see if the rank of one card is less than another
819 static bool
820 ranklower(struct cardtype *cp1, struct cardtype *cp2)
822 if (cp2->rank == Ace)
823 if (cp1->rank == King)
824 return (TRUE);
825 else
826 return (FALSE);
827 else if (cp1->rank + 1 == cp2->rank)
828 return (TRUE);
829 else
830 return (FALSE);
834 * function to check the cardcolor for moving to a tableau
836 static bool
837 diffcolor(struct cardtype *cp1, struct cardtype *cp2)
839 if (cp1->color == cp2->color)
840 return (FALSE);
841 else
842 return (TRUE);
846 * function to see if the card can move to the tableau
848 static bool
849 tabok(struct cardtype *cp, int des)
851 if ((cp == stock) && (tableau[des] == NIL))
852 return (TRUE);
853 else if (tableau[des] == NIL)
854 if (stock == NIL &&
855 cp != bottom[0] && cp != bottom[1] &&
856 cp != bottom[2] && cp != bottom[3])
857 return (TRUE);
858 else
859 return (FALSE);
860 else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
861 return (TRUE);
862 else
863 return (FALSE);
867 * procedure to turn the cards onto the talon from the deck
869 static void
870 movetotalon(void)
872 int i, fin;
874 if (cinhand <= 3 && cinhand > 0) {
875 move(msgrow, msgcol);
876 printw("Hand is now empty ");
878 if (cinhand >= 3)
879 fin = 3;
880 else if (cinhand > 0)
881 fin = cinhand;
882 else if (talon != NIL) {
883 timesthru++;
884 errmsg = TRUE;
885 move(msgrow, msgcol);
886 if (timesthru != 4) {
887 printw("Talon is now the new hand");
888 this.runs += costofrunthroughhand;
889 game.runs += costofrunthroughhand;
890 total.runs += costofrunthroughhand;
891 while (talon != NIL) {
892 transit(&talon, &hand);
893 cinhand++;
895 if (cinhand >= 3)
896 fin = 3;
897 else
898 fin = cinhand;
899 taloncnt = 0;
900 coldrow = ctoprow;
901 coldcol = cinitcol;
902 cnewrow = ctoprow;
903 cnewcol = cinitcol + cwidthcol;
904 clearstat();
905 showstat();
906 } else {
907 fin = 0;
908 done = TRUE;
909 printw("I believe you have lost");
910 refresh();
911 sleep(5);
913 } else {
914 errmsg = TRUE;
915 move(msgrow, msgcol);
916 printw("Talon and hand are empty");
917 fin = 0;
919 for (i=0; i<fin; i++) {
920 transit(&hand, &talon);
921 INCRHAND(cnewrow, cnewcol);
922 INCRHAND(coldrow, coldcol);
923 removecard(cnewcol, cnewrow);
924 if (i == fin - 1)
925 talon->visible = TRUE;
926 if (Cflag) {
927 if (talon->paid == FALSE && talon->visible == TRUE) {
928 this.information += costofinformation;
929 game.information += costofinformation;
930 total.information += costofinformation;
931 talon->paid = TRUE;
933 printcard(coldcol, coldrow, talon);
936 if (fin != 0) {
937 printcard(taloncol, talonrow, talon);
938 cinhand -= fin;
939 taloncnt += fin;
940 if (Cflag) {
941 move(handstatrow, handstatcol);
942 printw("%3d", cinhand);
943 move(talonstatrow, talonstatcol);
944 printw("%3d", taloncnt);
946 fndbase(&talon, taloncol, talonrow);
952 * procedure to print card counting info on screen
954 static void
955 showstat(void)
957 int row, col;
958 struct cardtype *ptr;
960 if (!Cflag)
961 return;
962 move(talonstatrow, talonstatcol - 7);
963 printw("Talon: %3d", taloncnt);
964 move(handstatrow, handstatcol - 7);
965 printw("Hand: %3d", cinhand);
966 move(stockstatrow, stockstatcol - 7);
967 printw("Stock: %3d", stockcnt);
968 for ( row = coldrow, col = coldcol, ptr = talon;
969 ptr != NIL;
970 ptr = ptr->next ) {
971 if (ptr->paid == FALSE && ptr->visible == TRUE) {
972 ptr->paid = TRUE;
973 this.information += costofinformation;
974 game.information += costofinformation;
975 total.information += costofinformation;
977 printcard(col, row, ptr);
978 DECRHAND(row, col);
980 for ( row = cnewrow, col = cnewcol, ptr = hand;
981 ptr != NIL;
982 ptr = ptr->next ) {
983 if (ptr->paid == FALSE && ptr->visible == TRUE) {
984 ptr->paid = TRUE;
985 this.information += costofinformation;
986 game.information += costofinformation;
987 total.information += costofinformation;
989 INCRHAND(row, col);
990 printcard(col, row, ptr);
995 * procedure to clear card counting info from screen
997 static void
998 clearstat(void)
1000 int row;
1002 move(talonstatrow, talonstatcol - 7);
1003 printw(" ");
1004 move(handstatrow, handstatcol - 7);
1005 printw(" ");
1006 move(stockstatrow, stockstatcol - 7);
1007 printw(" ");
1008 for ( row = ctoprow ; row <= cbotrow ; row++ ) {
1009 move(row, cinitcol);
1010 printw("%56s", " ");
1015 * procedure to update card counting base
1017 static void
1018 usedtalon(void)
1020 removecard(coldcol, coldrow);
1021 DECRHAND(coldrow, coldcol);
1022 if (talon != NIL && (talon->visible == FALSE)) {
1023 talon->visible = TRUE;
1024 if (Cflag) {
1025 this.information += costofinformation;
1026 game.information += costofinformation;
1027 total.information += costofinformation;
1028 talon->paid = TRUE;
1029 printcard(coldcol, coldrow, talon);
1032 taloncnt--;
1033 if (Cflag) {
1034 move(talonstatrow, talonstatcol);
1035 printw("%3d", taloncnt);
1040 * procedure to update stock card counting base
1042 static void
1043 usedstock(void)
1045 stockcnt--;
1046 if (Cflag) {
1047 move(stockstatrow, stockstatcol);
1048 printw("%3d", stockcnt);
1053 * let 'em know how they lost!
1055 static void
1056 showcards(void)
1058 struct cardtype *ptr;
1059 int row;
1061 if (!Cflag || cardsoff == 52)
1062 return;
1063 for (ptr = talon; ptr != NIL; ptr = ptr->next) {
1064 ptr->visible = TRUE;
1065 ptr->paid = TRUE;
1067 for (ptr = hand; ptr != NIL; ptr = ptr->next) {
1068 ptr->visible = TRUE;
1069 ptr->paid = TRUE;
1071 showstat();
1072 move(stockrow + 1, sidecol);
1073 printw(" ");
1074 move(talonrow - 2, sidecol);
1075 printw(" ");
1076 move(talonrow - 1, sidecol);
1077 printw(" ");
1078 move(talonrow, sidecol);
1079 printw(" ");
1080 move(talonrow + 1, sidecol);
1081 printw(" ");
1082 for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
1083 move(row, stockcol - 1);
1084 printw("| |");
1085 printcard(stockcol, row, ptr);
1087 if (stock == NIL) {
1088 move(row, stockcol - 1);
1089 printw("| |");
1090 row++;
1092 move(handstatrow, handstatcol - 7);
1093 printw(" ");
1094 move(row, stockcol - 1);
1095 printw("=---=");
1096 if ( cardsoff == 52 )
1097 getcmd(moverow, movecol, "Hit return to exit");
1101 * procedure to update the betting values
1103 static void
1104 updatebettinginfo(void)
1106 long thiscosts, gamecosts, totalcosts;
1107 double thisreturn, gamereturn, totalreturn;
1108 time_t now;
1109 long dollars;
1111 time(&now);
1112 dollars = (now - acctstart) / secondsperdollar;
1113 if (dollars > 0) {
1114 acctstart += dollars * secondsperdollar;
1115 if (dollars > maxtimecharge)
1116 dollars = maxtimecharge;
1117 this.thinktime += dollars;
1118 game.thinktime += dollars;
1119 total.thinktime += dollars;
1121 thiscosts = this.hand + this.inspection + this.game +
1122 this.runs + this.information + this.thinktime;
1123 gamecosts = game.hand + game.inspection + game.game +
1124 game.runs + game.information + game.thinktime;
1125 totalcosts = total.hand + total.inspection + total.game +
1126 total.runs + total.information + total.thinktime;
1127 this.worth = this.wins - thiscosts;
1128 game.worth = game.wins - gamecosts;
1129 total.worth = total.wins - totalcosts;
1130 thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0;
1131 gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0;
1132 totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0;
1133 if (status != BETTINGBOX)
1134 return;
1135 move(tboxrow + 2, boxcol + 13);
1136 printw("%4d%8d%9d", this.hand, game.hand, total.hand);
1137 move(tboxrow + 3, boxcol + 13);
1138 printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection);
1139 move(tboxrow + 4, boxcol + 13);
1140 printw("%4d%8d%9d", this.game, game.game, total.game);
1141 move(tboxrow + 5, boxcol + 13);
1142 printw("%4d%8d%9d", this.runs, game.runs, total.runs);
1143 move(tboxrow + 6, boxcol + 13);
1144 printw("%4d%8d%9d", this.information, game.information,
1145 total.information);
1146 move(tboxrow + 7, boxcol + 13);
1147 printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime);
1148 move(tboxrow + 8, boxcol + 13);
1149 printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts);
1150 move(tboxrow + 9, boxcol + 13);
1151 printw("%4d%8d%9d", this.wins, game.wins, total.wins);
1152 move(tboxrow + 10, boxcol + 13);
1153 printw("%4d%8d%9d", this.worth, game.worth, total.worth);
1154 move(tboxrow + 11, boxcol + 13);
1155 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn);
1159 * procedure to move a card from the stock or talon to the tableau
1161 static void
1162 simpletableau(struct cardtype **cp, int des)
1164 int origin;
1166 if (notempty(*cp)) {
1167 if (tabok(*cp, des)) {
1168 if (*cp == stock)
1169 origin = stk;
1170 else
1171 origin = tal;
1172 if (tableau[des] == NIL)
1173 bottom[des] = *cp;
1174 transit(cp, &tableau[des]);
1175 length[des]++;
1176 printcard(pilemap[des], length[des], tableau[des]);
1177 timesthru = 0;
1178 if (origin == stk) {
1179 usedstock();
1180 printcard(stockcol, stockrow, stock);
1181 } else {
1182 usedtalon();
1183 printcard(taloncol, talonrow, talon);
1185 } else
1186 destinerror();
1191 * print the tableau
1193 static void
1194 tabprint(int sour, int des)
1196 int dlength, slength, i;
1197 struct cardtype *tempcard;
1199 for (i=tabrow; i<=length[sour]; i++)
1200 removecard(pilemap[sour], i);
1201 dlength = length[des] + 1;
1202 slength = length[sour];
1203 if (slength == tabrow)
1204 printcard(pilemap[des], dlength, tableau[sour]);
1205 else
1206 while (slength != tabrow - 1) {
1207 tempcard = tableau[sour];
1208 for (i=1; i<=slength-tabrow; i++)
1209 tempcard = tempcard->next;
1210 printcard(pilemap[des], dlength, tempcard);
1211 slength--;
1212 dlength++;
1217 * procedure to move from the tableau to the tableau
1219 static void
1220 tabtotab(int sour, int des)
1222 struct cardtype *temp;
1224 if (notempty(tableau[sour])) {
1225 if (tabok(bottom[sour], des)) {
1226 tabprint(sour, des);
1227 temp = bottom[sour];
1228 bottom[sour] = NIL;
1229 if (bottom[des] == NIL)
1230 bottom[des] = temp;
1231 temp->next = tableau[des];
1232 tableau[des] = tableau[sour];
1233 tableau[sour] = NIL;
1234 length[des] = length[des] +
1235 (length[sour] - (tabrow - 1));
1236 length[sour] = tabrow - 1;
1237 timesthru = 0;
1238 } else
1239 destinerror();
1244 * functions to see if the card can go onto the foundation
1246 static bool
1247 rankhigher(struct cardtype *cp, int let)
1249 if (found[let]->rank == King)
1250 if (cp->rank == Ace)
1251 return(TRUE);
1252 else
1253 return(FALSE);
1254 else if (cp->rank - 1 == found[let]->rank)
1255 return(TRUE);
1256 else
1257 return(FALSE);
1261 * function to determine if two cards are the same suit
1263 static bool
1264 samesuit(struct cardtype *cp, int let)
1266 if (cp->suit == found[let]->suit)
1267 return (TRUE);
1268 else
1269 return (FALSE);
1273 * procedure to move a card to the correct foundation pile
1275 static void
1276 movetofound(struct cardtype **cp, int source)
1278 tempbase = 0;
1279 mtfdone = FALSE;
1280 if (notempty(*cp)) {
1281 do {
1282 if (found[tempbase] != NIL)
1283 if (rankhigher(*cp, tempbase)
1284 && samesuit(*cp, tempbase)) {
1285 if (*cp == stock)
1286 mtforigin = stk;
1287 else if (*cp == talon)
1288 mtforigin = tal;
1289 else
1290 mtforigin = tab;
1291 transit(cp, &found[tempbase]);
1292 printcard(pilemap[tempbase],
1293 foundrow, found[tempbase]);
1294 timesthru = 0;
1295 if (mtforigin == stk) {
1296 usedstock();
1297 printcard(stockcol, stockrow,
1298 stock);
1299 } else if (mtforigin == tal) {
1300 usedtalon();
1301 printcard(taloncol, talonrow,
1302 talon);
1303 } else {
1304 removecard(pilemap[source],
1305 length[source]);
1306 length[source]--;
1308 cardsoff++;
1309 if (infullgame) {
1310 this.wins += valuepercardup;
1311 game.wins += valuepercardup;
1312 total.wins += valuepercardup;
1314 mtfdone = TRUE;
1315 } else
1316 tempbase++;
1317 else
1318 tempbase++;
1319 } while ((tempbase != 4) && !mtfdone);
1320 if (!mtfdone)
1321 destinerror();
1326 * procedure to get a command
1328 static void
1329 getcmd(int row, int col, const char *cp)
1331 char cmd[2], ch;
1332 int i;
1334 i = 0;
1335 move(row, col);
1336 printw("%-24s", cp);
1337 col += 1 + strlen(cp);
1338 move(row, col);
1339 refresh();
1340 do {
1341 ch = getch() & 0177;
1342 if (ch >= 'A' && ch <= 'Z')
1343 ch += ('a' - 'A');
1344 if (ch == '\f') {
1345 wrefresh(curscr);
1346 refresh();
1347 } else if (i >= 2 && ch != erasechar() && ch != killchar()) {
1348 if (ch != '\n' && ch != '\r' && ch != ' ')
1349 write(1, "\007", 1);
1350 } else if (ch == erasechar() && i > 0) {
1351 printw("\b \b");
1352 refresh();
1353 i--;
1354 } else if (ch == killchar() && i > 0) {
1355 while (i > 0) {
1356 printw("\b \b");
1357 i--;
1359 refresh();
1360 } else if (ch == '\032') { /* Control-Z */
1361 suspend();
1362 move(row, col + i);
1363 refresh();
1364 } else if (isprint(ch)) {
1365 cmd[i++] = ch;
1366 addch(ch);
1367 refresh();
1369 } while (ch != '\n' && ch != '\r' && ch != ' ');
1370 srcpile = cmd[0];
1371 destpile = cmd[1];
1375 * Suspend the game (shell escape if no process control on system)
1377 static void
1378 suspend(void)
1380 #ifndef SIGTSTP
1381 char *sh;
1382 #endif
1384 updatebettinginfo();
1385 move(21, 0);
1386 refresh();
1387 if (dbfd != -1) {
1388 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1389 write(dbfd, (char *)&total, sizeof(total));
1391 kill(getpid(), SIGTSTP);
1392 raw();
1393 noecho();
1397 * procedure to evaluate and make the specific moves
1399 static void
1400 movecard(void)
1402 int source, dest;
1403 char osrcpile, odestpile;
1405 source = 0;
1406 dest = 0;
1407 done = FALSE;
1408 errmsg = FALSE;
1409 do {
1410 if (talon == NIL && hand != NIL)
1411 movetotalon();
1412 if (cardsoff == 52) {
1413 refresh();
1414 srcpile = 'q';
1415 } else if (!startedgame) {
1416 move(msgrow, msgcol);
1417 errmsg = TRUE;
1418 switch (34 - taloncnt - cinhand) {
1419 default:
1420 errmsg = FALSE;
1421 break;
1422 case 1:
1423 printw("One card used from talon ");
1424 break;
1425 case 2:
1426 printw("Two cards used from talon ");
1427 break;
1428 case 3:
1429 printw(">3< cards used from talon ");
1430 break;
1432 getcmd(moverow, movecol, "Move:");
1433 } else
1434 getcmd(moverow, movecol, "Move:");
1435 clearmsg();
1436 if (srcpile >= '1' && srcpile <= '4')
1437 source = (int) (srcpile - '1');
1438 if (destpile >= '1' && destpile <= '4')
1439 dest = (int) (destpile - '1');
1440 if (!startedgame &&
1441 (srcpile == 't' || srcpile == 's' || srcpile == 'h' ||
1442 srcpile == '1' || srcpile == '2' || srcpile == '3' ||
1443 srcpile == '4')) {
1444 startedgame = TRUE;
1445 osrcpile = srcpile;
1446 odestpile = destpile;
1447 if (status != BETTINGBOX)
1448 srcpile = 'y';
1449 else do {
1450 getcmd(moverow, movecol, "Inspect game?");
1451 } while (srcpile != 'y' && srcpile != 'n');
1452 if (srcpile == 'n') {
1453 srcpile = 'q';
1454 } else {
1455 this.inspection += costofinspection;
1456 game.inspection += costofinspection;
1457 total.inspection += costofinspection;
1458 srcpile = osrcpile;
1459 destpile = odestpile;
1462 switch (srcpile) {
1463 case 't':
1464 if (destpile == 'f' || destpile == 'F')
1465 movetofound(&talon, source);
1466 else if (destpile >= '1' && destpile <= '4')
1467 simpletableau(&talon, dest);
1468 else
1469 dumberror();
1470 break;
1471 case 's':
1472 if (destpile == 'f' || destpile == 'F')
1473 movetofound(&stock, source);
1474 else if (destpile >= '1' && destpile <= '4')
1475 simpletableau(&stock, dest);
1476 else dumberror();
1477 break;
1478 case 'h':
1479 if (destpile != 't' && destpile != 'T') {
1480 dumberror();
1481 break;
1483 if (infullgame) {
1484 movetotalon();
1485 break;
1487 if (status == BETTINGBOX) {
1488 do {
1489 getcmd(moverow, movecol,
1490 "Buy game?");
1491 } while (srcpile != 'y' &&
1492 srcpile != 'n');
1493 if (srcpile == 'n') {
1494 showcards();
1495 done = TRUE;
1496 break;
1499 infullgame = TRUE;
1500 this.wins += valuepercardup * cardsoff;
1501 game.wins += valuepercardup * cardsoff;
1502 total.wins += valuepercardup * cardsoff;
1503 this.game += costofgame;
1504 game.game += costofgame;
1505 total.game += costofgame;
1506 movetotalon();
1507 break;
1508 case 'q':
1509 showcards();
1510 done = TRUE;
1511 break;
1512 case 'b':
1513 printtopbettingbox();
1514 printbottombettingbox();
1515 status = BETTINGBOX;
1516 break;
1517 case 'x':
1518 clearabovemovebox();
1519 clearbelowmovebox();
1520 status = NOBOX;
1521 break;
1522 case 'i':
1523 printtopinstructions();
1524 printbottominstructions();
1525 status = INSTRUCTIONBOX;
1526 break;
1527 case 'c':
1528 Cflag = !Cflag;
1529 if (Cflag)
1530 showstat();
1531 else
1532 clearstat();
1533 break;
1534 case '1': case '2': case '3': case '4':
1535 if (destpile == 'f' || destpile == 'F')
1536 movetofound(&tableau[source], source);
1537 else if (destpile >= '1' && destpile <= '4')
1538 tabtotab(source, dest);
1539 else dumberror();
1540 break;
1541 default:
1542 dumberror();
1544 fndbase(&stock, stockcol, stockrow);
1545 fndbase(&talon, taloncol, talonrow);
1546 updatebettinginfo();
1547 } while (!done);
1550 const char *const basicinstructions[] = {
1551 "Here are brief instuctions to the game of Canfield:\n\n",
1552 " If you have never played solitaire before, it is recom-\n",
1553 "mended that you consult a solitaire instruction book. In\n",
1554 "Canfield, tableau cards may be built on each other downward\n",
1555 "in alternate colors. An entire pile must be moved as a unit\n",
1556 "in building. Top cards of the piles are available to be able\n",
1557 "to be played on foundations, but never into empty spaces.\n\n",
1558 " Spaces must be filled from the stock. The top card of\n",
1559 "the stock also is available to be played on foundations or\n",
1560 "built on tableau piles. After the stock is exhausted, ta-\n",
1561 "bleau spaces may be filled from the talon and the player may\n",
1562 "keep them open until he wishes to use them.\n\n",
1563 " Cards are dealt from the hand to the talon by threes\n",
1564 "and this repeats until there are no more cards in the hand\n",
1565 "or the player quits. To have cards dealt onto the talon the\n",
1566 "player types 'ht' for his move. Foundation base cards are\n",
1567 "also automatically moved to the foundation when they become\n",
1568 "available.\n\n",
1569 "push any key when you are finished: ",
1570 0 };
1572 const char *const bettinginstructions[] = {
1573 " The rules for betting are somewhat less strict than\n",
1574 "those used in the official version of the game. The initial\n",
1575 "deal costs $13. You may quit at this point or inspect the\n",
1576 "game. Inspection costs $13 and allows you to make as many\n",
1577 "moves as is possible without moving any cards from your hand\n",
1578 "to the talon. (the initial deal places three cards on the\n",
1579 "talon; if all these cards are used, three more are made\n",
1580 "available) Finally, if the game seems interesting, you must\n",
1581 "pay the final installment of $26. At this point you are\n",
1582 "credited at the rate of $5 for each card on the foundation;\n",
1583 "as the game progresses you are credited with $5 for each\n",
1584 "card that is moved to the foundation. Each run through the\n",
1585 "hand after the first costs $5. The card counting feature\n",
1586 "costs $1 for each unknown card that is identified. If the\n",
1587 "information is toggled on, you are only charged for cards\n",
1588 "that became visible since it was last turned on. Thus the\n",
1589 "maximum cost of information is $34. Playing time is charged\n",
1590 "at a rate of $1 per minute.\n\n",
1591 "push any key when you are finished: ",
1592 0 };
1595 * procedure to printout instructions
1597 static void
1598 instruct(void)
1600 const char *const *cp;
1602 move(originrow, origincol);
1603 printw("This is the game of solitaire called Canfield. Do\n");
1604 printw("you want instructions for the game?");
1605 do {
1606 getcmd(originrow + 3, origincol, "y or n?");
1607 } while (srcpile != 'y' && srcpile != 'n');
1608 if (srcpile == 'n')
1609 return;
1610 clear();
1611 for (cp = basicinstructions; *cp != 0; cp++)
1612 printw(*cp);
1613 refresh();
1614 getch();
1615 clear();
1616 move(originrow, origincol);
1617 printw("Do you want instructions for betting?");
1618 do {
1619 getcmd(originrow + 2, origincol, "y or n?");
1620 } while (srcpile != 'y' && srcpile != 'n');
1621 if (srcpile == 'n')
1622 return;
1623 clear();
1624 for (cp = bettinginstructions; *cp != 0; cp++)
1625 printw(*cp);
1626 refresh();
1627 getch();
1631 * procedure to initialize the game
1633 static void
1634 initall(void)
1636 int i;
1638 if (dbfd < 0)
1639 return;
1640 srandomdev();
1641 time(&acctstart);
1642 initdeck(deck);
1643 uid = getuid();
1645 i = lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1646 if (i < 0) {
1647 close(dbfd);
1648 dbfd = -1;
1649 return;
1651 i = read(dbfd, (char *)&total, sizeof(total));
1652 if (i < 0) {
1653 close(dbfd);
1654 dbfd = -1;
1655 return;
1660 * procedure to end the game
1662 static bool
1663 finish(void)
1665 int row, col;
1667 if (cardsoff == 52) {
1668 getcmd(moverow, movecol, "Hit return to exit");
1669 clear();
1670 refresh();
1671 move(originrow, origincol);
1672 printw("CONGRATULATIONS!\n");
1673 printw("You won the game. That is a feat to be proud of.\n");
1674 row = originrow + 5;
1675 col = origincol;
1676 } else {
1677 move(msgrow, msgcol);
1678 printw("You got %d card", cardsoff);
1679 if (cardsoff > 1)
1680 printw("s");
1681 printw(" off ");
1682 move(msgrow, msgcol);
1683 row = moverow;
1684 col = movecol;
1686 do {
1687 getcmd(row, col, "Play again (y or n)?");
1688 } while (srcpile != 'y' && srcpile != 'n');
1689 errmsg = TRUE;
1690 clearmsg();
1691 if (srcpile == 'y')
1692 return (FALSE);
1693 else
1694 return (TRUE);
1698 * procedure to clean up and exit
1700 static void
1701 cleanup(int sig __unused)
1704 total.thinktime += 1;
1705 status = NOBOX;
1706 updatebettinginfo();
1707 if (dbfd != -1) {
1708 lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1709 write(dbfd, (char *)&total, sizeof(total));
1710 close(dbfd);
1712 clear();
1713 move(22,0);
1714 refresh();
1715 endwin();
1716 exit(0);
1717 /* NOTREACHED */
1721 * Field an interrupt.
1723 static void
1724 askquit(int sig __unused)
1726 move(msgrow, msgcol);
1727 printw("Really wish to quit? ");
1728 do {
1729 getcmd(moverow, movecol, "y or n?");
1730 } while (srcpile != 'y' && srcpile != 'n');
1731 clearmsg();
1732 if (srcpile == 'y')
1733 cleanup(0);
1734 signal(SIGINT, askquit);
1738 * Can you tell that this used to be a Pascal program?
1741 main(void)
1743 dbfd = open(_PATH_SCORE, O_RDWR);
1745 /* revoke */
1746 setgid(getgid());
1748 #ifdef MAXLOAD
1749 double vec[3];
1751 loadav(vec);
1752 if (vec[2] >= MAXLOAD) {
1753 puts("The system load is too high. Try again later.");
1754 exit(0);
1756 #endif
1757 signal(SIGINT, askquit);
1758 signal(SIGHUP, cleanup);
1759 signal(SIGTERM, cleanup);
1760 initscr();
1761 raw();
1762 noecho();
1763 initall();
1764 instruct();
1765 makeboard();
1766 for (;;) {
1767 startgame();
1768 movecard();
1769 if (finish())
1770 break;
1771 if (cardsoff == 52)
1772 makeboard();
1773 else
1774 cleanupboard();
1776 cleanup(0);
1777 /* NOTREACHED */
1778 return (EXIT_FAILURE);