mirror of
https://github.com/bobbimanners/GNO-Extras.git
synced 2024-12-22 02:30:17 +00:00
499 lines
9.0 KiB
Plaintext
499 lines
9.0 KiB
Plaintext
# include <stdio.h>
|
|
|
|
/* Through, `my' refers to the program, `your' to the player */
|
|
|
|
# define CTYPE 13
|
|
# define CTSIZ (CTYPE+1)
|
|
# define DECK 52
|
|
# define NOMORE 0
|
|
# define DOUBTIT (-1);
|
|
|
|
typedef char HAND[CTSIZ];
|
|
|
|
/* data structures */
|
|
|
|
short debug;
|
|
|
|
HAND myhand;
|
|
HAND yourhand;
|
|
char deck[DECK];
|
|
short nextcd;
|
|
int proflag;
|
|
|
|
/* utility and output programs */
|
|
|
|
shuffle(){
|
|
/* shuffle the deck, and reset nextcd */
|
|
/* uses the random number generator `rand' in the C library */
|
|
/* assumes that `srand' has already been called */
|
|
|
|
register i;
|
|
|
|
for( i=0; i<DECK; ++i ) deck[i] = (i%13)+1; /* seed the deck */
|
|
|
|
for( i=DECK; i>0; --i ){ /* select the next card at random */
|
|
deck[i-1] = choose( deck, i );
|
|
}
|
|
|
|
nextcd = 0;
|
|
}
|
|
|
|
choose( a, n ) char a[]; {
|
|
/* pick and return one at random from the n choices in a */
|
|
/* The last one is moved to replace the one chosen */
|
|
register j, t;
|
|
|
|
if( n <= 0 ) error( "null choice" );
|
|
|
|
j = rand() % n;
|
|
t = a[j];
|
|
a[j] = a[n-1];
|
|
return(t);
|
|
}
|
|
|
|
draw() {
|
|
if( nextcd >= DECK ) return( NOMORE );
|
|
return( deck[nextcd++] );
|
|
}
|
|
|
|
error( s ) char *s; {
|
|
fprintf( stderr, "error: " );
|
|
fprintf( stderr, s );
|
|
exit( 1 );
|
|
}
|
|
|
|
empty( h ) HAND h; {
|
|
register i;
|
|
|
|
for( i=1; i<=CTYPE; ++i ){
|
|
if( h[i] != 0 && h[i] != 4 ) return( 0 );
|
|
}
|
|
return( i );
|
|
}
|
|
|
|
mark( cd, hand ) HAND hand; {
|
|
if( cd != NOMORE ){
|
|
++hand[cd];
|
|
if( hand[cd] > 4 ){
|
|
error( "mark overflow" );
|
|
}
|
|
}
|
|
return( cd );
|
|
}
|
|
|
|
deal( hand, n ) HAND hand; {
|
|
while( n-- ){
|
|
if( mark( hand, draw() ) == NOMORE ) error( "deck exhausted" );
|
|
}
|
|
}
|
|
|
|
char *cname[] {
|
|
"NOMORE!!!",
|
|
"A",
|
|
"2",
|
|
"3",
|
|
"4",
|
|
"5",
|
|
"6",
|
|
"7",
|
|
"8",
|
|
"9",
|
|
"10",
|
|
"J",
|
|
"Q",
|
|
"K",
|
|
};
|
|
|
|
stats(){
|
|
register i, ct, b;
|
|
|
|
if( proflag ) printf( "Pro level\n" );
|
|
b = ct = 0;
|
|
|
|
for( i=1; i<=CTYPE; ++i ){
|
|
if( myhand[i] == 4 ) ++b;
|
|
else ct += myhand[i];
|
|
}
|
|
|
|
if( b ){
|
|
printf( "My books: " );
|
|
for( i=1; i<=CTYPE; ++i ){
|
|
if( myhand[i] == 4 ) printf( "%s ", cname[i] );
|
|
}
|
|
printf( "\n" );
|
|
}
|
|
|
|
printf( "%d cards in my hand, %d in the pool\n", ct, DECK-nextcd );
|
|
printf( "You ask me for: " );
|
|
}
|
|
|
|
phand( h ) HAND h; {
|
|
register i, j;
|
|
|
|
j = 0;
|
|
|
|
for( i = 1; i<= CTYPE; ++i ){
|
|
if( h[i] == 4 ) {
|
|
++j;
|
|
continue;
|
|
}
|
|
if( h[i] ){
|
|
register k;
|
|
k = h[i];
|
|
while( k-- ) printf( "%s ", cname[i] );
|
|
}
|
|
}
|
|
|
|
if( j ){
|
|
printf( "+ Books of " );
|
|
for( i=1; i<=CTYPE; ++i ){
|
|
if( h[i] == 4 ) printf( "%s ", cname[i] );
|
|
}
|
|
}
|
|
|
|
printf( "\n" );
|
|
}
|
|
|
|
main( argc, argv ) char * argv[]; {
|
|
/* initialize shuffling, ask for instructions, play game, die */
|
|
register c;
|
|
|
|
if( argc > 1 && argv[1][0] == '-' ){
|
|
while( argv[1][0] == '-' ) { ++argv[1]; ++debug; }
|
|
argv++;
|
|
argc--;
|
|
}
|
|
|
|
srand( getpid() );
|
|
|
|
printf( "instructions?\n" );
|
|
if( (c=getchar()) != '\n' ){
|
|
if( c != 'n' ) instruct();
|
|
while( getchar() != '\n' );
|
|
}
|
|
|
|
game();
|
|
}
|
|
|
|
/* print instructions */
|
|
|
|
char *inst[] {
|
|
"`Go Fish' is a childrens' card game.",
|
|
"The Object is to accumulate `books' of 4 cards",
|
|
"with the same face value.",
|
|
"The players alternate turns; each turn begins with one",
|
|
"player selecting a card from his hand, and asking the",
|
|
"other player for all cards of that face value.",
|
|
"If the other player has one or more cards of that face value",
|
|
"in his hand, he gives them to the first player, and the",
|
|
"first player makes another request.",
|
|
"Eventually, the first player asks for a card which",
|
|
"is not in the second player's hand: he replies `GO FISH!'",
|
|
"The first player then draws a card from the `pool' of",
|
|
"undealt cards. If this is the card he had last requested, he",
|
|
"draws again.",
|
|
"When a book is made, either through drawing or requesting,",
|
|
"the cards are laid down and no further action takes",
|
|
"place with that face value.",
|
|
"To play the computer, simply make guesses by typing",
|
|
"a, 2, 3, 4, 5, 6, 7, 8, 9, 10, j, q, or k when asked.",
|
|
"Hitting return gives you information about the size of",
|
|
"my hand and the pool, and tells you about my books.",
|
|
"Saying `p' as a first guess puts you into `pro' level;",
|
|
"The default is pretty dumb!",
|
|
"Good Luck!",
|
|
"",
|
|
};
|
|
|
|
instruct(){
|
|
register char **cpp;
|
|
|
|
printf( "\n" );
|
|
|
|
for( cpp = inst; **cpp != '\0'; ++cpp ){
|
|
printf( "%s\n", *cpp );
|
|
}
|
|
}
|
|
|
|
game(){
|
|
|
|
shuffle();
|
|
|
|
deal( myhand, 7 );
|
|
deal( yourhand, 7 );
|
|
|
|
start( myhand );
|
|
|
|
for(;;){
|
|
|
|
register g;
|
|
|
|
|
|
/* you make repeated guesses */
|
|
|
|
for(;;) {
|
|
printf( "your hand is: " );
|
|
phand( yourhand );
|
|
printf( "you ask me for: " );
|
|
if( !move( yourhand, myhand, g=guess(), 0 ) ) break;
|
|
printf( "Guess again\n" );
|
|
}
|
|
|
|
/* I make repeated guesses */
|
|
|
|
for(;;) {
|
|
if( (g=myguess()) != NOMORE ){
|
|
printf( "I ask you for: %s\n", cname[g] );
|
|
}
|
|
if( !move( myhand, yourhand, g, 1 ) ) break;
|
|
printf( "I get another guess\n" );
|
|
}
|
|
}
|
|
}
|
|
|
|
/* reflect the effect of a move on the hands */
|
|
|
|
move( hs, ht, g, v ) HAND hs, ht; {
|
|
/* hand hs has made a guess, g, directed towards ht */
|
|
/* v on indicates that the guess was made by the machine */
|
|
register d;
|
|
char *sp, *tp;
|
|
|
|
sp = tp = "I";
|
|
if( v ) tp = "You";
|
|
else sp = "You";
|
|
|
|
if( g == NOMORE ){
|
|
d = draw();
|
|
if( d == NOMORE ) score();
|
|
else {
|
|
|
|
printf( "Empty Hand\n" );
|
|
if( !v ) printf( "You draw %s\n", cname[d] );
|
|
mark( hs, d );
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
if( !v ) heguessed( g );
|
|
|
|
if( hs[g] == 0 ){
|
|
if( v ) error( "Rotten Guess" );
|
|
printf( "You don't have any %s's\n", cname[g] );
|
|
return(1);
|
|
}
|
|
|
|
if( ht[g] ){ /* successful guess */
|
|
printf( "%s have %d %s%s\n", tp, ht[g], cname[g], ht[g]>1?"'s":"" );
|
|
hs[g] += ht[g];
|
|
ht[g] = 0;
|
|
if( hs[g] == 4 ) madebook(g);
|
|
return(1);
|
|
}
|
|
|
|
/* GO FISH! */
|
|
|
|
printf( "%s say \"GO FISH!\"\n", tp );
|
|
|
|
newdraw:
|
|
d = draw();
|
|
if( d == NOMORE ) {
|
|
printf( "No more cards\n" );
|
|
return(0);
|
|
}
|
|
mark( hs, d );
|
|
if( !v ) printf( "You draw %s\n", cname[d] );
|
|
if( hs[d] == 4 ) madebook(d);
|
|
if( d == g ){
|
|
printf( "%s drew the guess, so draw again\n", sp );
|
|
if( !v ) hedrew( d );
|
|
goto newdraw;
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
madebook( x ){
|
|
printf( "Made a book of %s's\n", cname[x] );
|
|
}
|
|
|
|
score(){
|
|
register my, your, i;
|
|
|
|
my = your = 0;
|
|
|
|
printf( "The game is over.\nMy books: " );
|
|
|
|
for( i=1; i<=CTYPE;++i ){
|
|
if( myhand[i] == 4 ){
|
|
++my;
|
|
printf( "%s ", cname[i] );
|
|
}
|
|
}
|
|
|
|
printf( "\nYour books: " );
|
|
|
|
for( i=1; i<=CTYPE;++i ){
|
|
if( yourhand[i] == 4 ){
|
|
++your;
|
|
printf( "%s ", cname[i] );
|
|
}
|
|
}
|
|
|
|
printf( "\n\nI have %d, you have %d\n", my, your );
|
|
|
|
printf( "\n%s win!!!\n", my>your?"I":"You" );
|
|
exit(0);
|
|
}
|
|
|
|
# define G(x) { if(go) goto err; else go = x; }
|
|
|
|
guess(){
|
|
/* get the guess from the tty and return it... */
|
|
register g, go;
|
|
|
|
go = 0;
|
|
|
|
for(;;) {
|
|
switch( g = getchar() ){
|
|
|
|
case 'p':
|
|
case 'P':
|
|
++proflag;
|
|
continue;
|
|
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
G(g-'0');
|
|
continue;
|
|
|
|
case 'a':
|
|
case 'A':
|
|
G(1);
|
|
continue;
|
|
|
|
case '1':
|
|
G(10);
|
|
continue;
|
|
|
|
case '0':
|
|
if( go != 10 ) goto err;
|
|
continue;
|
|
|
|
case 'J':
|
|
case 'j':
|
|
G(11);
|
|
continue;
|
|
|
|
case 'Q':
|
|
case 'q':
|
|
G(12);
|
|
continue;
|
|
|
|
case 'K':
|
|
case 'k':
|
|
G(13);
|
|
continue;
|
|
|
|
case '\n':
|
|
if( empty( yourhand ) ) return( NOMORE );
|
|
if( go == 0 ){
|
|
stats();
|
|
continue;
|
|
}
|
|
return( go );
|
|
|
|
case ' ':
|
|
case '\t':
|
|
continue;
|
|
|
|
default:
|
|
err:
|
|
while( g != '\n' ) g = getchar();
|
|
printf( "what?\n" );
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* the program's strategy appears from here to the end */
|
|
|
|
char try[100];
|
|
char ntry;
|
|
char haveguessed[CTSIZ];
|
|
|
|
char hehas[CTSIZ];
|
|
|
|
start( h ) HAND h; {
|
|
;
|
|
}
|
|
|
|
hedrew( d ){
|
|
++hehas[d];
|
|
}
|
|
|
|
heguessed( d ){
|
|
++hehas[d];
|
|
}
|
|
|
|
myguess(){
|
|
|
|
register i, lg, t;
|
|
|
|
if( empty( myhand ) ) return( NOMORE );
|
|
|
|
/* make a list of those things which i have */
|
|
/* leave off any which are books */
|
|
/* if something is found that he has, guess it! */
|
|
|
|
ntry = 0;
|
|
for( i=1; i<=CTYPE; ++i ){
|
|
if( myhand[i] == 0 || myhand[i] == 4 ) continue;
|
|
try[ntry++] = i;
|
|
}
|
|
|
|
if( !proflag ) goto random;
|
|
|
|
/* get ones he has, if any */
|
|
|
|
for( i=0; i<ntry; ++i ){
|
|
if( hehas[try[i]] ) {
|
|
i = try[i];
|
|
goto gotguess;
|
|
}
|
|
}
|
|
|
|
/* is there one that has never been guessed; if so, guess it */
|
|
lg = 101;
|
|
for( i=0; i<ntry; ++i ){
|
|
if( haveguessed[try[i]] < lg ) lg = haveguessed[try[i]];
|
|
}
|
|
/* remove all those not guessed longest ago */
|
|
|
|
t = 0;
|
|
for( i=0; i<ntry; ++i ){
|
|
if( haveguessed[try[i]] == lg ) try[t++] = try[i];
|
|
}
|
|
ntry = t;
|
|
if( t <= 0 ) error( "bad guessing loop" );
|
|
|
|
random:
|
|
i = choose( try, ntry ); /* make a random choice */
|
|
|
|
gotguess: /* do bookkeeping */
|
|
|
|
hehas[i] = 0; /* he won't anymore! */
|
|
for( t=1; t<=CTYPE; ++t ){
|
|
if( haveguessed[t] ) --haveguessed[t];
|
|
}
|
|
haveguessed[i] = 100; /* will have guessed it */
|
|
return(i);
|
|
|
|
}
|
|
|