|
|
1.1 root 1: /* Copyright (c) 1982 Regents of the University of California */
2:
3: static char sccsid[] = "@(#)canfield.c 4.1 10/24/82";
4:
5: /*
6: * The canfield program
7: *
8: * Authors:
9: * Originally written: Steve Levine
10: * Converted to use curses and debugged: Steve Feldman
11: * Card counting: Kirk McKusick and Mikey Olson
12: */
13:
14: #include <curses.h>
15: #include <ctype.h>
16: #include <signal.h>
17:
18: #define decksize 52
19: #define originrow 0
20: #define origincol 0
21: #define basecol 1
22: #define boxcol 42
23: #define tboxrow 2
24: #define bboxrow 16
25: #define movecol 43
26: #define moverow 15
27: #define msgcol 43
28: #define msgrow 14
29: #define titlecol 30
30: #define titlerow 0
31: #define sidecol 1
32: #define ottlrow 6
33: #define foundcol 11
34: #define foundrow 3
35: #define stockcol 2
36: #define stockrow 8
37: #define fttlcol 10
38: #define fttlrow 1
39: #define taloncol 2
40: #define talonrow 13
41: #define tabrow 8
42: #define ctoprow 21
43: #define cbotrow 23
44: #define cinitcol 14
45: #define cheightcol 1
46: #define cwidthcol 4
47: #define handstatrow 21
48: #define handstatcol 7
49: #define talonstatrow 22
50: #define talonstatcol 7
51: #define stockstatrow 23
52: #define stockstatcol 7
53: #define Ace 1
54: #define Jack 11
55: #define Queen 12
56: #define King 13
57: #define atabcol 11
58: #define btabcol 18
59: #define ctabcol 25
60: #define dtabcol 32
61:
62: #define spades 's'
63: #define clubs 'c'
64: #define hearts 'h'
65: #define diamonds 'd'
66: #define black 'b'
67: #define red 'r'
68:
69: #define stk 1
70: #define tal 2
71: #define tab 3
72: #define INCRHAND(row, col) {\
73: row -= cheightcol;\
74: if (row < ctoprow) {\
75: row = cbotrow;\
76: col += cwidthcol;\
77: }\
78: }
79: #define DECRHAND(row, col) {\
80: row += cheightcol;\
81: if (row > cbotrow) {\
82: row = ctoprow;\
83: col -= cwidthcol;\
84: }\
85: }
86:
87:
88: struct cardtype {
89: char suit;
90: char color;
91: bool visible;
92: int rank;
93: struct cardtype *next;
94: };
95:
96: #define NIL ((struct cardtype *) -1)
97:
98: struct cardtype *deck[decksize];
99: struct cardtype cards[decksize];
100: struct cardtype *bottom[4], *found[4], *tableau[4];
101: struct cardtype *talon, *hand, *stock, *basecard;
102: int length[4];
103: int cardsoff, base, cinhand, taloncnt, stockcnt, timesthru;
104: char suitmap[4] = {spades, clubs, hearts, diamonds};
105: char colormap[4] = {black, black, red, red};
106: char pilemap[4] = {atabcol, btabcol, ctabcol, dtabcol};
107: char srcpile, destpile;
108: int mtforigin, tempbase;
109: int coldcol, cnewcol, coldrow, cnewrow;
110: bool errmsg, done;
111: bool mtfdone, Cflag = FALSE;
112:
113:
114:
115: /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116: * The following procedures print the board onto the screen using the
117: * addressible cursor. The end of these procedures will also be
118: * separated from the rest of the program.
119: */
120: /* procedure to set the move command box */
121: movebox()
122: {
123: move(tboxrow, boxcol);
124: printw("*--------------------------*");
125: move(tboxrow + 1, boxcol);
126: printw("| MOVES |");
127: move(tboxrow + 2, boxcol);
128: printw("|s# = stock to tableau |");
129: move(tboxrow + 3, boxcol);
130: printw("|sf = stock to foundation |");
131: move(tboxrow + 4, boxcol);
132: printw("|t# = talon to tableau |");
133: move(tboxrow + 5, boxcol);
134: printw("|tf = talon to foundation |");
135: move(tboxrow + 6, boxcol);
136: printw("|## = tableau to tableau |");
137: move(tboxrow + 7, boxcol);
138: printw("|#f = tableau to foundation|");
139: move(tboxrow + 8, boxcol);
140: printw("|ht = hand to talon |");
141: move(tboxrow + 9, boxcol);
142: printw("|c = toggle card counting |");
143: move(tboxrow + 10, boxcol);
144: printw("|q = quit to end the game |");
145: move(tboxrow + 11, boxcol);
146: printw("|==========================|");
147: move(moverow, boxcol);
148: printw("| |");
149: move(msgrow, boxcol);
150: printw("| |");
151: move(bboxrow, boxcol);
152: printw("|Replace the # with the |");
153: move(bboxrow + 1, boxcol);
154: printw("|number of the tableau you |");
155: move(bboxrow + 2, boxcol);
156: printw("|want, 1, 2, 3, or 4. |");
157: move(bboxrow + 3, boxcol);
158: printw("*--------------------------*");
159: refresh();
160: }
161:
162: /* procedure to put the board on the screen using addressable cursor */
163: makeboard()
164: {
165: clear();
166: refresh();
167: move(titlerow, titlecol);
168: printw("=-> CANFIELD <-=");
169: move(fttlrow, fttlcol);
170: printw("foundation");
171: move(foundrow - 1, fttlcol);
172: printw("=---= =---= =---= =---=");
173: move(foundrow, fttlcol);
174: printw("| | | | | | | |");
175: move(foundrow + 1, fttlcol);
176: printw("=---= =---= =---= =---=");
177: move(ottlrow, sidecol);
178: printw("stock tableau");
179: move(stockrow - 1, sidecol);
180: printw("=---=");
181: move(stockrow, sidecol);
182: printw("| |");
183: move(stockrow + 1, sidecol);
184: printw("=---=");
185: move(talonrow - 2, sidecol);
186: printw("talon");
187: move(talonrow - 1, sidecol);
188: printw("=---=");
189: move(talonrow, sidecol);
190: printw("| |");
191: move(talonrow + 1, sidecol);
192: printw("=---=");
193: move(tabrow - 1, atabcol);
194: printw("-1- -2- -3- -4-");
195: movebox();
196: }
197: /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
198:
199: /* clean up the board for another game */
200: cleanupboard()
201: {
202: int cnt, row, col;
203: struct cardtype *ptr;
204:
205: if (Cflag) {
206: clearstat();
207: for(ptr = stock, row = stockrow;
208: ptr != NIL;
209: ptr = ptr->next, row++) {
210: move(row, sidecol);
211: printw(" ");
212: }
213: move(row, sidecol);
214: printw(" ");
215: move(stockrow + 1, sidecol);
216: printw("=---=");
217: move(talonrow - 2, sidecol);
218: printw("talon");
219: move(talonrow - 1, sidecol);
220: printw("=---=");
221: move(talonrow + 1, sidecol);
222: printw("=---=");
223: }
224: move(stockrow, sidecol);
225: printw("| |");
226: move(talonrow, sidecol);
227: printw("| |");
228: move(foundrow, fttlcol);
229: printw("| | | | | | | |");
230: for (cnt = 0; cnt < 4; cnt++) {
231: switch(cnt) {
232: case 0:
233: col = atabcol;
234: break;
235: case 1:
236: col = btabcol;
237: break;
238: case 2:
239: col = ctabcol;
240: break;
241: case 3:
242: col = dtabcol;
243: break;
244: }
245: for(ptr = tableau[cnt], row = tabrow;
246: ptr != NIL;
247: ptr = ptr->next, row++)
248: removecard(col, row);
249: }
250: }
251:
252: /* procedure to create a deck of cards */
253: initdeck(deck)
254: struct cardtype *deck[];
255: {
256: int i;
257: int scnt;
258: char s;
259: int r;
260:
261: i = 0;
262: for (scnt=0; scnt<4; scnt++) {
263: s = suitmap[scnt];
264: for (r=Ace; r<=King; r++) {
265: deck[i] = &cards[i];
266: cards[i].rank = r;
267: cards[i].suit = s;
268: cards[i].color = colormap[scnt];
269: cards[i].next = NIL;
270: i++;
271: }
272: }
273: }
274:
275: /* procedure to shuffle the deck */
276: shuffle(deck)
277: struct cardtype *deck[];
278: {
279: int i,j;
280: struct cardtype *temp;
281:
282: for (i=0; i<decksize; i++)
283: deck[i]->visible = FALSE;
284: for (i = decksize-1; i>=0; i--) {
285: j = rand() % decksize;
286: if (i != j) {
287: temp = deck[i];
288: deck[i] = deck[j];
289: deck[j] = temp;
290: }
291: }
292: }
293:
294: /* procedure to remove the card from the board */
295: removecard(a, b)
296: {
297: move(b, a);
298: printw(" ");
299: }
300:
301: /* procedure to print the cards on the board */
302: printrank(a, b, cp)
303: struct cardtype *cp;
304: {
305: move(b, a);
306: switch (cp->rank) {
307: case 2: case 3: case 4: case 5: case 6: case 7:
308: case 8: case 9: case 10:
309: printw("%2d", cp->rank);
310: break;
311: case Ace:
312: printw(" A");
313: break;
314: case Jack:
315: printw(" J");
316: break;
317: case Queen:
318: printw(" Q");
319: break;
320: case King:
321: printw(" K");
322: }
323: }
324:
325: printcard(a, b, cp)
326: int a,b;
327: struct cardtype *cp;
328: {
329: if (cp == NIL)
330: removecard(a, b);
331: else if (cp->visible == FALSE) {
332: move(b, a);
333: printw(" ? ");
334: } else {
335: printrank(a, b, cp);
336: addch(cp->suit);
337: }
338: }
339:
340: /*
341: * procedure to move the top card from one location to the top
342: * of another location. The pointers always point to the top
343: * of the piles.
344: */
345: transit(source, dest)
346: struct cardtype **source, **dest;
347: {
348: struct cardtype *temp;
349:
350: temp = *source;
351: *source = (*source)->next;
352: temp->next = *dest;
353: *dest = temp;
354: }
355:
356: /*
357: * Procedure to set the cards on the foundation base when available.
358: * Note that it is only called on a foundation pile at the beginning of
359: * the game, so the pile will have exactly one card in it.
360: */
361:
362: fndbase(cp, column, row)
363: struct cardtype **cp;
364: {
365: bool nomore;
366:
367: if (*cp != NIL)
368: do {
369: if ((*cp)->rank == basecard->rank) {
370: base++;
371: printcard(pilemap[base], foundrow, *cp);
372: if (*cp == tableau[0])
373: length[0] = length[0] - 1;
374: if (*cp == tableau[1])
375: length[1] = length[1] - 1;
376: if (*cp == tableau[2])
377: length[2] = length[2] - 1;
378: if (*cp == tableau[3])
379: length[3] = length[3] - 1;
380: transit(cp, &found[base]);
381: if (cp == &talon)
382: usedtalon();
383: if (cp == &stock)
384: usedstock();
385: if (*cp != NIL) {
386: printcard(column, row, *cp);
387: nomore = FALSE;
388: } else {
389: removecard(column, row);
390: nomore = TRUE;
391: }
392: cardsoff++;
393: } else
394: nomore = TRUE;
395: } while (nomore == FALSE);
396: }
397:
398: /* procedure to initialize the things necessary for the game */
399: initgame()
400: {
401: register i;
402:
403: for (i=0; i<18; i++)
404: deck[i]->visible = TRUE;
405: stockcnt = 13;
406: stock = deck[12];
407: for (i=12; i>=1; i--)
408: deck[i]->next = deck[i - 1];
409: deck[0]->next = NIL;
410: found[0] = deck[13];
411: deck[13]->next = NIL;
412: for (i=1; i<4; i++)
413: found[i] = NIL;
414: basecard = found[0];
415: for (i=14; i<18; i++) {
416: tableau[i - 14] = deck[i];
417: deck[i]->next = NIL;
418: }
419: for (i=0; i<4; i++) {
420: bottom[i] = tableau[i];
421: length[i] = tabrow;
422: }
423: hand = deck[18];
424: for (i=18; i<decksize-1; i++)
425: deck[i]->next = deck[i + 1];
426: deck[decksize-1]->next = NIL;
427: talon = NIL;
428: base = 0;
429: cinhand = 34;
430: taloncnt = 0;
431: timesthru = 0;
432: cardsoff = 1;
433: coldrow = ctoprow;
434: coldcol = cinitcol;
435: cnewrow = ctoprow;
436: cnewcol = cinitcol + cwidthcol;
437: }
438:
439: /* procedure to print the beginning cards and to start each game */
440: startgame()
441: {
442: register int j;
443:
444: shuffle(deck);
445: initgame();
446: printcard(foundcol, foundrow, found[0]);
447: printcard(stockcol, stockrow, stock);
448: printcard(atabcol, tabrow, tableau[0]);
449: printcard(btabcol, tabrow, tableau[1]);
450: printcard(ctabcol, tabrow, tableau[2]);
451: printcard(dtabcol, tabrow, tableau[3]);
452: printcard(taloncol, talonrow, talon);
453: move(foundrow - 2, basecol);
454: printw("Base");
455: move(foundrow - 1, basecol);
456: printw("Rank");
457: printrank(basecol, foundrow, found[0]);
458: for (j=0; j<=3; j++)
459: fndbase(&tableau[j], pilemap[j], tabrow);
460: fndbase(&stock, stockcol, stockrow);
461: showstat(); /* show card counting info to cheaters */
462: }
463:
464:
465: /* procedure to clear the message printed from an error */
466: clearmsg()
467: {
468: int i;
469:
470: if (errmsg == TRUE) {
471: errmsg = FALSE;
472: move(msgrow, msgcol);
473: for (i=0; i<25; i++)
474: addch(' ');
475: refresh();
476: }
477: }
478:
479: /* procedure to print an error message if the move is not listed */
480: dumberror()
481: {
482: errmsg = TRUE;
483: move(msgrow, msgcol);
484: printw("Not a proper move ");
485: }
486:
487: /* procedure to print an error message if the move is not possible */
488: destinerror()
489: {
490: errmsg = TRUE;
491: move(msgrow, msgcol);
492: printw("Error: Can't move there");
493: }
494:
495: /* function to see if the source has cards in it */
496: bool
497: notempty(cp)
498: struct cardtype *cp;
499: {
500: if (cp == NIL) {
501: errmsg = TRUE;
502: move(msgrow, msgcol);
503: printw("Error: no cards to move");
504: return (FALSE);
505: } else
506: return (TRUE);
507: }
508:
509:
510: /* function to see if the rank of one card is less than another */
511:
512: bool
513: ranklower(cp1, cp2)
514: struct cardtype *cp1, *cp2;
515: {
516: if (cp2->rank == Ace)
517: if (cp1->rank == King)
518: return (TRUE);
519: else
520: return (FALSE);
521: else if (cp1->rank + 1 == cp2->rank)
522: return (TRUE);
523: else
524: return (FALSE);
525: }
526:
527: /* function to check the cardcolor for moving to a tableau */
528: bool
529: diffcolor(cp1, cp2)
530: struct cardtype *cp1, *cp2;
531: {
532: if (cp1->color == cp2->color)
533: return (FALSE);
534: else
535: return (TRUE);
536: }
537:
538: /* function to see if the card can move to the tableau */
539: bool
540: tabok(cp, des)
541: struct cardtype *cp;
542: {
543: if ((cp == stock) && (tableau[des] == NIL))
544: return (TRUE);
545: else if (tableau[des] == NIL)
546: if (stock == NIL)
547: return (TRUE);
548: else
549: return (FALSE);
550: else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
551: return (TRUE);
552: else
553: return (FALSE);
554: }
555:
556:
557: /* procedure to turn the cards onto the talon from the deck */
558: movetotalon()
559: {
560: int i, fin;
561:
562: if (cinhand >= 3)
563: fin = 3;
564: else if (cinhand > 0)
565: fin = cinhand;
566: else if (talon != NIL) {
567: timesthru++;
568: errmsg = TRUE;
569: move(msgrow, msgcol);
570: if (timesthru != 4) {
571: printw("Talon is now the new hand");
572: while (talon != NIL) {
573: transit(&talon, &hand);
574: cinhand++;
575: }
576: if (cinhand >= 3)
577: fin = 3;
578: else
579: fin = cinhand;
580: taloncnt = 0;
581: coldrow = ctoprow;
582: coldcol = cinitcol;
583: cnewrow = ctoprow;
584: cnewcol = cinitcol + cwidthcol;
585: clearstat();
586: showstat();
587: } else {
588: fin = 0;
589: done = TRUE;
590: printw("I believe you have lost");
591: refresh();
592: sleep(5);
593: }
594: } else {
595: errmsg = TRUE;
596: move(msgrow, msgcol);
597: printw("Talon and hand are empty");
598: fin = 0;
599: }
600: for (i=0; i<fin; i++) {
601: transit(&hand, &talon);
602: INCRHAND(cnewrow, cnewcol);
603: INCRHAND(coldrow, coldcol);
604: removecard(cnewcol, cnewrow);
605: if (i == fin - 1)
606: talon->visible = TRUE;
607: if (Cflag)
608: printcard(coldcol, coldrow, talon);
609: }
610: if (fin != 0) {
611: printcard(taloncol, talonrow, talon);
612: cinhand -= fin;
613: taloncnt += fin;
614: if (Cflag) {
615: move(handstatrow, handstatcol);
616: printw("%3d", cinhand);
617: move(talonstatrow, talonstatcol);
618: printw("%3d", taloncnt);
619: }
620: fndbase(&talon, taloncol, talonrow);
621: }
622: }
623:
624:
625: /* procedure to print card counting info on screen */
626: showstat()
627: {
628: int row, col;
629: register struct cardtype *ptr;
630:
631: if (Cflag) {
632: move(talonstatrow, talonstatcol - 7);
633: printw("Talon: %3d", taloncnt);
634: move(handstatrow, handstatcol - 7);
635: printw("Hand: %3d", cinhand);
636: move(stockstatrow, stockstatcol - 7);
637: printw("Stock: %3d", stockcnt);
638: for ( row = coldrow, col = coldcol, ptr = talon;
639: ptr != NIL;
640: ptr = ptr->next ) {
641: printcard(col, row, ptr);
642: DECRHAND(row, col);
643: }
644: for ( row = cnewrow, col = cnewcol, ptr = hand;
645: ptr != NIL;
646: ptr = ptr->next ) {
647: INCRHAND(row, col);
648: printcard(col, row, ptr);
649: }
650: }
651: }
652:
653:
654: /* procedure to clear card counting info from screen */
655: clearstat()
656: {
657: int row;
658:
659: move(talonstatrow, talonstatcol - 7);
660: printw(" ");
661: move(handstatrow, handstatcol - 7);
662: printw(" ");
663: move(stockstatrow, stockstatcol - 7);
664: printw(" ");
665: for ( row = ctoprow ; row <= cbotrow ; row++ ) {
666: move(row, cinitcol);
667: printw("%56s", " ");
668: }
669: }
670:
671:
672: /* procedure to update card counting base */
673: usedtalon()
674: {
675: removecard(coldcol, coldrow);
676: DECRHAND(coldrow, coldcol);
677: if (talon != NIL && (talon->visible == FALSE)) {
678: talon->visible = TRUE;
679: if (Cflag)
680: printcard(coldcol, coldrow, talon);
681: }
682: taloncnt--;
683: if (Cflag) {
684: move(talonstatrow, talonstatcol);
685: printw("%3d", taloncnt);
686: }
687: }
688:
689:
690: /* procedure to update stock card counting base */
691: usedstock()
692: {
693: stockcnt--;
694: if (Cflag) {
695: move(stockstatrow, stockstatcol);
696: printw("%3d", stockcnt);
697: }
698: }
699:
700:
701: /* let 'em know how they lost! */
702: showcards()
703: {
704: register struct cardtype *ptr;
705: int row;
706:
707: if (!Cflag)
708: return;
709: for (ptr = talon; ptr != NIL; ptr = ptr->next)
710: ptr->visible = TRUE;
711: for (ptr = hand; ptr != NIL; ptr = ptr->next)
712: ptr->visible = TRUE;
713: showstat();
714: move(stockrow + 1, sidecol);
715: printw(" ");
716: move(talonrow - 2, sidecol);
717: printw(" ");
718: move(talonrow - 1, sidecol);
719: printw(" ");
720: move(talonrow, sidecol);
721: printw(" ");
722: move(talonrow + 1, sidecol);
723: printw(" ");
724: for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
725: move(row, stockcol - 1);
726: printw("| |");
727: printcard(stockcol, row, ptr);
728: }
729: if (stock == NIL) {
730: move(row, stockcol - 1);
731: printw("| |");
732: row++;
733: }
734: move(handstatrow, handstatcol - 7);
735: printw(" ");
736: move(row, stockcol - 1);
737: printw("=---=");
738: getcmd(moverow, movecol, "Hit return to exit");
739: }
740:
741:
742: /* procedure to move a card from the stock or talon to the tableau */
743: simpletableau(cp, des)
744: struct cardtype **cp;
745: {
746: int origin;
747:
748: if (notempty(*cp)) {
749: if (tabok(*cp, des)) {
750: if (*cp == stock)
751: origin = stk;
752: else
753: origin = tal;
754: if (tableau[des] == NIL)
755: bottom[des] = *cp;
756: transit(cp, &tableau[des]);
757: length[des]++;
758: printcard(pilemap[des], length[des], tableau[des]);
759: timesthru = 0;
760: if (origin == stk) {
761: usedstock();
762: printcard(stockcol, stockrow, stock);
763: } else {
764: usedtalon();
765: printcard(taloncol, talonrow, talon);
766: }
767: } else
768: destinerror();
769: }
770: }
771:
772:
773: tabprint(sour, des)
774: {
775: int dlength, slength, i;
776: struct cardtype *tempcard;
777:
778: for (i=tabrow; i<=length[sour]; i++)
779: removecard(pilemap[sour], i);
780: dlength = length[des] + 1;
781: slength = length[sour];
782: if (slength == tabrow)
783: printcard(pilemap[des], dlength, tableau[sour]);
784: else
785: while (slength != tabrow - 1) {
786: tempcard = tableau[sour];
787: for (i=1; i<=slength-tabrow; i++)
788: tempcard = tempcard->next;
789: printcard(pilemap[des], dlength, tempcard);
790: slength--;
791: dlength++;
792: }
793: }
794:
795: /* procedure to move from the tableau to the tableau */
796: tabtotab(sour, des)
797: {
798: struct cardtype *temp;
799:
800: if (notempty(tableau[sour])) {
801: if (tabok(bottom[sour], des)) {
802: tabprint(sour, des);
803: temp = bottom[sour];
804: bottom[sour] = NIL;
805: temp->next = tableau[des];
806: tableau[des] = tableau[sour];
807: tableau[sour] = NIL;
808: length[des] = length[des] + (length[sour] - (tabrow - 1));
809: length[sour] = tabrow - 1;
810: timesthru = 0;
811: } else
812: destinerror();
813: }
814: }
815:
816:
817: /* functions to see if the card can go onto the foundation */
818: bool
819: rankhigher(cp, let)
820: struct cardtype *cp;
821: {
822: if (found[let]->rank == King)
823: if (cp->rank == Ace)
824: return(TRUE);
825: else
826: return(FALSE);
827: else if (cp->rank - 1 == found[let]->rank)
828: return(TRUE);
829: else
830: return(FALSE);
831: }
832:
833: samesuit(cp, let)
834: struct cardtype *cp;
835: {
836: if (cp->suit == found[let]->suit)
837: return (TRUE);
838: else
839: return (FALSE);
840: }
841:
842: /* procedure to move a card to the correct foundation pile */
843:
844: movetofound(cp, source)
845: struct cardtype **cp;
846: {
847: tempbase = 0;
848: mtfdone = FALSE;
849: if (notempty(*cp)) {
850: do {
851: if (found[tempbase] != NIL)
852: if (rankhigher(*cp, tempbase)
853: && samesuit(*cp, tempbase)) {
854: if (*cp == stock)
855: mtforigin = stk;
856: else if (*cp == talon)
857: mtforigin = tal;
858: else
859: mtforigin = tab;
860: transit(cp, &found[tempbase]);
861: printcard(pilemap[tempbase],
862: foundrow, found[tempbase]);
863: timesthru = 0;
864: if (mtforigin == stk) {
865: usedstock();
866: printcard(stockcol, stockrow, stock);
867: } else if (mtforigin == tal) {
868: usedtalon();
869: printcard(taloncol, talonrow, talon);
870: } else {
871: removecard(pilemap[source], length[source]);
872: length[source]--;
873: }
874: cardsoff++;
875: mtfdone = TRUE;
876: } else
877: tempbase++;
878: else
879: tempbase++;
880: } while ((tempbase != 4) && !mtfdone);
881: if (!mtfdone)
882: destinerror();
883: }
884: }
885:
886:
887: /* procedure to get a command */
888:
889: getcmd(row, col, cp)
890: int row, col;
891: char *cp;
892: {
893: char cmd[2], ch;
894: int i;
895:
896: i = 0;
897: move(row, col);
898: printw("%-24s", cp);
899: col += 1 + strlen(cp);
900: move(row, col);
901: refresh();
902: do {
903: ch = getch() & 0177;
904: if (ch >= 'A' && ch <= 'Z')
905: ch += ('a' - 'A');
906: if (ch == '\f') {
907: wrefresh(curscr);
908: refresh();
909: } else if (i >= 2 && ch != _tty.sg_erase && ch != _tty.sg_kill) {
910: if (ch != '\n' && ch != '\r' && ch != ' ')
911: write(1, "\007", 1);
912: } else if (ch == _tty.sg_erase && i > 0) {
913: printw("\b \b");
914: refresh();
915: i--;
916: } else if (ch == _tty.sg_kill && i > 0) {
917: while (i > 0) {
918: printw("\b \b");
919: i--;
920: }
921: refresh();
922: } else if (ch == '\032') { /* Control-Z */
923: suspend();
924: move(row, col + i);
925: refresh();
926: } else if (isprint(ch)) {
927: cmd[i++] = ch;
928: addch(ch);
929: refresh();
930: }
931: } while (ch != '\n' && ch != '\r' && ch != ' ');
932: srcpile = cmd[0];
933: destpile = cmd[1];
934: }
935:
936: /* Suspend the game (shell escape if no process control on system) */
937:
938: suspend()
939: {
940: #ifndef SIGTSTP
941: char *sh;
942: #endif
943:
944: move(21, 0);
945: refresh();
946: endwin();
947: fflush(stdout);
948: #ifdef SIGTSTP
949: kill(getpid(), SIGTSTP);
950: #else
951: sh = getenv("SHELL");
952: if (sh == NULL)
953: sh = "/bin/sh";
954: system(sh);
955: #endif
956: raw();
957: noecho();
958: }
959:
960: /* procedure to evaluate and make the specific moves */
961:
962: movecard()
963: {
964: int source, dest;
965:
966: done = FALSE;
967: errmsg = FALSE;
968: do {
969: if (cardsoff == 52) {
970: refresh();
971: srcpile = 'q';
972: } else
973: getcmd(moverow, movecol, "Move:");
974: clearmsg();
975: if (srcpile >= '1' && srcpile <= '4')
976: source = (int) (srcpile - '1');
977: if (destpile >= '1' && destpile <= '4')
978: dest = (int) (destpile - '1');
979: switch (srcpile) {
980: case 't':
981: if (destpile == 'f' || destpile == 'F')
982: movetofound(&talon, source);
983: else if (destpile >= '1' && destpile <= '4')
984: simpletableau(&talon, dest);
985: else
986: dumberror();
987: break;
988: case 's':
989: if (destpile == 'f' || destpile == 'F')
990: movetofound(&stock, source);
991: else if (destpile >= '1' && destpile <= '4')
992: simpletableau(&stock, dest);
993: else dumberror();
994: break;
995: case 'h':
996: if (destpile == 't' || destpile == 'T')
997: movetotalon();
998: else dumberror();
999: break;
1000: case 'q':
1001: showcards();
1002: done = TRUE;
1003: break;
1004: case 'c':
1005: Cflag = !Cflag;
1006: if (Cflag)
1007: showstat();
1008: else
1009: clearstat();
1010: break;
1011: case '1': case '2': case '3': case '4':
1012: if (destpile == 'f' || destpile == 'F')
1013: movetofound(&tableau[source], source);
1014: else if (destpile >= '1' && destpile <= '4')
1015: tabtotab(source, dest);
1016: else dumberror();
1017: break;
1018: default:
1019: dumberror();
1020: }
1021: fndbase(&stock, stockcol, stockrow);
1022: fndbase(&talon, taloncol, talonrow);
1023: } while (!done);
1024: }
1025:
1026: /* procedure to printout instructions */
1027: instruct()
1028: {
1029: move(originrow, origincol);
1030: printw("This is the game of solitaire called Canfield. Do\n");
1031: printw("you want instructions for the game?");
1032: do {
1033: getcmd(originrow + 3, origincol, "y or n?");
1034: } while (srcpile != 'y' && srcpile != 'n');
1035: if (srcpile == 'y') {
1036: clear();
1037: refresh();
1038: printw("Here are brief instuctions to the game of Canfield:\n");
1039: printw("\n");
1040: printw(" If you have never played solitaire before, it is recom-\n");
1041: printw("mended that you consult a solitaire instruction book. In\n");
1042: printw("Canfield, tableau cards may be built on each other downward\n");
1043: printw("in alternate colors. An entire pile must be moved as a unit\n");
1044: printw("in building. Top cards of the piles are available to be able\n");
1045: printw("to be played on foundations, but never into empty spaces.\n");
1046: printw("\n");
1047: printw(" Spaces must be filled from the stock. The top card of\n");
1048: printw("the stock also is available to be played on foundations or\n");
1049: printw("built on tableau piles. After the stock is exhausted, ta-\n");
1050: printw("bleau spaces may be filled from the talon and the player may\n");
1051: printw("keep them open until he wishes to use them.\n");
1052: printw("\n");
1053: printw(" Cards are dealt from the hand to the talon by threes\n");
1054: printw("and this repeats until there are no more cards in the hand\n");
1055: printw("or the player quits. To have cards dealt onto the talon the\n");
1056: printw("player types 'ht' for his move. Foundation base cards are\n");
1057: printw("also automatically moved to the foundation when they become\n");
1058: printw("available.\n\n");
1059: printw("push any key when you are finished: ");
1060: refresh();
1061: getch();
1062: }
1063: }
1064:
1065: /* procedure to initialize the game */
1066: initall()
1067:
1068: {
1069: srand(getpid());
1070: initdeck(deck);
1071: }
1072:
1073: /* procedure to end the game */
1074: bool
1075: finish()
1076: {
1077: int row, col;
1078:
1079: if (cardsoff == 52) {
1080: clear();
1081: refresh();
1082: move(originrow, origincol);
1083: printw("CONGRATULATIONS!\n");
1084: printw("You won the game. That is a feat to be proud of.\n");
1085: move(originrow + 4, origincol);
1086: printw("Wish to play again? ");
1087: row = originrow + 5;
1088: col = origincol;
1089: } else {
1090: move(msgrow, msgcol);
1091: printw("You got %d card", cardsoff);
1092: if (cardsoff > 1)
1093: printw("s");
1094: printw(" off ");
1095: getcmd(moverow, movecol, "Hit return to continue");
1096: move(msgrow, msgcol);
1097: printw("Wish to play again? ");
1098: row = moverow;
1099: col = movecol;
1100: }
1101: do {
1102: getcmd(row, col, "y or n?");
1103: } while (srcpile != 'y' && srcpile != 'n');
1104: errmsg = TRUE;
1105: clearmsg();
1106: if (srcpile == 'y')
1107: return (FALSE);
1108: else
1109: return (TRUE);
1110: }
1111:
1112: main(argc, argv)
1113: int argc;
1114: char *argv[];
1115: {
1116: #ifdef MAXLOAD
1117: double vec[3];
1118:
1119: loadav(vec);
1120: if (vec[2] >= MAXLOAD) {
1121: puts("The system load is too high. Try again later.");
1122: exit(0);
1123: }
1124: #endif
1125: initscr();
1126: raw();
1127: noecho();
1128: initall();
1129: instruct();
1130: makeboard();
1131: for (;;) {
1132: startgame();
1133: movecard();
1134: if (finish())
1135: break;
1136: if (cardsoff == 52)
1137: makeboard();
1138: else
1139: cleanupboard();
1140: }
1141: clear();
1142: move(22,0);
1143: refresh();
1144: endwin();
1145: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.