/* Copyright (c) 1982 Regents of the University of California */
static char sccsid
[] = "@(#)canfield.c 4.1 10/24/82";
* Originally written: Steve Levine
* Converted to use curses and debugged: Steve Feldman
* Card counting: Kirk McKusick and Mikey Olson
#define INCRHAND(row, col) {\
#define DECRHAND(row, col) {\
#define NIL ((struct cardtype *) -1)
struct cardtype
*deck
[decksize
];
struct cardtype cards
[decksize
];
struct cardtype
*bottom
[4], *found
[4], *tableau
[4];
struct cardtype
*talon
, *hand
, *stock
, *basecard
;
int cardsoff
, base
, cinhand
, taloncnt
, stockcnt
, timesthru
;
char suitmap
[4] = {spades
, clubs
, hearts
, diamonds
};
char colormap
[4] = {black
, black
, red
, red
};
char pilemap
[4] = {atabcol
, btabcol
, ctabcol
, dtabcol
};
int coldcol
, cnewcol
, coldrow
, cnewrow
;
bool mtfdone
, Cflag
= FALSE
;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* The following procedures print the board onto the screen using the
* addressible cursor. The end of these procedures will also be
* separated from the rest of the program.
/* procedure to set the move command box */
printw("*--------------------------*");
move(tboxrow
+ 1, boxcol
);
move(tboxrow
+ 2, boxcol
);
printw("|s# = stock to tableau |");
move(tboxrow
+ 3, boxcol
);
printw("|sf = stock to foundation |");
move(tboxrow
+ 4, boxcol
);
printw("|t# = talon to tableau |");
move(tboxrow
+ 5, boxcol
);
printw("|tf = talon to foundation |");
move(tboxrow
+ 6, boxcol
);
printw("|## = tableau to tableau |");
move(tboxrow
+ 7, boxcol
);
printw("|#f = tableau to foundation|");
move(tboxrow
+ 8, boxcol
);
printw("|ht = hand to talon |");
move(tboxrow
+ 9, boxcol
);
printw("|c = toggle card counting |");
move(tboxrow
+ 10, boxcol
);
printw("|q = quit to end the game |");
move(tboxrow
+ 11, boxcol
);
printw("|==========================|");
printw("|Replace the # with the |");
move(bboxrow
+ 1, boxcol
);
printw("|number of the tableau you |");
move(bboxrow
+ 2, boxcol
);
printw("|want, 1, 2, 3, or 4. |");
move(bboxrow
+ 3, boxcol
);
printw("*--------------------------*");
/* procedure to put the board on the screen using addressable cursor */
move(titlerow
, titlecol
);
printw("=-> CANFIELD <-=");
move(foundrow
- 1, fttlcol
);
printw("=---= =---= =---= =---=");
printw("| | | | | | | |");
move(foundrow
+ 1, fttlcol
);
printw("=---= =---= =---= =---=");
move(stockrow
- 1, sidecol
);
move(stockrow
+ 1, sidecol
);
move(talonrow
- 2, sidecol
);
move(talonrow
- 1, sidecol
);
move(talonrow
+ 1, sidecol
);
move(tabrow
- 1, atabcol
);
printw("-1- -2- -3- -4-");
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* clean up the board for another game */
for(ptr
= stock
, row
= stockrow
;
ptr
= ptr
->next
, row
++) {
move(stockrow
+ 1, sidecol
);
move(talonrow
- 2, sidecol
);
move(talonrow
- 1, sidecol
);
move(talonrow
+ 1, sidecol
);
printw("| | | | | | | |");
for (cnt
= 0; cnt
< 4; cnt
++) {
for(ptr
= tableau
[cnt
], row
= tabrow
;
/* procedure to create a deck of cards */
for (scnt
=0; scnt
<4; scnt
++) {
for (r
=Ace
; r
<=King
; r
++) {
cards
[i
].color
= colormap
[scnt
];
/* procedure to shuffle the deck */
for (i
=0; i
<decksize
; i
++)
deck
[i
]->visible
= FALSE
;
for (i
= decksize
-1; i
>=0; i
--) {
/* procedure to remove the card from the board */
/* procedure to print the cards on the board */
case 2: case 3: case 4: case 5: case 6: case 7:
else if (cp
->visible
== FALSE
) {
* procedure to move the top card from one location to the top
* of another location. The pointers always point to the top
struct cardtype
**source
, **dest
;
*source
= (*source
)->next
;
* Procedure to set the cards on the foundation base when available.
* Note that it is only called on a foundation pile at the beginning of
* the game, so the pile will have exactly one card in it.
if ((*cp
)->rank
== basecard
->rank
) {
printcard(pilemap
[base
], foundrow
, *cp
);
length
[0] = length
[0] - 1;
length
[1] = length
[1] - 1;
length
[2] = length
[2] - 1;
length
[3] = length
[3] - 1;
transit(cp
, &found
[base
]);
printcard(column
, row
, *cp
);
} while (nomore
== FALSE
);
/* procedure to initialize the things necessary for the game */
deck
[i
]->next
= deck
[i
- 1];
tableau
[i
- 14] = deck
[i
];
for (i
=18; i
<decksize
-1; i
++)
deck
[i
]->next
= deck
[i
+ 1];
deck
[decksize
-1]->next
= NIL
;
cnewcol
= cinitcol
+ cwidthcol
;
/* procedure to print the beginning cards and to start each game */
printcard(foundcol
, foundrow
, found
[0]);
printcard(stockcol
, stockrow
, stock
);
printcard(atabcol
, tabrow
, tableau
[0]);
printcard(btabcol
, tabrow
, tableau
[1]);
printcard(ctabcol
, tabrow
, tableau
[2]);
printcard(dtabcol
, tabrow
, tableau
[3]);
printcard(taloncol
, talonrow
, talon
);
move(foundrow
- 2, basecol
);
move(foundrow
- 1, basecol
);
printrank(basecol
, foundrow
, found
[0]);
fndbase(&tableau
[j
], pilemap
[j
], tabrow
);
fndbase(&stock
, stockcol
, stockrow
);
showstat(); /* show card counting info to cheaters */
/* procedure to clear the message printed from an error */
/* procedure to print an error message if the move is not listed */
printw("Not a proper move ");
/* procedure to print an error message if the move is not possible */
printw("Error: Can't move there");
/* function to see if the source has cards in it */
printw("Error: no cards to move");
/* function to see if the rank of one card is less than another */
struct cardtype
*cp1
, *cp2
;
else if (cp1
->rank
+ 1 == cp2
->rank
)
/* function to check the cardcolor for moving to a tableau */
struct cardtype
*cp1
, *cp2
;
if (cp1
->color
== cp2
->color
)
/* function to see if the card can move to the tableau */
if ((cp
== stock
) && (tableau
[des
] == NIL
))
else if (tableau
[des
] == NIL
)
else if (ranklower(cp
, tableau
[des
]) && diffcolor(cp
, tableau
[des
]))
/* procedure to turn the cards onto the talon from the deck */
printw("Talon is now the new hand");
cnewcol
= cinitcol
+ cwidthcol
;
printw("I believe you have lost");
printw("Talon and hand are empty");
INCRHAND(cnewrow
, cnewcol
);
INCRHAND(coldrow
, coldcol
);
removecard(cnewcol
, cnewrow
);
printcard(coldcol
, coldrow
, talon
);
printcard(taloncol
, talonrow
, talon
);
move(handstatrow
, handstatcol
);
move(talonstatrow
, talonstatcol
);
fndbase(&talon
, taloncol
, talonrow
);
/* procedure to print card counting info on screen */
register struct cardtype
*ptr
;
move(talonstatrow
, talonstatcol
- 7);
printw("Talon: %3d", taloncnt
);
move(handstatrow
, handstatcol
- 7);
printw("Hand: %3d", cinhand
);
move(stockstatrow
, stockstatcol
- 7);
printw("Stock: %3d", stockcnt
);
for ( row
= coldrow
, col
= coldcol
, ptr
= talon
;
printcard(col
, row
, ptr
);
for ( row
= cnewrow
, col
= cnewcol
, ptr
= hand
;
printcard(col
, row
, ptr
);
/* procedure to clear card counting info from screen */
move(talonstatrow
, talonstatcol
- 7);
move(handstatrow
, handstatcol
- 7);
move(stockstatrow
, stockstatcol
- 7);
for ( row
= ctoprow
; row
<= cbotrow
; row
++ ) {
/* procedure to update card counting base */
removecard(coldcol
, coldrow
);
DECRHAND(coldrow
, coldcol
);
if (talon
!= NIL
&& (talon
->visible
== FALSE
)) {
printcard(coldcol
, coldrow
, talon
);
move(talonstatrow
, talonstatcol
);
/* procedure to update stock card counting base */
move(stockstatrow
, stockstatcol
);
/* let 'em know how they lost! */
register struct cardtype
*ptr
;
for (ptr
= talon
; ptr
!= NIL
; ptr
= ptr
->next
)
for (ptr
= hand
; ptr
!= NIL
; ptr
= ptr
->next
)
move(stockrow
+ 1, sidecol
);
move(talonrow
- 2, sidecol
);
move(talonrow
- 1, sidecol
);
move(talonrow
+ 1, sidecol
);
for (ptr
= stock
, row
= stockrow
; ptr
!= NIL
; ptr
= ptr
->next
, row
++) {
printcard(stockcol
, row
, ptr
);
move(handstatrow
, handstatcol
- 7);
getcmd(moverow
, movecol
, "Hit return to exit");
/* procedure to move a card from the stock or talon to the tableau */
transit(cp
, &tableau
[des
]);
printcard(pilemap
[des
], length
[des
], tableau
[des
]);
printcard(stockcol
, stockrow
, stock
);
printcard(taloncol
, talonrow
, talon
);
struct cardtype
*tempcard
;
for (i
=tabrow
; i
<=length
[sour
]; i
++)
removecard(pilemap
[sour
], i
);
dlength
= length
[des
] + 1;
printcard(pilemap
[des
], dlength
, tableau
[sour
]);
while (slength
!= tabrow
- 1) {
tempcard
= tableau
[sour
];
for (i
=1; i
<=slength
-tabrow
; i
++)
tempcard
= tempcard
->next
;
printcard(pilemap
[des
], dlength
, tempcard
);
/* procedure to move from the tableau to the tableau */
if (notempty(tableau
[sour
])) {
if (tabok(bottom
[sour
], des
)) {
temp
->next
= tableau
[des
];
tableau
[des
] = tableau
[sour
];
length
[des
] = length
[des
] + (length
[sour
] - (tabrow
- 1));
length
[sour
] = tabrow
- 1;
/* functions to see if the card can go onto the foundation */
if (found
[let
]->rank
== King
)
else if (cp
->rank
- 1 == found
[let
]->rank
)
if (cp
->suit
== found
[let
]->suit
)
/* procedure to move a card to the correct foundation pile */
if (found
[tempbase
] != NIL
)
if (rankhigher(*cp
, tempbase
)
&& samesuit(*cp
, tempbase
)) {
transit(cp
, &found
[tempbase
]);
printcard(pilemap
[tempbase
],
foundrow
, found
[tempbase
]);
printcard(stockcol
, stockrow
, stock
);
} else if (mtforigin
== tal
) {
printcard(taloncol
, talonrow
, talon
);
removecard(pilemap
[source
], length
[source
]);
} while ((tempbase
!= 4) && !mtfdone
);
/* procedure to get a command */
if (ch
>= 'A' && ch
<= 'Z')
} else if (i
>= 2 && ch
!= _tty
.sg_erase
&& ch
!= _tty
.sg_kill
) {
if (ch
!= '\n' && ch
!= '\r' && ch
!= ' ')
} else if (ch
== _tty
.sg_erase
&& i
> 0) {
} else if (ch
== _tty
.sg_kill
&& i
> 0) {
} else if (ch
== '\032') { /* Control-Z */
} else if (isprint(ch
)) {
} while (ch
!= '\n' && ch
!= '\r' && ch
!= ' ');
/* Suspend the game (shell escape if no process control on system) */
/* procedure to evaluate and make the specific moves */
getcmd(moverow
, movecol
, "Move:");
if (srcpile
>= '1' && srcpile
<= '4')
source
= (int) (srcpile
- '1');
if (destpile
>= '1' && destpile
<= '4')
dest
= (int) (destpile
- '1');
if (destpile
== 'f' || destpile
== 'F')
movetofound(&talon
, source
);
else if (destpile
>= '1' && destpile
<= '4')
simpletableau(&talon
, dest
);
if (destpile
== 'f' || destpile
== 'F')
movetofound(&stock
, source
);
else if (destpile
>= '1' && destpile
<= '4')
simpletableau(&stock
, dest
);
if (destpile
== 't' || destpile
== 'T')
case '1': case '2': case '3': case '4':
if (destpile
== 'f' || destpile
== 'F')
movetofound(&tableau
[source
], source
);
else if (destpile
>= '1' && destpile
<= '4')
fndbase(&stock
, stockcol
, stockrow
);
fndbase(&talon
, taloncol
, talonrow
);
/* procedure to printout instructions */
move(originrow
, origincol
);
printw("This is the game of solitaire called Canfield. Do\n");
printw("you want instructions for the game?");
getcmd(originrow
+ 3, origincol
, "y or n?");
} while (srcpile
!= 'y' && srcpile
!= 'n');
printw("Here are brief instuctions to the game of Canfield:\n");
printw(" If you have never played solitaire before, it is recom-\n");
printw("mended that you consult a solitaire instruction book. In\n");
printw("Canfield, tableau cards may be built on each other downward\n");
printw("in alternate colors. An entire pile must be moved as a unit\n");
printw("in building. Top cards of the piles are available to be able\n");
printw("to be played on foundations, but never into empty spaces.\n");
printw(" Spaces must be filled from the stock. The top card of\n");
printw("the stock also is available to be played on foundations or\n");
printw("built on tableau piles. After the stock is exhausted, ta-\n");
printw("bleau spaces may be filled from the talon and the player may\n");
printw("keep them open until he wishes to use them.\n");
printw(" Cards are dealt from the hand to the talon by threes\n");
printw("and this repeats until there are no more cards in the hand\n");
printw("or the player quits. To have cards dealt onto the talon the\n");
printw("player types 'ht' for his move. Foundation base cards are\n");
printw("also automatically moved to the foundation when they become\n");
printw("available.\n\n");
printw("push any key when you are finished: ");
/* procedure to initialize the game */
/* procedure to end the game */
move(originrow
, origincol
);
printw("CONGRATULATIONS!\n");
printw("You won the game. That is a feat to be proud of.\n");
move(originrow
+ 4, origincol
);
printw("Wish to play again? ");
printw("You got %d card", cardsoff
);
getcmd(moverow
, movecol
, "Hit return to continue");
printw("Wish to play again? ");
getcmd(row
, col
, "y or n?");
} while (srcpile
!= 'y' && srcpile
!= 'n');
puts("The system load is too high. Try again later.");