games - misc - clean up compiler warnings
[dragonfly.git] / games / canfield / canfield / canfield.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
1de703da
MD
32 *
33 * @(#) Copyright (c) 1980, 1993 The Regents of the University of California. All rights reserved.
34 * @(#)canfield.c 8.1 (Berkeley) 5/31/93
35 * $FreeBSD: src/games/canfield/canfield/canfield.c,v 1.11 1999/12/12 07:25:13 billf Exp $
d058a8bb 36 * $DragonFly: src/games/canfield/canfield/canfield.c,v 1.4 2005/11/19 09:50:30 swildner Exp $
984263bc
MD
37 */
38
984263bc
MD
39/*
40 * The canfield program
41 *
42 * Authors:
43 * Originally written: Steve Levine
44 * Converted to use curses and debugged: Steve Feldman
45 * Card counting: Kirk McKusick and Mikey Olson
46 * User interface cleanups: Eric Allman and Kirk McKusick
47 * Betting by Kirk McKusick
48 */
49
50#include <sys/types.h>
51
52#include <curses.h>
53#include <ctype.h>
54#include <signal.h>
984263bc
MD
55#include <unistd.h>
56#include <stdlib.h>
57#include <string.h>
58#include <fcntl.h>
235099c3 59#include <time.h>
984263bc
MD
60
61#include "pathnames.h"
62
63#define decksize 52
64#define originrow 0
65#define origincol 0
66#define basecol 1
67#define boxcol 42
68#define tboxrow 2
69#define bboxrow 17
70#define movecol 43
71#define moverow 16
72#define msgcol 43
73#define msgrow 15
74#define titlecol 30
75#define titlerow 0
76#define sidecol 1
77#define ottlrow 6
78#define foundcol 11
79#define foundrow 3
80#define stockcol 2
81#define stockrow 8
82#define fttlcol 10
83#define fttlrow 1
84#define taloncol 2
85#define talonrow 13
86#define tabrow 8
87#define ctoprow 21
88#define cbotrow 23
89#define cinitcol 14
90#define cheightcol 1
91#define cwidthcol 4
92#define handstatrow 21
93#define handstatcol 7
94#define talonstatrow 22
95#define talonstatcol 7
96#define stockstatrow 23
97#define stockstatcol 7
98#define Ace 1
99#define Jack 11
100#define Queen 12
101#define King 13
102#define atabcol 11
103#define btabcol 18
104#define ctabcol 25
105#define dtabcol 32
106
107#define spades 's'
108#define clubs 'c'
109#define hearts 'h'
110#define diamonds 'd'
111#define black 'b'
112#define red 'r'
113
114#define stk 1
115#define tal 2
116#define tab 3
117#define INCRHAND(row, col) {\
118 row -= cheightcol;\
119 if (row < ctoprow) {\
120 row = cbotrow;\
121 col += cwidthcol;\
122 }\
123}
124#define DECRHAND(row, col) {\
125 row += cheightcol;\
126 if (row > cbotrow) {\
127 row = ctoprow;\
128 col -= cwidthcol;\
129 }\
130}
131
132
133struct cardtype {
134 char suit;
135 char color;
136 bool visible;
137 bool paid;
138 int rank;
139 struct cardtype *next;
140};
141
142#define NIL ((struct cardtype *) -1)
143
144struct cardtype *deck[decksize];
145struct cardtype cards[decksize];
146struct cardtype *bottom[4], *found[4], *tableau[4];
147struct cardtype *talon, *hand, *stock, *basecard;
148int length[4];
149int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru;
150char suitmap[4] = {spades, clubs, hearts, diamonds};
151char colormap[4] = {black, black, red, red};
152char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol};
153char srcpile, destpile;
154int mtforigin, tempbase;
155int coldcol, cnewcol, coldrow, cnewrow;
156bool errmsg, done;
157bool mtfdone, Cflag = FALSE;
158#define INSTRUCTIONBOX 1
159#define BETTINGBOX 2
160#define NOBOX 3
161int status = INSTRUCTIONBOX;
162int uid;
163
164/*
165 * Basic betting costs
166 */
167#define costofhand 13
168#define costofinspection 13
169#define costofgame 26
170#define costofrunthroughhand 5
171#define costofinformation 1
172#define secondsperdollar 60
173#define maxtimecharge 3
174#define valuepercardup 5
175/*
176 * Variables associated with betting
177 */
178struct betinfo {
179 long hand; /* cost of dealing hand */
180 long inspection; /* cost of inspecting hand */
181 long game; /* cost of buying game */
182 long runs; /* cost of running through hands */
183 long information; /* cost of information */
184 long thinktime; /* cost of thinking time */
185 long wins; /* total winnings */
186 long worth; /* net worth after costs */
187};
188struct betinfo this, game, total;
189bool startedgame = FALSE, infullgame = FALSE;
190time_t acctstart;
191int dbfd = -1;
192
d058a8bb
SW
193static void askquit(int);
194static void cleanup(int);
195static void cleanupboard(void);
196static void clearabovemovebox(void);
197static void clearbelowmovebox(void);
198static void clearmsg(void);
199static void clearstat(void);
200static void destinerror(void);
201static bool diffcolor(struct cardtype *, struct cardtype *);
202static void dumberror(void);
203static bool finish(void);
204static void fndbase(struct cardtype **, int, int);
205static void getcmd(int, int, const char *);
206static void initall(void);
207static void initdeck(struct cardtype **);
208static void initgame(void);
209static void instruct(void);
210static void makeboard(void);
211static void movebox(void);
212static void movecard(void);
213static void movetofound(struct cardtype **, int);
214static void movetotalon(void);
215static bool notempty(struct cardtype *);
216static void printbottombettingbox(void);
217static void printbottominstructions(void);
218static void printcard(int, int, struct cardtype *);
219static void printrank(int, int, struct cardtype *, bool);
220static void printtopbettingbox(void);
221static void printtopinstructions(void);
222static bool rankhigher(struct cardtype *, int);
223static bool ranklower(struct cardtype *, struct cardtype *);
224static void removecard(int, int);
225static bool samesuit(struct cardtype *, int);
226static void showcards(void);
227static void showstat(void);
228static void shuffle(struct cardtype **);
229static void simpletableau(struct cardtype **, int);
230static void startgame(void);
231static void suspend(void);
232static bool tabok(struct cardtype *, int);
233static void tabprint(int, int);
234static void tabtotab(int, int);
235static void transit(struct cardtype **, struct cardtype **);
236static void updatebettinginfo(void);
237static void usedstock(void);
238static void usedtalon(void);
984263bc
MD
239
240/*
241 * The following procedures print the board onto the screen using the
242 * addressible cursor. The end of these procedures will also be
243 * separated from the rest of the program.
244 *
245 * procedure to set the move command box
246 */
d058a8bb
SW
247static void
248movebox(void)
984263bc
MD
249{
250 switch (status) {
251 case BETTINGBOX:
252 printtopbettingbox();
253 break;
254 case NOBOX:
255 clearabovemovebox();
256 break;
257 case INSTRUCTIONBOX:
258 printtopinstructions();
259 break;
260 }
261 move(moverow, boxcol);
262 printw("| |");
263 move(msgrow, boxcol);
264 printw("| |");
265 switch (status) {
266 case BETTINGBOX:
267 printbottombettingbox();
268 break;
269 case NOBOX:
270 clearbelowmovebox();
271 break;
272 case INSTRUCTIONBOX:
273 printbottominstructions();
274 break;
275 }
276 refresh();
277}
278
279/*
280 * print directions above move box
281 */
d058a8bb
SW
282static void
283printtopinstructions(void)
984263bc
MD
284{
285 move(tboxrow, boxcol);
286 printw("*----------------------------------*");
287 move(tboxrow + 1, boxcol);
288 printw("| MOVES |");
289 move(tboxrow + 2, boxcol);
290 printw("|s# = stock to tableau |");
291 move(tboxrow + 3, boxcol);
292 printw("|sf = stock to foundation |");
293 move(tboxrow + 4, boxcol);
294 printw("|t# = talon to tableau |");
295 move(tboxrow + 5, boxcol);
296 printw("|tf = talon to foundation |");
297 move(tboxrow + 6, boxcol);
298 printw("|## = tableau to tableau |");
299 move(tboxrow + 7, boxcol);
300 printw("|#f = tableau to foundation |");
301 move(tboxrow + 8, boxcol);
302 printw("|ht = hand to talon |");
303 move(tboxrow + 9, boxcol);
304 printw("|c = toggle card counting |");
305 move(tboxrow + 10, boxcol);
306 printw("|b = present betting information |");
307 move(tboxrow + 11, boxcol);
308 printw("|q = quit to end the game |");
309 move(tboxrow + 12, boxcol);
310 printw("|==================================|");
311}
312
313/*
314 * Print the betting box.
315 */
d058a8bb
SW
316static void
317printtopbettingbox(void)
984263bc
MD
318{
319
320 move(tboxrow, boxcol);
321 printw("*----------------------------------*");
322 move(tboxrow + 1, boxcol);
323 printw("|Costs Hand Game Total |");
324 move(tboxrow + 2, boxcol);
325 printw("| Hands |");
326 move(tboxrow + 3, boxcol);
327 printw("| Inspections |");
328 move(tboxrow + 4, boxcol);
329 printw("| Games |");
330 move(tboxrow + 5, boxcol);
331 printw("| Runs |");
332 move(tboxrow + 6, boxcol);
333 printw("| Information |");
334 move(tboxrow + 7, boxcol);
335 printw("| Think time |");
336 move(tboxrow + 8, boxcol);
337 printw("|Total Costs |");
338 move(tboxrow + 9, boxcol);
339 printw("|Winnings |");
340 move(tboxrow + 10, boxcol);
341 printw("|Net Worth |");
342 move(tboxrow + 11, boxcol);
343 printw("|Return |");
344 move(tboxrow + 12, boxcol);
345 printw("|==================================|");
346}
347
348/*
349 * clear info above move box
350 */
d058a8bb
SW
351static void
352clearabovemovebox(void)
984263bc
MD
353{
354 int i;
355
356 for (i = 0; i <= 11; i++) {
357 move(tboxrow + i, boxcol);
358 printw(" ");
359 }
360 move(tboxrow + 12, boxcol);
361 printw("*----------------------------------*");
362}
363
364/*
365 * print instructions below move box
366 */
d058a8bb
SW
367static void
368printbottominstructions(void)
984263bc
MD
369{
370 move(bboxrow, boxcol);
371 printw("|Replace # with the number of the |");
372 move(bboxrow + 1, boxcol);
373 printw("|tableau you want. |");
374 move(bboxrow + 2, boxcol);
375 printw("*----------------------------------*");
376}
377
378/*
379 * print betting information below move box
380 */
d058a8bb
SW
381static void
382printbottombettingbox(void)
984263bc
MD
383{
384 move(bboxrow, boxcol);
385 printw("|x = toggle information box |");
386 move(bboxrow + 1, boxcol);
387 printw("|i = list playing instructions |");
388 move(bboxrow + 2, boxcol);
389 printw("*----------------------------------*");
390}
391
392/*
393 * clear info below move box
394 */
d058a8bb
SW
395static void
396clearbelowmovebox(void)
984263bc
MD
397{
398 int i;
399
400 move(bboxrow, boxcol);
401 printw("*----------------------------------*");
402 for (i = 1; i <= 2; i++) {
403 move(bboxrow + i, boxcol);
404 printw(" ");
405 }
406}
407
408/*
409 * procedure to put the board on the screen using addressable cursor
410 */
d058a8bb
SW
411static void
412makeboard(void)
984263bc
MD
413{
414 clear();
415 refresh();
416 move(titlerow, titlecol);
417 printw("=-> CANFIELD <-=");
418 move(fttlrow, fttlcol);
419 printw("foundation");
420 move(foundrow - 1, fttlcol);
421 printw("=---= =---= =---= =---=");
422 move(foundrow, fttlcol);
423 printw("| | | | | | | |");
424 move(foundrow + 1, fttlcol);
425 printw("=---= =---= =---= =---=");
426 move(ottlrow, sidecol);
427 printw("stock tableau");
428 move(stockrow - 1, sidecol);
429 printw("=---=");
430 move(stockrow, sidecol);
431 printw("| |");
432 move(stockrow + 1, sidecol);
433 printw("=---=");
434 move(talonrow - 2, sidecol);
435 printw("talon");
436 move(talonrow - 1, sidecol);
437 printw("=---=");
438 move(talonrow, sidecol);
439 printw("| |");
440 move(talonrow + 1, sidecol);
441 printw("=---=");
442 move(tabrow - 1, atabcol);
443 printw("-1- -2- -3- -4-");
444 movebox();
445}
446
447/*
448 * clean up the board for another game
449 */
d058a8bb
SW
450static void
451cleanupboard(void)
984263bc
MD
452{
453 int cnt, row, col;
454 struct cardtype *ptr;
455
456 col = 0;
457 if (Cflag) {
458 clearstat();
459 for(ptr = stock, row = stockrow;
460 ptr != NIL;
461 ptr = ptr->next, row++) {
462 move(row, sidecol);
463 printw(" ");
464 }
465 move(row, sidecol);
466 printw(" ");
467 move(stockrow + 1, sidecol);
468 printw("=---=");
469 move(talonrow - 2, sidecol);
470 printw("talon");
471 move(talonrow - 1, sidecol);
472 printw("=---=");
473 move(talonrow + 1, sidecol);
474 printw("=---=");
475 }
476 move(stockrow, sidecol);
477 printw("| |");
478 move(talonrow, sidecol);
479 printw("| |");
480 move(foundrow, fttlcol);
481 printw("| | | | | | | |");
482 for (cnt = 0; cnt < 4; cnt++) {
483 switch(cnt) {
484 case 0:
485 col = atabcol;
486 break;
487 case 1:
488 col = btabcol;
489 break;
490 case 2:
491 col = ctabcol;
492 break;
493 case 3:
494 col = dtabcol;
495 break;
496 }
497 for(ptr = tableau[cnt], row = tabrow;
498 ptr != NIL;
499 ptr = ptr->next, row++)
500 removecard(col, row);
501 }
502}
503
504/*
505 * procedure to create a deck of cards
506 */
d058a8bb
SW
507static void
508initdeck(struct cardtype **ldeck)
984263bc
MD
509{
510 int i;
511 int scnt;
512 char s;
513 int r;
514
515 i = 0;
516 for (scnt=0; scnt<4; scnt++) {
517 s = suitmap[scnt];
518 for (r=Ace; r<=King; r++) {
d058a8bb 519 ldeck[i] = &cards[i];
984263bc
MD
520 cards[i].rank = r;
521 cards[i].suit = s;
522 cards[i].color = colormap[scnt];
523 cards[i].next = NIL;
524 i++;
525 }
526 }
527}
528
529/*
530 * procedure to shuffle the deck
531 */
d058a8bb
SW
532static void
533shuffle(struct cardtype **ldeck)
984263bc
MD
534{
535 int i,j;
536 struct cardtype *temp;
537
538 for (i=0; i<decksize; i++) {
d058a8bb
SW
539 ldeck[i]->visible = FALSE;
540 ldeck[i]->paid = FALSE;
984263bc
MD
541 }
542 for (i = decksize-1; i>=0; i--) {
543 j = random() % decksize;
544 if (i != j) {
d058a8bb
SW
545 temp = ldeck[i];
546 ldeck[i] = ldeck[j];
547 ldeck[j] = temp;
984263bc
MD
548 }
549 }
550}
551
552/*
553 * procedure to remove the card from the board
554 */
d058a8bb
SW
555static void
556removecard(int a, int b)
984263bc
MD
557{
558 move(b, a);
559 printw(" ");
560}
561
562/*
563 * procedure to print the cards on the board
564 */
d058a8bb
SW
565static void
566printrank(int a, int b, struct cardtype *cp, bool inverse)
984263bc
MD
567{
568 move(b, a);
569 if (cp->rank != 10)
570 addch(' ');
571 if (inverse)
572 standout();
573 switch (cp->rank) {
574 case 2: case 3: case 4: case 5: case 6: case 7:
575 case 8: case 9: case 10:
576 printw("%d", cp->rank);
577 break;
578 case Ace:
579 addch('A');
580 break;
581 case Jack:
582 addch('J');
583 break;
584 case Queen:
585 addch('Q');
586 break;
587 case King:
588 addch('K');
589 }
590 if (inverse)
591 standend();
592}
593
594/*
595 * procedure to print out a card
596 */
d058a8bb
SW
597static void
598printcard(int a, int b, struct cardtype *cp)
984263bc
MD
599{
600 if (cp == NIL)
601 removecard(a, b);
602 else if (cp->visible == FALSE) {
603 move(b, a);
604 printw(" ? ");
605 } else {
606 bool inverse = (cp->suit == 'd' || cp->suit == 'h');
607
608 printrank(a, b, cp, inverse);
609 if (inverse)
610 standout();
611 addch(cp->suit);
612 if (inverse)
613 standend();
614 }
615}
616
617/*
618 * procedure to move the top card from one location to the top
619 * of another location. The pointers always point to the top
620 * of the piles.
621 */
d058a8bb
SW
622static void
623transit(struct cardtype **source, struct cardtype **dest)
984263bc
MD
624{
625 struct cardtype *temp;
626
627 temp = *source;
628 *source = (*source)->next;
629 temp->next = *dest;
630 *dest = temp;
631}
632
633/*
634 * Procedure to set the cards on the foundation base when available.
635 * Note that it is only called on a foundation pile at the beginning of
636 * the game, so the pile will have exactly one card in it.
637 */
d058a8bb
SW
638static void
639fndbase(struct cardtype **cp, int column, int row)
984263bc
MD
640{
641 bool nomore;
642
643 if (*cp != NIL)
644 do {
645 if ((*cp)->rank == basecard->rank) {
646 base++;
647 printcard(pilemap[base], foundrow, *cp);
648 if (*cp == tableau[0])
649 length[0] = length[0] - 1;
650 if (*cp == tableau[1])
651 length[1] = length[1] - 1;
652 if (*cp == tableau[2])
653 length[2] = length[2] - 1;
654 if (*cp == tableau[3])
655 length[3] = length[3] - 1;
656 transit(cp, &found[base]);
657 if (cp == &talon)
658 usedtalon();
659 if (cp == &stock)
660 usedstock();
661 if (*cp != NIL) {
662 printcard(column, row, *cp);
663 nomore = FALSE;
664 } else {
665 removecard(column, row);
666 nomore = TRUE;
667 }
668 cardsoff++;
669 if (infullgame) {
670 this.wins += valuepercardup;
671 game.wins += valuepercardup;
672 total.wins += valuepercardup;
673 }
674 } else
675 nomore = TRUE;
676 } while (nomore == FALSE);
677}
678
679/*
680 * procedure to initialize the things necessary for the game
681 */
d058a8bb
SW
682static void
683initgame(void)
984263bc
MD
684{
685 int i;
686
687 for (i=0; i<18; i++) {
688 deck[i]->visible = TRUE;
689 deck[i]->paid = TRUE;
690 }
691 stockcnt = 13;
692 stock = deck[12];
693 for (i=12; i>=1; i--)
694 deck[i]->next = deck[i - 1];
695 deck[0]->next = NIL;
696 found[0] = deck[13];
697 deck[13]->next = NIL;
698 for (i=1; i<4; i++)
699 found[i] = NIL;
700 basecard = found[0];
701 for (i=14; i<18; i++) {
702 tableau[i - 14] = deck[i];
703 deck[i]->next = NIL;
704 }
705 for (i=0; i<4; i++) {
706 bottom[i] = tableau[i];
707 length[i] = tabrow;
708 }
709 hand = deck[18];
710 for (i=18; i<decksize-1; i++)
711 deck[i]->next = deck[i + 1];
712 deck[decksize-1]->next = NIL;
713 talon = NIL;
714 base = 0;
715 cinhand = 34;
716 taloncnt = 0;
717 timesthru = 0;
718 cardsoff = 1;
719 coldrow = ctoprow;
720 coldcol = cinitcol;
721 cnewrow = ctoprow;
722 cnewcol = cinitcol + cwidthcol;
723}
724
725/*
726 * procedure to print the beginning cards and to start each game
727 */
d058a8bb
SW
728static void
729startgame(void)
984263bc
MD
730{
731 int j;
732
733 shuffle(deck);
734 initgame();
735 this.hand = costofhand;
736 game.hand += costofhand;
737 total.hand += costofhand;
738 this.inspection = 0;
739 this.game = 0;
740 this.runs = 0;
741 this.information = 0;
742 this.wins = 0;
743 this.thinktime = 0;
744 infullgame = FALSE;
745 startedgame = FALSE;
746 printcard(foundcol, foundrow, found[0]);
747 printcard(stockcol, stockrow, stock);
748 printcard(atabcol, tabrow, tableau[0]);
749 printcard(btabcol, tabrow, tableau[1]);
750 printcard(ctabcol, tabrow, tableau[2]);
751 printcard(dtabcol, tabrow, tableau[3]);
752 printcard(taloncol, talonrow, talon);
753 move(foundrow - 2, basecol);
754 printw("Base");
755 move(foundrow - 1, basecol);
756 printw("Rank");
757 printrank(basecol, foundrow, found[0], 0);
758 for (j=0; j<=3; j++)
759 fndbase(&tableau[j], pilemap[j], tabrow);
760 fndbase(&stock, stockcol, stockrow);
761 showstat(); /* show card counting info to cheaters */
762 movetotalon();
763 updatebettinginfo();
764}
765
766/*
767 * procedure to clear the message printed from an error
768 */
d058a8bb
SW
769static void
770clearmsg(void)
984263bc
MD
771{
772 int i;
773
774 if (errmsg == TRUE) {
775 errmsg = FALSE;
776 move(msgrow, msgcol);
777 for (i=0; i<25; i++)
778 addch(' ');
779 refresh();
780 }
781}
782
783/*
784 * procedure to print an error message if the move is not listed
785 */
d058a8bb
SW
786static void
787dumberror(void)
984263bc
MD
788{
789 errmsg = TRUE;
790 move(msgrow, msgcol);
791 printw("Not a proper move ");
792}
793
794/*
795 * procedure to print an error message if the move is not possible
796 */
d058a8bb
SW
797static void
798destinerror(void)
984263bc
MD
799{
800 errmsg = TRUE;
801 move(msgrow, msgcol);
802 printw("Error: Can't move there");
803}
804
805/*
806 * function to see if the source has cards in it
807 */
d058a8bb
SW
808static bool
809notempty(struct cardtype *cp)
984263bc
MD
810{
811 if (cp == NIL) {
812 errmsg = TRUE;
813 move(msgrow, msgcol);
814 printw("Error: no cards to move");
815 return (FALSE);
816 } else
817 return (TRUE);
818}
819
820/*
821 * function to see if the rank of one card is less than another
822 */
d058a8bb
SW
823static bool
824ranklower(struct cardtype *cp1, struct cardtype *cp2)
984263bc
MD
825{
826 if (cp2->rank == Ace)
827 if (cp1->rank == King)
828 return (TRUE);
829 else
830 return (FALSE);
831 else if (cp1->rank + 1 == cp2->rank)
832 return (TRUE);
833 else
834 return (FALSE);
835}
836
837/*
838 * function to check the cardcolor for moving to a tableau
839 */
d058a8bb
SW
840static bool
841diffcolor(struct cardtype *cp1, struct cardtype *cp2)
984263bc
MD
842{
843 if (cp1->color == cp2->color)
844 return (FALSE);
845 else
846 return (TRUE);
847}
848
849/*
850 * function to see if the card can move to the tableau
851 */
d058a8bb
SW
852static bool
853tabok(struct cardtype *cp, int des)
984263bc
MD
854{
855 if ((cp == stock) && (tableau[des] == NIL))
856 return (TRUE);
857 else if (tableau[des] == NIL)
858 if (stock == NIL &&
859 cp != bottom[0] && cp != bottom[1] &&
860 cp != bottom[2] && cp != bottom[3])
861 return (TRUE);
862 else
863 return (FALSE);
864 else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
865 return (TRUE);
866 else
867 return (FALSE);
868}
869
870/*
871 * procedure to turn the cards onto the talon from the deck
872 */
d058a8bb
SW
873static void
874movetotalon(void)
984263bc
MD
875{
876 int i, fin;
877
878 if (cinhand <= 3 && cinhand > 0) {
879 move(msgrow, msgcol);
880 printw("Hand is now empty ");
881 }
882 if (cinhand >= 3)
883 fin = 3;
884 else if (cinhand > 0)
885 fin = cinhand;
886 else if (talon != NIL) {
887 timesthru++;
888 errmsg = TRUE;
889 move(msgrow, msgcol);
890 if (timesthru != 4) {
891 printw("Talon is now the new hand");
892 this.runs += costofrunthroughhand;
893 game.runs += costofrunthroughhand;
894 total.runs += costofrunthroughhand;
895 while (talon != NIL) {
896 transit(&talon, &hand);
897 cinhand++;
898 }
899 if (cinhand >= 3)
900 fin = 3;
901 else
902 fin = cinhand;
903 taloncnt = 0;
904 coldrow = ctoprow;
905 coldcol = cinitcol;
906 cnewrow = ctoprow;
907 cnewcol = cinitcol + cwidthcol;
908 clearstat();
909 showstat();
910 } else {
911 fin = 0;
912 done = TRUE;
913 printw("I believe you have lost");
914 refresh();
915 sleep(5);
916 }
917 } else {
918 errmsg = TRUE;
919 move(msgrow, msgcol);
920 printw("Talon and hand are empty");
921 fin = 0;
922 }
923 for (i=0; i<fin; i++) {
924 transit(&hand, &talon);
925 INCRHAND(cnewrow, cnewcol);
926 INCRHAND(coldrow, coldcol);
927 removecard(cnewcol, cnewrow);
928 if (i == fin - 1)
929 talon->visible = TRUE;
930 if (Cflag) {
931 if (talon->paid == FALSE && talon->visible == TRUE) {
932 this.information += costofinformation;
933 game.information += costofinformation;
934 total.information += costofinformation;
935 talon->paid = TRUE;
936 }
937 printcard(coldcol, coldrow, talon);
938 }
939 }
940 if (fin != 0) {
941 printcard(taloncol, talonrow, talon);
942 cinhand -= fin;
943 taloncnt += fin;
944 if (Cflag) {
945 move(handstatrow, handstatcol);
946 printw("%3d", cinhand);
947 move(talonstatrow, talonstatcol);
948 printw("%3d", taloncnt);
949 }
950 fndbase(&talon, taloncol, talonrow);
951 }
952}
953
954
955/*
956 * procedure to print card counting info on screen
957 */
d058a8bb
SW
958static void
959showstat(void)
984263bc
MD
960{
961 int row, col;
962 struct cardtype *ptr;
963
964 if (!Cflag)
965 return;
966 move(talonstatrow, talonstatcol - 7);
967 printw("Talon: %3d", taloncnt);
968 move(handstatrow, handstatcol - 7);
969 printw("Hand: %3d", cinhand);
970 move(stockstatrow, stockstatcol - 7);
971 printw("Stock: %3d", stockcnt);
972 for ( row = coldrow, col = coldcol, ptr = talon;
973 ptr != NIL;
974 ptr = ptr->next ) {
975 if (ptr->paid == FALSE && ptr->visible == TRUE) {
976 ptr->paid = TRUE;
977 this.information += costofinformation;
978 game.information += costofinformation;
979 total.information += costofinformation;
980 }
981 printcard(col, row, ptr);
982 DECRHAND(row, col);
983 }
984 for ( row = cnewrow, col = cnewcol, ptr = hand;
985 ptr != NIL;
986 ptr = ptr->next ) {
987 if (ptr->paid == FALSE && ptr->visible == TRUE) {
988 ptr->paid = TRUE;
989 this.information += costofinformation;
990 game.information += costofinformation;
991 total.information += costofinformation;
992 }
993 INCRHAND(row, col);
994 printcard(col, row, ptr);
995 }
996}
997
998/*
999 * procedure to clear card counting info from screen
1000 */
d058a8bb
SW
1001static void
1002clearstat(void)
984263bc
MD
1003{
1004 int row;
1005
1006 move(talonstatrow, talonstatcol - 7);
1007 printw(" ");
1008 move(handstatrow, handstatcol - 7);
1009 printw(" ");
1010 move(stockstatrow, stockstatcol - 7);
1011 printw(" ");
1012 for ( row = ctoprow ; row <= cbotrow ; row++ ) {
1013 move(row, cinitcol);
1014 printw("%56s", " ");
1015 }
1016}
1017
1018/*
1019 * procedure to update card counting base
1020 */
d058a8bb
SW
1021static void
1022usedtalon(void)
984263bc
MD
1023{
1024 removecard(coldcol, coldrow);
1025 DECRHAND(coldrow, coldcol);
1026 if (talon != NIL && (talon->visible == FALSE)) {
1027 talon->visible = TRUE;
1028 if (Cflag) {
1029 this.information += costofinformation;
1030 game.information += costofinformation;
1031 total.information += costofinformation;
1032 talon->paid = TRUE;
1033 printcard(coldcol, coldrow, talon);
1034 }
1035 }
1036 taloncnt--;
1037 if (Cflag) {
1038 move(talonstatrow, talonstatcol);
1039 printw("%3d", taloncnt);
1040 }
1041}
1042
1043/*
1044 * procedure to update stock card counting base
1045 */
d058a8bb
SW
1046static void
1047usedstock(void)
984263bc
MD
1048{
1049 stockcnt--;
1050 if (Cflag) {
1051 move(stockstatrow, stockstatcol);
1052 printw("%3d", stockcnt);
1053 }
1054}
1055
1056/*
1057 * let 'em know how they lost!
1058 */
d058a8bb
SW
1059static void
1060showcards(void)
984263bc
MD
1061{
1062 struct cardtype *ptr;
1063 int row;
1064
1065 if (!Cflag || cardsoff == 52)
1066 return;
1067 for (ptr = talon; ptr != NIL; ptr = ptr->next) {
1068 ptr->visible = TRUE;
1069 ptr->paid = TRUE;
1070 }
1071 for (ptr = hand; ptr != NIL; ptr = ptr->next) {
1072 ptr->visible = TRUE;
1073 ptr->paid = TRUE;
1074 }
1075 showstat();
1076 move(stockrow + 1, sidecol);
1077 printw(" ");
1078 move(talonrow - 2, sidecol);
1079 printw(" ");
1080 move(talonrow - 1, sidecol);
1081 printw(" ");
1082 move(talonrow, sidecol);
1083 printw(" ");
1084 move(talonrow + 1, sidecol);
1085 printw(" ");
1086 for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
1087 move(row, stockcol - 1);
1088 printw("| |");
1089 printcard(stockcol, row, ptr);
1090 }
1091 if (stock == NIL) {
1092 move(row, stockcol - 1);
1093 printw("| |");
1094 row++;
1095 }
1096 move(handstatrow, handstatcol - 7);
1097 printw(" ");
1098 move(row, stockcol - 1);
1099 printw("=---=");
1100 if ( cardsoff == 52 )
1101 getcmd(moverow, movecol, "Hit return to exit");
1102}
1103
1104/*
1105 * procedure to update the betting values
1106 */
d058a8bb
SW
1107static void
1108updatebettinginfo(void)
984263bc
MD
1109{
1110 long thiscosts, gamecosts, totalcosts;
1111 double thisreturn, gamereturn, totalreturn;
1112 time_t now;
1113 long dollars;
1114
1115 time(&now);
1116 dollars = (now - acctstart) / secondsperdollar;
1117 if (dollars > 0) {
1118 acctstart += dollars * secondsperdollar;
1119 if (dollars > maxtimecharge)
1120 dollars = maxtimecharge;
1121 this.thinktime += dollars;
1122 game.thinktime += dollars;
1123 total.thinktime += dollars;
1124 }
1125 thiscosts = this.hand + this.inspection + this.game +
1126 this.runs + this.information + this.thinktime;
1127 gamecosts = game.hand + game.inspection + game.game +
1128 game.runs + game.information + game.thinktime;
1129 totalcosts = total.hand + total.inspection + total.game +
1130 total.runs + total.information + total.thinktime;
1131 this.worth = this.wins - thiscosts;
1132 game.worth = game.wins - gamecosts;
1133 total.worth = total.wins - totalcosts;
1134 thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0;
1135 gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0;
1136 totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0;
1137 if (status != BETTINGBOX)
1138 return;
1139 move(tboxrow + 2, boxcol + 13);
1140 printw("%4d%8d%9d", this.hand, game.hand, total.hand);
1141 move(tboxrow + 3, boxcol + 13);
1142 printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection);
1143 move(tboxrow + 4, boxcol + 13);
1144 printw("%4d%8d%9d", this.game, game.game, total.game);
1145 move(tboxrow + 5, boxcol + 13);
1146 printw("%4d%8d%9d", this.runs, game.runs, total.runs);
1147 move(tboxrow + 6, boxcol + 13);
1148 printw("%4d%8d%9d", this.information, game.information,
1149 total.information);
1150 move(tboxrow + 7, boxcol + 13);
1151 printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime);
1152 move(tboxrow + 8, boxcol + 13);
1153 printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts);
1154 move(tboxrow + 9, boxcol + 13);
1155 printw("%4d%8d%9d", this.wins, game.wins, total.wins);
1156 move(tboxrow + 10, boxcol + 13);
1157 printw("%4d%8d%9d", this.worth, game.worth, total.worth);
1158 move(tboxrow + 11, boxcol + 13);
1159 printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn);
1160}
1161
1162/*
1163 * procedure to move a card from the stock or talon to the tableau
1164 */
d058a8bb
SW
1165static void
1166simpletableau(struct cardtype **cp, int des)
984263bc
MD
1167{
1168 int origin;
1169
1170 if (notempty(*cp)) {
1171 if (tabok(*cp, des)) {
1172 if (*cp == stock)
1173 origin = stk;
1174 else
1175 origin = tal;
1176 if (tableau[des] == NIL)
1177 bottom[des] = *cp;
1178 transit(cp, &tableau[des]);
1179 length[des]++;
1180 printcard(pilemap[des], length[des], tableau[des]);
1181 timesthru = 0;
1182 if (origin == stk) {
1183 usedstock();
1184 printcard(stockcol, stockrow, stock);
1185 } else {
1186 usedtalon();
1187 printcard(taloncol, talonrow, talon);
1188 }
1189 } else
1190 destinerror();
1191 }
1192}
1193
1194/*
1195 * print the tableau
1196 */
d058a8bb
SW
1197static void
1198tabprint(int sour, int des)
984263bc
MD
1199{
1200 int dlength, slength, i;
1201 struct cardtype *tempcard;
1202
1203 for (i=tabrow; i<=length[sour]; i++)
1204 removecard(pilemap[sour], i);
1205 dlength = length[des] + 1;
1206 slength = length[sour];
1207 if (slength == tabrow)
1208 printcard(pilemap[des], dlength, tableau[sour]);
1209 else
1210 while (slength != tabrow - 1) {
1211 tempcard = tableau[sour];
1212 for (i=1; i<=slength-tabrow; i++)
1213 tempcard = tempcard->next;
1214 printcard(pilemap[des], dlength, tempcard);
1215 slength--;
1216 dlength++;
1217 }
1218}
1219
1220/*
1221 * procedure to move from the tableau to the tableau
1222 */
d058a8bb
SW
1223static void
1224tabtotab(int sour, int des)
984263bc
MD
1225{
1226 struct cardtype *temp;
1227
1228 if (notempty(tableau[sour])) {
1229 if (tabok(bottom[sour], des)) {
1230 tabprint(sour, des);
1231 temp = bottom[sour];
1232 bottom[sour] = NIL;
1233 if (bottom[des] == NIL)
1234 bottom[des] = temp;
1235 temp->next = tableau[des];
1236 tableau[des] = tableau[sour];
1237 tableau[sour] = NIL;
1238 length[des] = length[des] + (length[sour] - (tabrow - 1));
1239 length[sour] = tabrow - 1;
1240 timesthru = 0;
1241 } else
1242 destinerror();
1243 }
1244}
1245
1246/*
1247 * functions to see if the card can go onto the foundation
1248 */
d058a8bb
SW
1249static bool
1250rankhigher(struct cardtype *cp, int let)
984263bc
MD
1251{
1252 if (found[let]->rank == King)
1253 if (cp->rank == Ace)
1254 return(TRUE);
1255 else
1256 return(FALSE);
1257 else if (cp->rank - 1 == found[let]->rank)
1258 return(TRUE);
1259 else
1260 return(FALSE);
1261}
1262
1263/*
1264 * function to determine if two cards are the same suit
1265 */
d058a8bb
SW
1266static bool
1267samesuit(struct cardtype *cp, int let)
984263bc
MD
1268{
1269 if (cp->suit == found[let]->suit)
1270 return (TRUE);
1271 else
1272 return (FALSE);
1273}
1274
1275/*
1276 * procedure to move a card to the correct foundation pile
1277 */
d058a8bb
SW
1278static void
1279movetofound(struct cardtype **cp, int source)
984263bc
MD
1280{
1281 tempbase = 0;
1282 mtfdone = FALSE;
1283 if (notempty(*cp)) {
1284 do {
1285 if (found[tempbase] != NIL)
1286 if (rankhigher(*cp, tempbase)
1287 && samesuit(*cp, tempbase)) {
1288 if (*cp == stock)
1289 mtforigin = stk;
1290 else if (*cp == talon)
1291 mtforigin = tal;
1292 else
1293 mtforigin = tab;
1294 transit(cp, &found[tempbase]);
1295 printcard(pilemap[tempbase],
1296 foundrow, found[tempbase]);
1297 timesthru = 0;
1298 if (mtforigin == stk) {
1299 usedstock();
1300 printcard(stockcol, stockrow, stock);
1301 } else if (mtforigin == tal) {
1302 usedtalon();
1303 printcard(taloncol, talonrow, talon);
1304 } else {
1305 removecard(pilemap[source], length[source]);
1306 length[source]--;
1307 }
1308 cardsoff++;
1309 if (infullgame) {
1310 this.wins += valuepercardup;
1311 game.wins += valuepercardup;
1312 total.wins += valuepercardup;
1313 }
1314 mtfdone = TRUE;
1315 } else
1316 tempbase++;
1317 else
1318 tempbase++;
1319 } while ((tempbase != 4) && !mtfdone);
1320 if (!mtfdone)
1321 destinerror();
1322 }
1323}
1324
1325/*
1326 * procedure to get a command
1327 */
d058a8bb
SW
1328static void
1329getcmd(int row, int col, const char *cp)
984263bc
MD
1330{
1331 char cmd[2], ch;
1332 int i;
1333
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--;
1358 }
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();
1368 }
1369 } while (ch != '\n' && ch != '\r' && ch != ' ');
1370 srcpile = cmd[0];
1371 destpile = cmd[1];
1372}
1373
1374/*
1375 * Suspend the game (shell escape if no process control on system)
1376 */
d058a8bb
SW
1377static void
1378suspend(void)
984263bc
MD
1379{
1380#ifndef SIGTSTP
1381 char *sh;
1382#endif
1383
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));
1390 }
1391 kill(getpid(), SIGTSTP);
1392 raw();
1393 noecho();
1394}
1395
1396/*
1397 * procedure to evaluate and make the specific moves
1398 */
d058a8bb
SW
1399static void
1400movecard(void)
984263bc
MD
1401{
1402 int source, dest;
1403 char osrcpile, odestpile;
1404
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;
1431 }
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;
1460 }
1461 }
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;
1482 }
1483 if (infullgame) {
1484 movetotalon();
1485 break;
1486 }
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;
1497 }
1498 }
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();
1543 }
1544 fndbase(&stock, stockcol, stockrow);
1545 fndbase(&talon, taloncol, talonrow);
1546 updatebettinginfo();
1547 } while (!done);
1548}
1549
d058a8bb 1550const char *const basicinstructions[] = {
984263bc
MD
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 };
1571
d058a8bb 1572const char *const bettinginstructions[] = {
984263bc
MD
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 };
1593
1594/*
1595 * procedure to printout instructions
1596 */
d058a8bb
SW
1597static void
1598instruct(void)
984263bc 1599{
d058a8bb 1600 const char *const *cp;
984263bc
MD
1601
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();
1628}
1629
1630/*
1631 * procedure to initialize the game
1632 */
d058a8bb
SW
1633static void
1634initall(void)
984263bc
MD
1635{
1636 int i;
1637
1638 if (dbfd < 0)
1639 return;
1640 srandomdev();
1641 time(&acctstart);
1642 initdeck(deck);
1643 uid = getuid();
1644
1645 i = lseek(dbfd, uid * sizeof(struct betinfo), SEEK_SET);
1646 if (i < 0) {
1647 close(dbfd);
1648 dbfd = -1;
1649 return;
1650 }
1651 i = read(dbfd, (char *)&total, sizeof(total));
1652 if (i < 0) {
1653 close(dbfd);
1654 dbfd = -1;
1655 return;
1656 }
1657}
1658
1659/*
1660 * procedure to end the game
1661 */
d058a8bb
SW
1662static bool
1663finish(void)
984263bc
MD
1664{
1665 int row, col;
1666
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;
1685 }
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);
1695}
1696
1697/*
1698 * procedure to clean up and exit
1699 */
d058a8bb
SW
1700static void
1701cleanup(__unused int sig)
984263bc
MD
1702{
1703
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);
1711 }
1712 clear();
1713 move(22,0);
1714 refresh();
1715 endwin();
1716 exit(0);
1717 /* NOTREACHED */
1718}
1719
1720/*
1721 * Field an interrupt.
1722 */
d058a8bb
SW
1723static void
1724askquit(__unused int sig)
984263bc
MD
1725{
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);
1735}
1736
1737/*
1738 * Can you tell that this used to be a Pascal program?
1739 */
1740int
d058a8bb 1741main(void)
984263bc
MD
1742{
1743 dbfd = open(_PATH_SCORE, O_RDWR);
1744
1745 /* revoke */
1746 setgid(getgid());
1747
1748#ifdef MAXLOAD
1749 double vec[3];
1750
1751 loadav(vec);
1752 if (vec[2] >= MAXLOAD) {
1753 puts("The system load is too high. Try again later.");
1754 exit(0);
1755 }
1756#endif
1757 signal(SIGINT, askquit);
1758 signal(SIGHUP, cleanup);
1759 signal(SIGTERM, cleanup);
1760 initscr();
1761 raw();
1762 noecho();
1763 initall();
1764
1765 instruct();
1766 makeboard();
1767 for (;;) {
1768 startgame();
1769 movecard();
1770 if (finish())
1771 break;
1772 if (cardsoff == 52)
1773 makeboard();
1774 else
1775 cleanupboard();
1776 }
1777 cleanup(0);
1778 /* NOTREACHED */
d058a8bb 1779 return (EXIT_FAILURE);
984263bc 1780}