summaryrefslogtreecommitdiff
path: root/games/canfield
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 08:53:40 +0000
commitd6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch)
treeece253b876159b39c620e62b6c9b1174642e070e /games/canfield
initial import of NetBSD tree
Diffstat (limited to 'games/canfield')
-rw-r--r--games/canfield/Makefile6
-rw-r--r--games/canfield/canfield/Makefile12
-rw-r--r--games/canfield/canfield/canfield.6131
-rw-r--r--games/canfield/canfield/canfield.c1716
-rw-r--r--games/canfield/canfield/pathnames.h39
-rw-r--r--games/canfield/cfscores/Makefile10
-rw-r--r--games/canfield/cfscores/cfscores.c154
7 files changed, 2068 insertions, 0 deletions
diff --git a/games/canfield/Makefile b/games/canfield/Makefile
new file mode 100644
index 00000000000..c656887f7ee
--- /dev/null
+++ b/games/canfield/Makefile
@@ -0,0 +1,6 @@
+# $NetBSD: Makefile,v 1.3 1995/03/21 15:08:26 cgd Exp $
+# @(#)Makefile 8.1 (Berkeley) 5/31/93
+
+SUBDIR= canfield cfscores
+
+.include <bsd.subdir.mk>
diff --git a/games/canfield/canfield/Makefile b/games/canfield/canfield/Makefile
new file mode 100644
index 00000000000..5877216910a
--- /dev/null
+++ b/games/canfield/canfield/Makefile
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.5 1995/03/21 15:08:28 cgd Exp $
+# @(#)Makefile 8.1 (Berkeley) 5/31/93
+
+PROG= canfield
+MAN= canfield.6
+DPADD= ${LIBCURSES} ${LIBTERM}
+LDADD= -lcurses -ltermcap
+HIDEGAME=hidegame
+
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/games/canfield/canfield/canfield.6 b/games/canfield/canfield/canfield.6
new file mode 100644
index 00000000000..17b34ae38dd
--- /dev/null
+++ b/games/canfield/canfield/canfield.6
@@ -0,0 +1,131 @@
+.\" $NetBSD: canfield.6,v 1.4 1995/03/21 15:08:30 cgd Exp $
+.\"
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)canfield.6 8.1 (Berkeley) 5/31/93
+.\"
+.Dd May 31, 1993
+.Dt CANFIELD 6
+.Os
+.Sh NAME
+.Nm canfield ,
+.Nm cfscores
+.Nd the solitaire card game canfield
+.Sh SYNOPSIS
+.Nm canfield
+.Nm cfscores
+.Op Fl a
+.Op Ar user
+.Sh DESCRIPTION
+If you have never played solitaire before, it is recommended
+that you consult a solitaire instruction book. In
+Canfield, tableau cards may be built on each other downward
+in alternate colors. An entire pile must be moved as a unit
+in building. Top cards of the piles are available
+to be played on foundations, but never into empty spaces.
+.Pp
+Spaces must be filled from the stock. The top card of
+the stock also is available to be played on foundations or
+built on tableau piles. After the stock is exhausted,
+tableau spaces may be filled from the talon and the player may
+keep them open until he wishes to use them.
+.Pp
+Cards are dealt from the hand to the talon by threes
+and this repeats until there are no more cards in the hand
+or the player quits. To have cards dealt onto the talon the
+player types
+.Sq Ic ht
+for his move. Foundation base cards are
+also automatically moved to the foundation when they become
+available.
+.Pp
+The command
+.Sq Ic c
+causes
+.Nm canfield
+to maintain card counting statistics
+on the bottom of the screen.
+When properly used this can greatly increase one's chances of
+winning.
+.Pp
+The rules for betting are somewhat less strict than
+those used in the official version of the game.
+The initial deal costs $13.
+You may quit at this point or inspect the game.
+Inspection costs $13 and allows you to make as many
+moves as possible without moving any cards from your hand
+to the talon.
+(The initial deal places three cards on the talon;
+if all these cards are used,
+three more are made available.)
+Finally, if the game seems interesting,
+you must pay the final installment of $26.
+At this point you are
+credited at the rate of $5 for each card on the foundation;
+as the game progresses you are credited with $5 for each
+card that is moved to the foundation.
+Each run through the hand after the first costs $5.
+The card counting feature
+costs $1 for each unknown card that is identified.
+If the information is toggled on,
+you are only charged for cards
+that became visible since it was last turned on.
+Thus the maximum cost of information is $34.
+Playing time is charged at a rate of $1 per minute.
+.Pp
+With no arguments, the program
+.Nm cfscores
+prints out the current status of your canfield account.
+If a
+.Ar user
+name is specified,
+it prints out the status of their canfield account.
+If the
+.Fl a
+flag is specified,
+it prints out the canfield accounts for all users that have
+played the game since the database was set up.
+.Sh FILES
+.Bl -tag -width /usr/games/canfield -compact
+.It Pa /usr/games/canfield
+the game itself
+.It Pa /usr/games/cfscores
+the database printer
+.It Pa /var/games/cfscores
+the database of scores
+.Sh BUGS
+It is impossible to cheat.
+.Sh AUTHORS
+Originally written: Steve Levine.
+.Pp
+Further random hacking by: Steve Feldman, Kirk McKusick,
+Mikey Olson, and Eric Allman.
diff --git a/games/canfield/canfield/canfield.c b/games/canfield/canfield/canfield.c
new file mode 100644
index 00000000000..406b698dbc9
--- /dev/null
+++ b/games/canfield/canfield/canfield.c
@@ -0,0 +1,1716 @@
+/* $NetBSD: canfield.c,v 1.7 1995/05/13 07:28:35 jtc Exp $ */
+
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)canfield.c 8.1 (Berkeley) 5/31/93";
+#else
+static char rcsid[] = "$NetBSD: canfield.c,v 1.7 1995/05/13 07:28:35 jtc Exp $";
+#endif
+#endif /* not lint */
+
+/*
+ * The canfield program
+ *
+ * Authors:
+ * Originally written: Steve Levine
+ * Converted to use curses and debugged: Steve Feldman
+ * Card counting: Kirk McKusick and Mikey Olson
+ * User interface cleanups: Eric Allman and Kirk McKusick
+ * Betting by Kirk McKusick
+ */
+
+#include <sys/types.h>
+
+#include <curses.h>
+#include <termios.h>
+#include <ctype.h>
+#include <signal.h>
+#include <string.h>
+#include <termios.h>
+
+#include "pathnames.h"
+
+#define decksize 52
+#define originrow 0
+#define origincol 0
+#define basecol 1
+#define boxcol 42
+#define tboxrow 2
+#define bboxrow 17
+#define movecol 43
+#define moverow 16
+#define msgcol 43
+#define msgrow 15
+#define titlecol 30
+#define titlerow 0
+#define sidecol 1
+#define ottlrow 6
+#define foundcol 11
+#define foundrow 3
+#define stockcol 2
+#define stockrow 8
+#define fttlcol 10
+#define fttlrow 1
+#define taloncol 2
+#define talonrow 13
+#define tabrow 8
+#define ctoprow 21
+#define cbotrow 23
+#define cinitcol 14
+#define cheightcol 1
+#define cwidthcol 4
+#define handstatrow 21
+#define handstatcol 7
+#define talonstatrow 22
+#define talonstatcol 7
+#define stockstatrow 23
+#define stockstatcol 7
+#define Ace 1
+#define Jack 11
+#define Queen 12
+#define King 13
+#define atabcol 11
+#define btabcol 18
+#define ctabcol 25
+#define dtabcol 32
+
+#define spades 's'
+#define clubs 'c'
+#define hearts 'h'
+#define diamonds 'd'
+#define black 'b'
+#define red 'r'
+
+#define stk 1
+#define tal 2
+#define tab 3
+#define INCRHAND(row, col) {\
+ row -= cheightcol;\
+ if (row < ctoprow) {\
+ row = cbotrow;\
+ col += cwidthcol;\
+ }\
+}
+#define DECRHAND(row, col) {\
+ row += cheightcol;\
+ if (row > cbotrow) {\
+ row = ctoprow;\
+ col -= cwidthcol;\
+ }\
+}
+
+
+struct cardtype {
+ char suit;
+ char color;
+ bool visible;
+ bool paid;
+ int rank;
+ struct cardtype *next;
+};
+
+#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 length[4];
+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};
+char srcpile, destpile;
+int mtforigin, tempbase;
+int coldcol, cnewcol, coldrow, cnewrow;
+bool errmsg, done;
+bool mtfdone, Cflag = FALSE;
+#define INSTRUCTIONBOX 1
+#define BETTINGBOX 2
+#define NOBOX 3
+int status = INSTRUCTIONBOX;
+int uid;
+
+/*
+ * Basic betting costs
+ */
+#define costofhand 13
+#define costofinspection 13
+#define costofgame 26
+#define costofrunthroughhand 5
+#define costofinformation 1
+#define secondsperdollar 60
+#define maxtimecharge 3
+#define valuepercardup 5
+/*
+ * Variables associated with betting
+ */
+struct betinfo {
+ long hand; /* cost of dealing hand */
+ long inspection; /* cost of inspecting hand */
+ long game; /* cost of buying game */
+ long runs; /* cost of running through hands */
+ long information; /* cost of information */
+ long thinktime; /* cost of thinking time */
+ long wins; /* total winnings */
+ long worth; /* net worth after costs */
+};
+struct betinfo this, game, total;
+bool startedgame = FALSE, infullgame = FALSE;
+time_t acctstart;
+int dbfd = -1;
+
+/*
+ * 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
+ */
+movebox()
+{
+ switch (status) {
+ case BETTINGBOX:
+ printtopbettingbox();
+ break;
+ case NOBOX:
+ clearabovemovebox();
+ break;
+ case INSTRUCTIONBOX:
+ printtopinstructions();
+ break;
+ }
+ move(moverow, boxcol);
+ printw("| |");
+ move(msgrow, boxcol);
+ printw("| |");
+ switch (status) {
+ case BETTINGBOX:
+ printbottombettingbox();
+ break;
+ case NOBOX:
+ clearbelowmovebox();
+ break;
+ case INSTRUCTIONBOX:
+ printbottominstructions();
+ break;
+ }
+ refresh();
+}
+
+/*
+ * print directions above move box
+ */
+printtopinstructions()
+{
+ move(tboxrow, boxcol);
+ printw("*----------------------------------*");
+ move(tboxrow + 1, boxcol);
+ printw("| MOVES |");
+ 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("|b = present betting information |");
+ move(tboxrow + 11, boxcol);
+ printw("|q = quit to end the game |");
+ move(tboxrow + 12, boxcol);
+ printw("|==================================|");
+}
+
+/*
+ * Print the betting box.
+ */
+printtopbettingbox()
+{
+
+ move(tboxrow, boxcol);
+ printw("*----------------------------------*");
+ move(tboxrow + 1, boxcol);
+ printw("|Costs Hand Game Total |");
+ move(tboxrow + 2, boxcol);
+ printw("| Hands |");
+ move(tboxrow + 3, boxcol);
+ printw("| Inspections |");
+ move(tboxrow + 4, boxcol);
+ printw("| Games |");
+ move(tboxrow + 5, boxcol);
+ printw("| Runs |");
+ move(tboxrow + 6, boxcol);
+ printw("| Information |");
+ move(tboxrow + 7, boxcol);
+ printw("| Think time |");
+ move(tboxrow + 8, boxcol);
+ printw("|Total Costs |");
+ move(tboxrow + 9, boxcol);
+ printw("|Winnings |");
+ move(tboxrow + 10, boxcol);
+ printw("|Net Worth |");
+ move(tboxrow + 11, boxcol);
+ printw("|Return |");
+ move(tboxrow + 12, boxcol);
+ printw("|==================================|");
+}
+
+/*
+ * clear info above move box
+ */
+clearabovemovebox()
+{
+ int i;
+
+ for (i = 0; i <= 11; i++) {
+ move(tboxrow + i, boxcol);
+ printw(" ");
+ }
+ move(tboxrow + 12, boxcol);
+ printw("*----------------------------------*");
+}
+
+/*
+ * print instructions below move box
+ */
+printbottominstructions()
+{
+ move(bboxrow, boxcol);
+ printw("|Replace # with the number of the |");
+ move(bboxrow + 1, boxcol);
+ printw("|tableau you want. |");
+ move(bboxrow + 2, boxcol);
+ printw("*----------------------------------*");
+}
+
+/*
+ * print betting information below move box
+ */
+printbottombettingbox()
+{
+ move(bboxrow, boxcol);
+ printw("|x = toggle information box |");
+ move(bboxrow + 1, boxcol);
+ printw("|i = list playing instructions |");
+ move(bboxrow + 2, boxcol);
+ printw("*----------------------------------*");
+}
+
+/*
+ * clear info below move box
+ */
+clearbelowmovebox()
+{
+ int i;
+
+ move(bboxrow, boxcol);
+ printw("*----------------------------------*");
+ for (i = 1; i <= 2; i++) {
+ move(bboxrow + i, boxcol);
+ printw(" ");
+ }
+}
+
+/*
+ * procedure to put the board on the screen using addressable cursor
+ */
+makeboard()
+{
+ clear();
+ refresh();
+ move(titlerow, titlecol);
+ printw("=-> CANFIELD <-=");
+ move(fttlrow, fttlcol);
+ printw("foundation");
+ move(foundrow - 1, fttlcol);
+ printw("=---= =---= =---= =---=");
+ move(foundrow, fttlcol);
+ printw("| | | | | | | |");
+ move(foundrow + 1, fttlcol);
+ printw("=---= =---= =---= =---=");
+ move(ottlrow, sidecol);
+ printw("stock tableau");
+ move(stockrow - 1, sidecol);
+ printw("=---=");
+ move(stockrow, sidecol);
+ printw("| |");
+ move(stockrow + 1, sidecol);
+ printw("=---=");
+ move(talonrow - 2, sidecol);
+ printw("talon");
+ move(talonrow - 1, sidecol);
+ printw("=---=");
+ move(talonrow, sidecol);
+ printw("| |");
+ move(talonrow + 1, sidecol);
+ printw("=---=");
+ move(tabrow - 1, atabcol);
+ printw("-1- -2- -3- -4-");
+ movebox();
+}
+
+/*
+ * clean up the board for another game
+ */
+cleanupboard()
+{
+ int cnt, row, col;
+ struct cardtype *ptr;
+
+ if (Cflag) {
+ clearstat();
+ for(ptr = stock, row = stockrow;
+ ptr != NIL;
+ ptr = ptr->next, row++) {
+ move(row, sidecol);
+ printw(" ");
+ }
+ move(row, sidecol);
+ printw(" ");
+ move(stockrow + 1, sidecol);
+ printw("=---=");
+ move(talonrow - 2, sidecol);
+ printw("talon");
+ move(talonrow - 1, sidecol);
+ printw("=---=");
+ move(talonrow + 1, sidecol);
+ printw("=---=");
+ }
+ move(stockrow, sidecol);
+ printw("| |");
+ move(talonrow, sidecol);
+ printw("| |");
+ move(foundrow, fttlcol);
+ printw("| | | | | | | |");
+ for (cnt = 0; cnt < 4; cnt++) {
+ switch(cnt) {
+ case 0:
+ col = atabcol;
+ break;
+ case 1:
+ col = btabcol;
+ break;
+ case 2:
+ col = ctabcol;
+ break;
+ case 3:
+ col = dtabcol;
+ break;
+ }
+ for(ptr = tableau[cnt], row = tabrow;
+ ptr != NIL;
+ ptr = ptr->next, row++)
+ removecard(col, row);
+ }
+}
+
+/*
+ * procedure to create a deck of cards
+ */
+initdeck(deck)
+ struct cardtype *deck[];
+{
+ int i;
+ int scnt;
+ char s;
+ int r;
+
+ i = 0;
+ for (scnt=0; scnt<4; scnt++) {
+ s = suitmap[scnt];
+ for (r=Ace; r<=King; r++) {
+ deck[i] = &cards[i];
+ cards[i].rank = r;
+ cards[i].suit = s;
+ cards[i].color = colormap[scnt];
+ cards[i].next = NIL;
+ i++;
+ }
+ }
+}
+
+/*
+ * procedure to shuffle the deck
+ */
+shuffle(deck)
+ struct cardtype *deck[];
+{
+ int i,j;
+ struct cardtype *temp;
+
+ for (i=0; i<decksize; i++) {
+ deck[i]->visible = FALSE;
+ deck[i]->paid = FALSE;
+ }
+ for (i = decksize-1; i>=0; i--) {
+ j = random() % decksize;
+ if (i != j) {
+ temp = deck[i];
+ deck[i] = deck[j];
+ deck[j] = temp;
+ }
+ }
+}
+
+/*
+ * procedure to remove the card from the board
+ */
+removecard(a, b)
+{
+ move(b, a);
+ printw(" ");
+}
+
+/*
+ * procedure to print the cards on the board
+ */
+printrank(a, b, cp, inverse)
+ struct cardtype *cp;
+ bool inverse;
+{
+ move(b, a);
+ if (cp->rank != 10)
+ addch(' ');
+ if (inverse)
+ standout();
+ switch (cp->rank) {
+ case 2: case 3: case 4: case 5: case 6: case 7:
+ case 8: case 9: case 10:
+ printw("%d", cp->rank);
+ break;
+ case Ace:
+ addch('A');
+ break;
+ case Jack:
+ addch('J');
+ break;
+ case Queen:
+ addch('Q');
+ break;
+ case King:
+ addch('K');
+ }
+ if (inverse)
+ standend();
+}
+
+/*
+ * procedure to print out a card
+ */
+printcard(a, b, cp)
+ int a,b;
+ struct cardtype *cp;
+{
+ if (cp == NIL)
+ removecard(a, b);
+ else if (cp->visible == FALSE) {
+ move(b, a);
+ printw(" ? ");
+ } else {
+ bool inverse = (cp->suit == 'd' || cp->suit == 'h');
+
+ printrank(a, b, cp, inverse);
+ if (inverse)
+ standout();
+ addch(cp->suit);
+ if (inverse)
+ standend();
+ }
+}
+
+/*
+ * procedure to move the top card from one location to the top
+ * of another location. The pointers always point to the top
+ * of the piles.
+ */
+transit(source, dest)
+ struct cardtype **source, **dest;
+{
+ struct cardtype *temp;
+
+ temp = *source;
+ *source = (*source)->next;
+ temp->next = *dest;
+ *dest = temp;
+}
+
+/*
+ * 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.
+ */
+fndbase(cp, column, row)
+ struct cardtype **cp;
+{
+ bool nomore;
+
+ if (*cp != NIL)
+ do {
+ if ((*cp)->rank == basecard->rank) {
+ base++;
+ printcard(pilemap[base], foundrow, *cp);
+ if (*cp == tableau[0])
+ length[0] = length[0] - 1;
+ if (*cp == tableau[1])
+ length[1] = length[1] - 1;
+ if (*cp == tableau[2])
+ length[2] = length[2] - 1;
+ if (*cp == tableau[3])
+ length[3] = length[3] - 1;
+ transit(cp, &found[base]);
+ if (cp == &talon)
+ usedtalon();
+ if (cp == &stock)
+ usedstock();
+ if (*cp != NIL) {
+ printcard(column, row, *cp);
+ nomore = FALSE;
+ } else {
+ removecard(column, row);
+ nomore = TRUE;
+ }
+ cardsoff++;
+ if (infullgame) {
+ this.wins += valuepercardup;
+ game.wins += valuepercardup;
+ total.wins += valuepercardup;
+ }
+ } else
+ nomore = TRUE;
+ } while (nomore == FALSE);
+}
+
+/*
+ * procedure to initialize the things necessary for the game
+ */
+initgame()
+{
+ register i;
+
+ for (i=0; i<18; i++) {
+ deck[i]->visible = TRUE;
+ deck[i]->paid = TRUE;
+ }
+ stockcnt = 13;
+ stock = deck[12];
+ for (i=12; i>=1; i--)
+ deck[i]->next = deck[i - 1];
+ deck[0]->next = NIL;
+ found[0] = deck[13];
+ deck[13]->next = NIL;
+ for (i=1; i<4; i++)
+ found[i] = NIL;
+ basecard = found[0];
+ for (i=14; i<18; i++) {
+ tableau[i - 14] = deck[i];
+ deck[i]->next = NIL;
+ }
+ for (i=0; i<4; i++) {
+ bottom[i] = tableau[i];
+ length[i] = tabrow;
+ }
+ hand = deck[18];
+ for (i=18; i<decksize-1; i++)
+ deck[i]->next = deck[i + 1];
+ deck[decksize-1]->next = NIL;
+ talon = NIL;
+ base = 0;
+ cinhand = 34;
+ taloncnt = 0;
+ timesthru = 0;
+ cardsoff = 1;
+ coldrow = ctoprow;
+ coldcol = cinitcol;
+ cnewrow = ctoprow;
+ cnewcol = cinitcol + cwidthcol;
+}
+
+/*
+ * procedure to print the beginning cards and to start each game
+ */
+startgame()
+{
+ register int j;
+
+ shuffle(deck);
+ initgame();
+ this.hand = costofhand;
+ game.hand += costofhand;
+ total.hand += costofhand;
+ this.inspection = 0;
+ this.game = 0;
+ this.runs = 0;
+ this.information = 0;
+ this.wins = 0;
+ this.thinktime = 0;
+ infullgame = FALSE;
+ startedgame = FALSE;
+ 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);
+ printw("Base");
+ move(foundrow - 1, basecol);
+ printw("Rank");
+ printrank(basecol, foundrow, found[0], 0);
+ for (j=0; j<=3; j++)
+ fndbase(&tableau[j], pilemap[j], tabrow);
+ fndbase(&stock, stockcol, stockrow);
+ showstat(); /* show card counting info to cheaters */
+ movetotalon();
+ updatebettinginfo();
+}
+
+/*
+ * procedure to clear the message printed from an error
+ */
+clearmsg()
+{
+ int i;
+
+ if (errmsg == TRUE) {
+ errmsg = FALSE;
+ move(msgrow, msgcol);
+ for (i=0; i<25; i++)
+ addch(' ');
+ refresh();
+ }
+}
+
+/*
+ * procedure to print an error message if the move is not listed
+ */
+dumberror()
+{
+ errmsg = TRUE;
+ move(msgrow, msgcol);
+ printw("Not a proper move ");
+}
+
+/*
+ * procedure to print an error message if the move is not possible
+ */
+destinerror()
+{
+ errmsg = TRUE;
+ move(msgrow, msgcol);
+ printw("Error: Can't move there");
+}
+
+/*
+ * function to see if the source has cards in it
+ */
+bool
+notempty(cp)
+struct cardtype *cp;
+{
+ if (cp == NIL) {
+ errmsg = TRUE;
+ move(msgrow, msgcol);
+ printw("Error: no cards to move");
+ return (FALSE);
+ } else
+ return (TRUE);
+}
+
+/*
+ * function to see if the rank of one card is less than another
+ */
+bool
+ranklower(cp1, cp2)
+ struct cardtype *cp1, *cp2;
+{
+ if (cp2->rank == Ace)
+ if (cp1->rank == King)
+ return (TRUE);
+ else
+ return (FALSE);
+ else if (cp1->rank + 1 == cp2->rank)
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
+/*
+ * function to check the cardcolor for moving to a tableau
+ */
+bool
+diffcolor(cp1, cp2)
+ struct cardtype *cp1, *cp2;
+{
+ if (cp1->color == cp2->color)
+ return (FALSE);
+ else
+ return (TRUE);
+}
+
+/*
+ * function to see if the card can move to the tableau
+ */
+bool
+tabok(cp, des)
+ struct cardtype *cp;
+{
+ if ((cp == stock) && (tableau[des] == NIL))
+ return (TRUE);
+ else if (tableau[des] == NIL)
+ if (stock == NIL &&
+ cp != bottom[0] && cp != bottom[1] &&
+ cp != bottom[2] && cp != bottom[3])
+ return (TRUE);
+ else
+ return (FALSE);
+ else if (ranklower(cp, tableau[des]) && diffcolor(cp, tableau[des]))
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
+/*
+ * procedure to turn the cards onto the talon from the deck
+ */
+movetotalon()
+{
+ int i, fin;
+
+ if (cinhand <= 3 && cinhand > 0) {
+ move(msgrow, msgcol);
+ printw("Hand is now empty ");
+ }
+ if (cinhand >= 3)
+ fin = 3;
+ else if (cinhand > 0)
+ fin = cinhand;
+ else if (talon != NIL) {
+ timesthru++;
+ errmsg = TRUE;
+ move(msgrow, msgcol);
+ if (timesthru != 4) {
+ printw("Talon is now the new hand");
+ this.runs += costofrunthroughhand;
+ game.runs += costofrunthroughhand;
+ total.runs += costofrunthroughhand;
+ while (talon != NIL) {
+ transit(&talon, &hand);
+ cinhand++;
+ }
+ if (cinhand >= 3)
+ fin = 3;
+ else
+ fin = cinhand;
+ taloncnt = 0;
+ coldrow = ctoprow;
+ coldcol = cinitcol;
+ cnewrow = ctoprow;
+ cnewcol = cinitcol + cwidthcol;
+ clearstat();
+ showstat();
+ } else {
+ fin = 0;
+ done = TRUE;
+ printw("I believe you have lost");
+ refresh();
+ sleep(5);
+ }
+ } else {
+ errmsg = TRUE;
+ move(msgrow, msgcol);
+ printw("Talon and hand are empty");
+ fin = 0;
+ }
+ for (i=0; i<fin; i++) {
+ transit(&hand, &talon);
+ INCRHAND(cnewrow, cnewcol);
+ INCRHAND(coldrow, coldcol);
+ removecard(cnewcol, cnewrow);
+ if (i == fin - 1)
+ talon->visible = TRUE;
+ if (Cflag) {
+ if (talon->paid == FALSE && talon->visible == TRUE) {
+ this.information += costofinformation;
+ game.information += costofinformation;
+ total.information += costofinformation;
+ talon->paid = TRUE;
+ }
+ printcard(coldcol, coldrow, talon);
+ }
+ }
+ if (fin != 0) {
+ printcard(taloncol, talonrow, talon);
+ cinhand -= fin;
+ taloncnt += fin;
+ if (Cflag) {
+ move(handstatrow, handstatcol);
+ printw("%3d", cinhand);
+ move(talonstatrow, talonstatcol);
+ printw("%3d", taloncnt);
+ }
+ fndbase(&talon, taloncol, talonrow);
+ }
+}
+
+
+/*
+ * procedure to print card counting info on screen
+ */
+showstat()
+{
+ int row, col;
+ register struct cardtype *ptr;
+
+ if (!Cflag)
+ return;
+ 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;
+ ptr != NIL;
+ ptr = ptr->next ) {
+ if (ptr->paid == FALSE && ptr->visible == TRUE) {
+ ptr->paid = TRUE;
+ this.information += costofinformation;
+ game.information += costofinformation;
+ total.information += costofinformation;
+ }
+ printcard(col, row, ptr);
+ DECRHAND(row, col);
+ }
+ for ( row = cnewrow, col = cnewcol, ptr = hand;
+ ptr != NIL;
+ ptr = ptr->next ) {
+ if (ptr->paid == FALSE && ptr->visible == TRUE) {
+ ptr->paid = TRUE;
+ this.information += costofinformation;
+ game.information += costofinformation;
+ total.information += costofinformation;
+ }
+ INCRHAND(row, col);
+ printcard(col, row, ptr);
+ }
+}
+
+/*
+ * procedure to clear card counting info from screen
+ */
+clearstat()
+{
+ int row;
+
+ move(talonstatrow, talonstatcol - 7);
+ printw(" ");
+ move(handstatrow, handstatcol - 7);
+ printw(" ");
+ move(stockstatrow, stockstatcol - 7);
+ printw(" ");
+ for ( row = ctoprow ; row <= cbotrow ; row++ ) {
+ move(row, cinitcol);
+ printw("%56s", " ");
+ }
+}
+
+/*
+ * procedure to update card counting base
+ */
+usedtalon()
+{
+ removecard(coldcol, coldrow);
+ DECRHAND(coldrow, coldcol);
+ if (talon != NIL && (talon->visible == FALSE)) {
+ talon->visible = TRUE;
+ if (Cflag) {
+ this.information += costofinformation;
+ game.information += costofinformation;
+ total.information += costofinformation;
+ talon->paid = TRUE;
+ printcard(coldcol, coldrow, talon);
+ }
+ }
+ taloncnt--;
+ if (Cflag) {
+ move(talonstatrow, talonstatcol);
+ printw("%3d", taloncnt);
+ }
+}
+
+/*
+ * procedure to update stock card counting base
+ */
+usedstock()
+{
+ stockcnt--;
+ if (Cflag) {
+ move(stockstatrow, stockstatcol);
+ printw("%3d", stockcnt);
+ }
+}
+
+/*
+ * let 'em know how they lost!
+ */
+showcards()
+{
+ register struct cardtype *ptr;
+ int row;
+
+ if (!Cflag || cardsoff == 52)
+ return;
+ for (ptr = talon; ptr != NIL; ptr = ptr->next) {
+ ptr->visible = TRUE;
+ ptr->paid = TRUE;
+ }
+ for (ptr = hand; ptr != NIL; ptr = ptr->next) {
+ ptr->visible = TRUE;
+ ptr->paid = TRUE;
+ }
+ showstat();
+ move(stockrow + 1, sidecol);
+ printw(" ");
+ move(talonrow - 2, sidecol);
+ printw(" ");
+ move(talonrow - 1, sidecol);
+ printw(" ");
+ move(talonrow, sidecol);
+ printw(" ");
+ move(talonrow + 1, sidecol);
+ printw(" ");
+ for (ptr = stock, row = stockrow; ptr != NIL; ptr = ptr->next, row++) {
+ move(row, stockcol - 1);
+ printw("| |");
+ printcard(stockcol, row, ptr);
+ }
+ if (stock == NIL) {
+ move(row, stockcol - 1);
+ printw("| |");
+ row++;
+ }
+ move(handstatrow, handstatcol - 7);
+ printw(" ");
+ move(row, stockcol - 1);
+ printw("=---=");
+ if ( cardsoff == 52 )
+ getcmd(moverow, movecol, "Hit return to exit");
+}
+
+/*
+ * procedure to update the betting values
+ */
+updatebettinginfo()
+{
+ long thiscosts, gamecosts, totalcosts;
+ double thisreturn, gamereturn, totalreturn;
+ time_t now;
+ register long dollars;
+
+ time(&now);
+ dollars = (now - acctstart) / secondsperdollar;
+ if (dollars > 0) {
+ acctstart += dollars * secondsperdollar;
+ if (dollars > maxtimecharge)
+ dollars = maxtimecharge;
+ this.thinktime += dollars;
+ game.thinktime += dollars;
+ total.thinktime += dollars;
+ }
+ thiscosts = this.hand + this.inspection + this.game +
+ this.runs + this.information + this.thinktime;
+ gamecosts = game.hand + game.inspection + game.game +
+ game.runs + game.information + game.thinktime;
+ totalcosts = total.hand + total.inspection + total.game +
+ total.runs + total.information + total.thinktime;
+ this.worth = this.wins - thiscosts;
+ game.worth = game.wins - gamecosts;
+ total.worth = total.wins - totalcosts;
+ thisreturn = ((double)this.wins / (double)thiscosts - 1.0) * 100.0;
+ gamereturn = ((double)game.wins / (double)gamecosts - 1.0) * 100.0;
+ totalreturn = ((double)total.wins / (double)totalcosts - 1.0) * 100.0;
+ if (status != BETTINGBOX)
+ return;
+ move(tboxrow + 2, boxcol + 13);
+ printw("%4d%8d%9d", this.hand, game.hand, total.hand);
+ move(tboxrow + 3, boxcol + 13);
+ printw("%4d%8d%9d", this.inspection, game.inspection, total.inspection);
+ move(tboxrow + 4, boxcol + 13);
+ printw("%4d%8d%9d", this.game, game.game, total.game);
+ move(tboxrow + 5, boxcol + 13);
+ printw("%4d%8d%9d", this.runs, game.runs, total.runs);
+ move(tboxrow + 6, boxcol + 13);
+ printw("%4d%8d%9d", this.information, game.information,
+ total.information);
+ move(tboxrow + 7, boxcol + 13);
+ printw("%4d%8d%9d", this.thinktime, game.thinktime, total.thinktime);
+ move(tboxrow + 8, boxcol + 13);
+ printw("%4d%8d%9d", thiscosts, gamecosts, totalcosts);
+ move(tboxrow + 9, boxcol + 13);
+ printw("%4d%8d%9d", this.wins, game.wins, total.wins);
+ move(tboxrow + 10, boxcol + 13);
+ printw("%4d%8d%9d", this.worth, game.worth, total.worth);
+ move(tboxrow + 11, boxcol + 13);
+ printw("%4.0f%%%7.1f%%%8.1f%%", thisreturn, gamereturn, totalreturn);
+}
+
+/*
+ * procedure to move a card from the stock or talon to the tableau
+ */
+simpletableau(cp, des)
+struct cardtype **cp;
+{
+ int origin;
+
+ if (notempty(*cp)) {
+ if (tabok(*cp, des)) {
+ if (*cp == stock)
+ origin = stk;
+ else
+ origin = tal;
+ if (tableau[des] == NIL)
+ bottom[des] = *cp;
+ transit(cp, &tableau[des]);
+ length[des]++;
+ printcard(pilemap[des], length[des], tableau[des]);
+ timesthru = 0;
+ if (origin == stk) {
+ usedstock();
+ printcard(stockcol, stockrow, stock);
+ } else {
+ usedtalon();
+ printcard(taloncol, talonrow, talon);
+ }
+ } else
+ destinerror();
+ }
+}
+
+/*
+ * print the tableau
+ */
+tabprint(sour, des)
+{
+ int dlength, slength, i;
+ struct cardtype *tempcard;
+
+ for (i=tabrow; i<=length[sour]; i++)
+ removecard(pilemap[sour], i);
+ dlength = length[des] + 1;
+ slength = length[sour];
+ if (slength == tabrow)
+ printcard(pilemap[des], dlength, tableau[sour]);
+ else
+ while (slength != tabrow - 1) {
+ tempcard = tableau[sour];
+ for (i=1; i<=slength-tabrow; i++)
+ tempcard = tempcard->next;
+ printcard(pilemap[des], dlength, tempcard);
+ slength--;
+ dlength++;
+ }
+}
+
+/*
+ * procedure to move from the tableau to the tableau
+ */
+tabtotab(sour, des)
+ register int sour, des;
+{
+ struct cardtype *temp;
+
+ if (notempty(tableau[sour])) {
+ if (tabok(bottom[sour], des)) {
+ tabprint(sour, des);
+ temp = bottom[sour];
+ bottom[sour] = NIL;
+ if (bottom[des] == NIL)
+ bottom[des] = temp;
+ temp->next = tableau[des];
+ tableau[des] = tableau[sour];
+ tableau[sour] = NIL;
+ length[des] = length[des] + (length[sour] - (tabrow - 1));
+ length[sour] = tabrow - 1;
+ timesthru = 0;
+ } else
+ destinerror();
+ }
+}
+
+/*
+ * functions to see if the card can go onto the foundation
+ */
+bool
+rankhigher(cp, let)
+ struct cardtype *cp;
+{
+ if (found[let]->rank == King)
+ if (cp->rank == Ace)
+ return(TRUE);
+ else
+ return(FALSE);
+ else if (cp->rank - 1 == found[let]->rank)
+ return(TRUE);
+ else
+ return(FALSE);
+}
+
+/*
+ * function to determine if two cards are the same suit
+ */
+samesuit(cp, let)
+ struct cardtype *cp;
+{
+ if (cp->suit == found[let]->suit)
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
+/*
+ * procedure to move a card to the correct foundation pile
+ */
+movetofound(cp, source)
+ struct cardtype **cp;
+{
+ tempbase = 0;
+ mtfdone = FALSE;
+ if (notempty(*cp)) {
+ do {
+ if (found[tempbase] != NIL)
+ if (rankhigher(*cp, tempbase)
+ && samesuit(*cp, tempbase)) {
+ if (*cp == stock)
+ mtforigin = stk;
+ else if (*cp == talon)
+ mtforigin = tal;
+ else
+ mtforigin = tab;
+ transit(cp, &found[tempbase]);
+ printcard(pilemap[tempbase],
+ foundrow, found[tempbase]);
+ timesthru = 0;
+ if (mtforigin == stk) {
+ usedstock();
+ printcard(stockcol, stockrow, stock);
+ } else if (mtforigin == tal) {
+ usedtalon();
+ printcard(taloncol, talonrow, talon);
+ } else {
+ removecard(pilemap[source], length[source]);
+ length[source]--;
+ }
+ cardsoff++;
+ if (infullgame) {
+ this.wins += valuepercardup;
+ game.wins += valuepercardup;
+ total.wins += valuepercardup;
+ }
+ mtfdone = TRUE;
+ } else
+ tempbase++;
+ else
+ tempbase++;
+ } while ((tempbase != 4) && !mtfdone);
+ if (!mtfdone)
+ destinerror();
+ }
+}
+
+/*
+ * procedure to get a command
+ */
+getcmd(row, col, cp)
+ int row, col;
+ char *cp;
+{
+ char cmd[2] = { '\0', '\0'}, ch;
+ int i;
+
+ i = 0;
+ move(row, col);
+ printw("%-24s", cp);
+ col += 1 + strlen(cp);
+ move(row, col);
+ refresh();
+ do {
+ ch = getch() & 0177;
+ if (ch >= 'A' && ch <= 'Z')
+ ch += ('a' - 'A');
+ if (ch == '\f') {
+ wrefresh(curscr);
+ refresh();
+ } else if (i >= 2 && ch != erasechar() && ch != killchar()) {
+ if (ch != '\n' && ch != '\r' && ch != ' ')
+ write(1, "\007", 1);
+ } else if (ch == erasechar() && i > 0) {
+ printw("\b \b");
+ refresh();
+ cmd[--i] = '\0';
+ } else if (ch == killchar() && i > 0) {
+ while (i > 0) {
+ printw("\b \b");
+ cmd[--i] = '\0';
+ }
+ refresh();
+ } else if (ch == '\032') { /* Control-Z */
+ suspend();
+ move(row, col + i);
+ refresh();
+ } else if (isprint(ch)) {
+ cmd[i++] = ch;
+ addch(ch);
+ refresh();
+ }
+ } while (ch != '\n' && ch != '\r' && ch != ' ');
+ srcpile = cmd[0];
+ destpile = cmd[1];
+}
+
+/*
+ * Suspend the game (shell escape if no process control on system)
+ */
+suspend()
+{
+#ifndef SIGTSTP
+ char *sh;
+#endif
+
+ updatebettinginfo();
+ move(21, 0);
+ refresh();
+ if (dbfd != -1) {
+ lseek(dbfd, uid * sizeof(struct betinfo), 0);
+ write(dbfd, (char *)&total, sizeof(total));
+ }
+ kill(getpid(), SIGTSTP);
+ raw();
+ noecho();
+}
+
+/*
+ * procedure to evaluate and make the specific moves
+ */
+movecard()
+{
+ int source, dest;
+ char osrcpile, odestpile;
+
+ done = FALSE;
+ errmsg = FALSE;
+ do {
+ if (talon == NIL && hand != NIL)
+ movetotalon();
+ if (cardsoff == 52) {
+ refresh();
+ srcpile = 'q';
+ } else if (!startedgame) {
+ move(msgrow, msgcol);
+ errmsg = TRUE;
+ switch (34 - taloncnt - cinhand) {
+ default:
+ errmsg = FALSE;
+ break;
+ case 1:
+ printw("One card used from talon ");
+ break;
+ case 2:
+ printw("Two cards used from talon ");
+ break;
+ case 3:
+ printw(">3< cards used from talon ");
+ break;
+ }
+ getcmd(moverow, movecol, "Move:");
+ } else
+ getcmd(moverow, movecol, "Move:");
+ clearmsg();
+ if (srcpile >= '1' && srcpile <= '4')
+ source = (int) (srcpile - '1');
+ if (destpile >= '1' && destpile <= '4')
+ dest = (int) (destpile - '1');
+ if (!startedgame &&
+ (srcpile == 't' || srcpile == 's' || srcpile == 'h' ||
+ srcpile == '1' || srcpile == '2' || srcpile == '3' ||
+ srcpile == '4')) {
+ startedgame = TRUE;
+ osrcpile = srcpile;
+ odestpile = destpile;
+ if (status != BETTINGBOX)
+ srcpile = 'y';
+ else do {
+ getcmd(moverow, movecol, "Inspect game?");
+ } while (srcpile != 'y' && srcpile != 'n');
+ if (srcpile == 'n') {
+ srcpile = 'q';
+ } else {
+ this.inspection += costofinspection;
+ game.inspection += costofinspection;
+ total.inspection += costofinspection;
+ srcpile = osrcpile;
+ destpile = odestpile;
+ }
+ }
+ switch (srcpile) {
+ case 't':
+ if (destpile == 'f' || destpile == 'F')
+ movetofound(&talon, source);
+ else if (destpile >= '1' && destpile <= '4')
+ simpletableau(&talon, dest);
+ else
+ dumberror();
+ break;
+ case 's':
+ if (destpile == 'f' || destpile == 'F')
+ movetofound(&stock, source);
+ else if (destpile >= '1' && destpile <= '4')
+ simpletableau(&stock, dest);
+ else dumberror();
+ break;
+ case 'h':
+ if (destpile != 't' && destpile != 'T') {
+ dumberror();
+ break;
+ }
+ if (infullgame) {
+ movetotalon();
+ break;
+ }
+ if (status == BETTINGBOX) {
+ do {
+ getcmd(moverow, movecol,
+ "Buy game?");
+ } while (srcpile != 'y' &&
+ srcpile != 'n');
+ if (srcpile == 'n') {
+ showcards();
+ done = TRUE;
+ break;
+ }
+ }
+ infullgame = TRUE;
+ this.wins += valuepercardup * cardsoff;
+ game.wins += valuepercardup * cardsoff;
+ total.wins += valuepercardup * cardsoff;
+ this.game += costofgame;
+ game.game += costofgame;
+ total.game += costofgame;
+ movetotalon();
+ break;
+ case 'q':
+ showcards();
+ done = TRUE;
+ break;
+ case 'b':
+ printtopbettingbox();
+ printbottombettingbox();
+ status = BETTINGBOX;
+ break;
+ case 'x':
+ clearabovemovebox();
+ clearbelowmovebox();
+ status = NOBOX;
+ break;
+ case 'i':
+ printtopinstructions();
+ printbottominstructions();
+ status = INSTRUCTIONBOX;
+ break;
+ case 'c':
+ Cflag = !Cflag;
+ if (Cflag)
+ showstat();
+ else
+ clearstat();
+ break;
+ case '1': case '2': case '3': case '4':
+ if (destpile == 'f' || destpile == 'F')
+ movetofound(&tableau[source], source);
+ else if (destpile >= '1' && destpile <= '4')
+ tabtotab(source, dest);
+ else dumberror();
+ break;
+ default:
+ dumberror();
+ }
+ fndbase(&stock, stockcol, stockrow);
+ fndbase(&talon, taloncol, talonrow);
+ updatebettinginfo();
+ } while (!done);
+}
+
+char *basicinstructions[] = {
+ "Here are brief instuctions to the game of Canfield:\n\n",
+ " If you have never played solitaire before, it is recom-\n",
+ "mended that you consult a solitaire instruction book. In\n",
+ "Canfield, tableau cards may be built on each other downward\n",
+ "in alternate colors. An entire pile must be moved as a unit\n",
+ "in building. Top cards of the piles are available to be able\n",
+ "to be played on foundations, but never into empty spaces.\n\n",
+ " Spaces must be filled from the stock. The top card of\n",
+ "the stock also is available to be played on foundations or\n",
+ "built on tableau piles. After the stock is exhausted, ta-\n",
+ "bleau spaces may be filled from the talon and the player may\n",
+ "keep them open until he wishes to use them.\n\n",
+ " Cards are dealt from the hand to the talon by threes\n",
+ "and this repeats until there are no more cards in the hand\n",
+ "or the player quits. To have cards dealt onto the talon the\n",
+ "player types 'ht' for his move. Foundation base cards are\n",
+ "also automatically moved to the foundation when they become\n",
+ "available.\n\n",
+ "push any key when you are finished: ",
+ 0 };
+
+char *bettinginstructions[] = {
+ " The rules for betting are somewhat less strict than\n",
+ "those used in the official version of the game. The initial\n",
+ "deal costs $13. You may quit at this point or inspect the\n",
+ "game. Inspection costs $13 and allows you to make as many\n",
+ "moves as is possible without moving any cards from your hand\n",
+ "to the talon. (the initial deal places three cards on the\n",
+ "talon; if all these cards are used, three more are made\n",
+ "available) Finally, if the game seems interesting, you must\n",
+ "pay the final installment of $26. At this point you are\n",
+ "credited at the rate of $5 for each card on the foundation;\n",
+ "as the game progresses you are credited with $5 for each\n",
+ "card that is moved to the foundation. Each run through the\n",
+ "hand after the first costs $5. The card counting feature\n",
+ "costs $1 for each unknown card that is identified. If the\n",
+ "information is toggled on, you are only charged for cards\n",
+ "that became visible since it was last turned on. Thus the\n",
+ "maximum cost of information is $34. Playing time is charged\n",
+ "at a rate of $1 per minute.\n\n",
+ "push any key when you are finished: ",
+ 0 };
+
+/*
+ * procedure to printout instructions
+ */
+instruct()
+{
+ register char **cp;
+
+ move(originrow, origincol);
+ printw("This is the game of solitaire called Canfield. Do\n");
+ printw("you want instructions for the game?");
+ do {
+ getcmd(originrow + 3, origincol, "y or n?");
+ } while (srcpile != 'y' && srcpile != 'n');
+ if (srcpile == 'n')
+ return;
+ clear();
+ for (cp = basicinstructions; *cp != 0; cp++)
+ printw(*cp);
+ refresh();
+ getch();
+ clear();
+ move(originrow, origincol);
+ printw("Do you want instructions for betting?");
+ do {
+ getcmd(originrow + 2, origincol, "y or n?");
+ } while (srcpile != 'y' && srcpile != 'n');
+ if (srcpile == 'n')
+ return;
+ clear();
+ for (cp = bettinginstructions; *cp != 0; cp++)
+ printw(*cp);
+ refresh();
+ getch();
+}
+
+/*
+ * procedure to initialize the game
+ */
+initall()
+{
+ int i;
+
+ srandom(getpid());
+ time(&acctstart);
+ initdeck(deck);
+ uid = getuid();
+ if (uid < 0)
+ uid = 0;
+ dbfd = open(_PATH_SCORE, 2);
+ if (dbfd < 0)
+ return;
+ i = lseek(dbfd, uid * sizeof(struct betinfo), 0);
+ if (i < 0) {
+ close(dbfd);
+ dbfd = -1;
+ return;
+ }
+ i = read(dbfd, (char *)&total, sizeof(total));
+ if (i < 0) {
+ close(dbfd);
+ dbfd = -1;
+ return;
+ }
+}
+
+/*
+ * procedure to end the game
+ */
+bool
+finish()
+{
+ int row, col;
+
+ if (cardsoff == 52) {
+ getcmd(moverow, movecol, "Hit return to exit");
+ clear();
+ refresh();
+ move(originrow, origincol);
+ printw("CONGRATULATIONS!\n");
+ printw("You won the game. That is a feat to be proud of.\n");
+ row = originrow + 5;
+ col = origincol;
+ } else {
+ move(msgrow, msgcol);
+ printw("You got %d card", cardsoff);
+ if (cardsoff > 1)
+ printw("s");
+ printw(" off ");
+ move(msgrow, msgcol);
+ row = moverow;
+ col = movecol;
+ }
+ do {
+ getcmd(row, col, "Play again (y or n)?");
+ } while (srcpile != 'y' && srcpile != 'n');
+ errmsg = TRUE;
+ clearmsg();
+ if (srcpile == 'y')
+ return (FALSE);
+ else
+ return (TRUE);
+}
+
+/*
+ * procedure to clean up and exit
+ */
+void
+cleanup()
+{
+
+ total.thinktime += 1;
+ status = NOBOX;
+ updatebettinginfo();
+ if (dbfd != -1) {
+ lseek(dbfd, uid * sizeof(struct betinfo), 0);
+ write(dbfd, (char *)&total, sizeof(total));
+ close(dbfd);
+ }
+ clear();
+ move(22,0);
+ refresh();
+ endwin();
+ exit(0);
+ /* NOTREACHED */
+}
+
+/*
+ * Field an interrupt.
+ */
+void
+askquit()
+{
+ move(msgrow, msgcol);
+ printw("Really wish to quit? ");
+ do {
+ getcmd(moverow, movecol, "y or n?");
+ } while (srcpile != 'y' && srcpile != 'n');
+ clearmsg();
+ if (srcpile == 'y')
+ cleanup();
+ signal(SIGINT, askquit);
+}
+
+/*
+ * Can you tell that this used to be a Pascal program?
+ */
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#ifdef MAXLOAD
+ double vec[3];
+
+ loadav(vec);
+ if (vec[2] >= MAXLOAD) {
+ puts("The system load is too high. Try again later.");
+ exit(0);
+ }
+#endif
+ signal(SIGINT, askquit);
+ signal(SIGHUP, cleanup);
+ signal(SIGTERM, cleanup);
+ initscr();
+ raw();
+ noecho();
+ initall();
+ instruct();
+ makeboard();
+ for (;;) {
+ startgame();
+ movecard();
+ if (finish())
+ break;
+ if (cardsoff == 52)
+ makeboard();
+ else
+ cleanupboard();
+ }
+ cleanup();
+ /* NOTREACHED */
+}
diff --git a/games/canfield/canfield/pathnames.h b/games/canfield/canfield/pathnames.h
new file mode 100644
index 00000000000..4ecb7bb9a43
--- /dev/null
+++ b/games/canfield/canfield/pathnames.h
@@ -0,0 +1,39 @@
+/* $NetBSD: pathnames.h,v 1.3 1995/03/21 15:08:34 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 5/31/93
+ */
+
+#define _PATH_SCORE "/var/games/cfscores"
+
diff --git a/games/canfield/cfscores/Makefile b/games/canfield/cfscores/Makefile
new file mode 100644
index 00000000000..bdc6269f8c3
--- /dev/null
+++ b/games/canfield/cfscores/Makefile
@@ -0,0 +1,10 @@
+# $NetBSD: Makefile,v 1.3 1995/03/21 15:08:36 cgd Exp $
+# @(#)Makefile 8.1 (Berkeley) 5/31/93
+
+PROG= cfscores
+CFLAGS+=-I${.CURDIR}/../canfield
+NOMAN= noman
+HIDEGAME=hidegame
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/games/canfield/cfscores/cfscores.c b/games/canfield/cfscores/cfscores.c
new file mode 100644
index 00000000000..4a3a0e8f782
--- /dev/null
+++ b/games/canfield/cfscores/cfscores.c
@@ -0,0 +1,154 @@
+/* $NetBSD: cfscores.c,v 1.3 1995/03/21 15:08:37 cgd Exp $ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cfscores.c 8.1 (Berkeley) 5/31/93";
+#else
+static char rcsid[] = "$NetBSD: cfscores.c,v 1.3 1995/03/21 15:08:37 cgd Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <pwd.h>
+#include "pathnames.h"
+
+struct betinfo {
+ long hand; /* cost of dealing hand */
+ long inspection; /* cost of inspecting hand */
+ long game; /* cost of buying game */
+ long runs; /* cost of running through hands */
+ long information; /* cost of information */
+ long thinktime; /* cost of thinking time */
+ long wins; /* total winnings */
+ long worth; /* net worth after costs */
+};
+
+int dbfd;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct passwd *pw;
+ int uid;
+
+ if (argc > 2) {
+ printf("Usage: cfscores [user]\n");
+ exit(1);
+ }
+ dbfd = open(_PATH_SCORE, 0);
+ if (dbfd < 0) {
+ perror(_PATH_SCORE);
+ exit(2);
+ }
+ setpwent();
+ if (argc == 1) {
+ uid = getuid();
+ pw = getpwuid(uid);
+ if (pw == 0) {
+ printf("You are not listed in the password file?!?\n");
+ exit(2);
+ }
+ printuser(pw, 1);
+ exit(0);
+ }
+ if (strcmp(argv[1], "-a") == 0) {
+ while ((pw = getpwent()) != 0)
+ printuser(pw, 0);
+ exit(0);
+ }
+ pw = getpwnam(argv[1]);
+ if (pw == 0) {
+ printf("User %s unknown\n", argv[1]);
+ exit(3);
+ }
+ printuser(pw, 1);
+ exit(0);
+}
+
+/*
+ * print out info for specified password entry
+ */
+printuser(pw, printfail)
+ register struct passwd *pw;
+ int printfail;
+{
+ struct betinfo total;
+ int i;
+
+ if (pw->pw_uid < 0) {
+ printf("Bad uid %d\n", pw->pw_uid);
+ return;
+ }
+ i = lseek(dbfd, pw->pw_uid * sizeof(struct betinfo), 0);
+ if (i < 0) {
+ perror("lseek");
+ return;
+ }
+ i = read(dbfd, (char *)&total, sizeof(total));
+ if (i < 0) {
+ perror("read");
+ return;
+ }
+ if (i == 0 || total.hand == 0) {
+ if (printfail)
+ printf("%s has never played canfield.\n", pw->pw_name);
+ return;
+ }
+ printf("*----------------------*\n");
+ if (total.worth >= 0)
+ printf("* Winnings for %-8s*\n", pw->pw_name);
+ else
+ printf("* Losses for %-10s*\n", pw->pw_name);
+ printf("*======================*\n");
+ printf("|Costs Total |\n");
+ printf("| Hands %8d |\n", total.hand);
+ printf("| Inspections %8d |\n", total.inspection);
+ printf("| Games %8d |\n", total.game);
+ printf("| Runs %8d |\n", total.runs);
+ printf("| Information %8d |\n", total.information);
+ printf("| Think time %8d |\n", total.thinktime);
+ printf("|Total Costs %8d |\n", total.wins - total.worth);
+ printf("|Winnings %8d |\n", total.wins);
+ printf("|Net Worth %8d |\n", total.worth);
+ printf("*----------------------*\n\n");
+}