xref: /original-bsd/games/fish/fish.c (revision 39c8fdd5)
1 
2 static char sccsid[] = "	fish.c	4.1	82/10/24	";
3 
4 # include <stdio.h>
5 
6 /*	Through, `my' refers to the program, `your' to the player */
7 
8 # define CTYPE 13
9 # define CTSIZ (CTYPE+1)
10 # define DECK 52
11 # define NOMORE 0
12 # define DOUBTIT (-1);
13 
14 typedef char HAND[CTSIZ];
15 
16 /* data structures */
17 
18 short debug;
19 
20 HAND myhand;
21 HAND yourhand;
22 char deck[DECK];
23 short nextcd;
24 int proflag;
25 
26 /* utility and output programs */
27 
28 shuffle(){
29 	/* shuffle the deck, and reset nextcd */
30 	/* uses the random number generator `rand' in the C library */
31 	/* assumes that `srand' has already been called */
32 
33 	register i;
34 
35 	for( i=0; i<DECK; ++i ) deck[i] = (i%13)+1;  /* seed the deck */
36 
37 	for( i=DECK; i>0; --i ){ /* select the next card at random */
38 		deck[i-1] = choose( deck, i );
39 		}
40 
41 	nextcd = 0;
42 	}
43 
44 choose( a, n ) char a[]; {
45 	/* pick and return one at random from the n choices in a */
46 	/* The last one is moved to replace the one chosen */
47 	register j, t;
48 
49 	if( n <= 0 ) error( "null choice" );
50 
51 	j = rand() % n;
52 	t = a[j];
53 	a[j] = a[n-1];
54 	return(t);
55 	}
56 
57 draw() {
58 	if( nextcd >= DECK ) return( NOMORE );
59 	return( deck[nextcd++] );
60 	}
61 
62 error( s ) char *s; {
63 	fprintf( stderr, "error: " );
64 	fprintf( stderr, s );
65 	exit( 1 );
66 	}
67 
68 empty( h ) HAND h; {
69 	register i;
70 
71 	for( i=1; i<=CTYPE; ++i ){
72 		if( h[i] != 0 && h[i] != 4 ) return( 0 );
73 		}
74 	return( i );
75 	}
76 
77 mark( cd, hand ) HAND hand; {
78 	if( cd != NOMORE ){
79 		++hand[cd];
80 		if( hand[cd] > 4 ){
81 			error( "mark overflow" );
82 			}
83 		}
84 	return( cd );
85 	}
86 
87 deal( hand, n ) HAND hand; {
88 	while( n-- ){
89 		if( mark( hand, draw() ) == NOMORE ) error( "deck exhausted" );
90 		}
91 	}
92 
93 char *cname[] = {
94 	"NOMORE!!!",
95 	"A",
96 	"2",
97 	"3",
98 	"4",
99 	"5",
100 	"6",
101 	"7",
102 	"8",
103 	"9",
104 	"10",
105 	"J",
106 	"Q",
107 	"K",
108 	};
109 
110 stats(){
111 	register i, ct, b;
112 
113 	if( proflag ) printf( "Pro level\n" );
114 	b = ct = 0;
115 
116 	for( i=1; i<=CTYPE; ++i ){
117 		if( myhand[i] == 4 ) ++b;
118 		else ct += myhand[i];
119 		}
120 
121 	if( b ){
122 		printf( "My books: " );
123 		for( i=1; i<=CTYPE; ++i ){
124 			if( myhand[i] == 4 ) printf( "%s ", cname[i] );
125 			}
126 		printf( "\n" );
127 		}
128 
129 	printf( "%d cards in my hand, %d in the pool\n", ct, DECK-nextcd );
130 	printf( "You ask me for: " );
131 	}
132 
133 phand( h ) HAND h; {
134 	register i, j;
135 
136 	j = 0;
137 
138 	for( i = 1; i<= CTYPE; ++i ){
139 		if( h[i] == 4 ) {
140 			++j;
141 			continue;
142 			}
143 		if( h[i] ){
144 			register k;
145 			k = h[i];
146 			while( k-- ) printf( "%s ", cname[i] );
147 			}
148 		}
149 
150 	if( j ){
151 		printf( "+ Books of " );
152 		for( i=1; i<=CTYPE; ++i ){
153 			if( h[i] == 4 ) printf( "%s ", cname[i] );
154 			}
155 		}
156 
157 	printf( "\n" );
158 	}
159 
160 main( argc, argv ) char * argv[]; {
161 	/* initialize shuffling, ask for instructions, play game, die */
162 	register c;
163 
164 	if( argc > 1 && argv[1][0] == '-' ){
165 		while( argv[1][0] == '-' ) { ++argv[1]; ++debug; }
166 		argv++;
167 		argc--;
168 		}
169 
170 	srand( getpid() );
171 
172 	printf( "instructions?\n" );
173 	if( (c=getchar()) != '\n' ){
174 		if( c != 'n' ) instruct();
175 		while( getchar() != '\n' );
176 		}
177 
178 	game();
179 	}
180 
181 /*	print instructions */
182 
183 char *inst[] = {
184 	"`Go Fish' is a childrens' card game.  The Object is to",
185 	"accumulate `books' of 4 cards with the same face value.  The",
186 	"players alternate turns; each turn begins with one player",
187 	"selecting a card from his hand, and asking the other player for",
188 	"all cards of that face value.  If the other player has one or",
189 	"more cards of that face value in his hand, he gives them to the",
190 	"first player, and the first player makes another request.",
191 	"Eventually, the first player asks for a card which is not in",
192 	"the second player's hand: he replies `GO FISH!' The first",
193 	"player then draws a card from the `pool' of undealt cards.  If",
194 	"this is the card he had last requested, he draws again.  When a",
195 	"book is made, either through drawing or requesting, the cards",
196 	"are laid down and no further action takes place with that face",
197 	"value.  To play the computer, simply make guesses by typing a,",
198 	"2, 3, 4, 5, 6, 7, 8, 9, 10, j, q, or k when asked.  Hitting",
199 	"return gives you information about the size of my hand and the",
200 	"pool, and tells you about my books.  Saying `p' as a first",
201 	"guess puts you into `pro' level; The default is pretty dumb!",
202 	"Good Luck!\n",
203 	"",
204 	};
205 
206 instruct(){
207 	register char **cpp;
208 
209 	printf( "\n" );
210 
211 	for( cpp = inst; **cpp != '\0'; ++cpp ){
212 		printf( "%s\n", *cpp );
213 		}
214 	}
215 
216 game(){
217 
218 	shuffle();
219 
220 	deal( myhand, 7 );
221 	deal( yourhand, 7 );
222 
223 	start( myhand );
224 
225 	for(;;){
226 
227 		register g;
228 
229 
230 		/* you make repeated guesses */
231 
232 		for(;;) {
233 			printf( "your hand is: " );
234 			phand( yourhand );
235 			printf( "you ask me for: " );
236 			if( !move( yourhand, myhand, g=guess(), 0 ) ) break;
237 			printf( "Guess again\n" );
238 			}
239 
240 		/* I make repeated guesses */
241 
242 		for(;;) {
243 			if( (g=myguess()) != NOMORE ){
244 				printf( "I ask you for: %s\n", cname[g] );
245 				}
246 			if( !move( myhand, yourhand, g, 1 ) ) break;
247 			printf( "I get another guess\n" );
248 			}
249 		}
250 	}
251 
252 /*	reflect the effect of a move on the hands */
253 
254 move( hs, ht, g, v ) HAND hs, ht; {
255 	/* hand hs has made a guess, g, directed towards ht */
256 	/* v on indicates that the guess was made by the machine */
257 	register d;
258 	char *sp, *tp;
259 
260 	sp = tp = "I";
261 	if( v ) tp = "You";
262 	else sp = "You";
263 
264 	if( g == NOMORE ){
265 		d = draw();
266 		if( d == NOMORE ) score();
267 		else {
268 
269 			printf( "Empty Hand\n" );
270 			if( !v ) printf( "You draw %s\n", cname[d] );
271 			mark( hs, d );
272 			}
273 		return( 0 );
274 		}
275 
276 	if( !v ) heguessed( g );
277 
278 	if( hs[g] == 0 ){
279 		if( v ) error( "Rotten Guess" );
280 		printf( "You don't have any %s's\n", cname[g] );
281 		return(1);
282 		}
283 
284 	if( ht[g] ){ /* successful guess */
285 		printf( "%s have %d %s%s\n", tp, ht[g], cname[g], ht[g]>1?"'s":"" );
286 		hs[g] += ht[g];
287 		ht[g] = 0;
288 		if( hs[g] == 4 ) madebook(g);
289 		return(1);
290 		}
291 
292 	/* GO FISH! */
293 
294 	printf( "%s say \"GO FISH!\"\n", tp );
295 
296 	newdraw:
297 	d = draw();
298 	if( d == NOMORE ) {
299 		printf( "No more cards\n" );
300 		return(0);
301 		}
302 	mark( hs, d );
303 	if( !v ) printf( "You draw %s\n", cname[d] );
304 	if( hs[d] == 4 ) madebook(d);
305 	if( d == g ){
306 		printf( "%s drew the guess, so draw again\n", sp );
307 		if( !v ) hedrew( d );
308 		goto newdraw;
309 		}
310 	return( 0 );
311 	}
312 
313 madebook( x ){
314 	printf( "Made a book of %s's\n", cname[x] );
315 	}
316 
317 score(){
318 	register my, your, i;
319 
320 	my = your = 0;
321 
322 	printf( "The game is over.\nMy books: " );
323 
324 	for( i=1; i<=CTYPE;++i ){
325 		if( myhand[i] == 4 ){
326 			++my;
327 			printf( "%s ", cname[i] );
328 			}
329 		}
330 
331 	printf( "\nYour books: " );
332 
333 	for( i=1; i<=CTYPE;++i ){
334 		if( yourhand[i] == 4 ){
335 			++your;
336 			printf( "%s ", cname[i] );
337 			}
338 		}
339 
340 	printf( "\n\nI have %d, you have %d\n", my, your );
341 
342 	printf( "\n%s win!!!\n", my>your?"I":"You" );
343 	exit(0);
344 	}
345 
346 # define G(x) { if(go) goto err;  else go = x; }
347 
348 guess(){
349 	/* get the guess from the tty and return it... */
350 	register g, go;
351 
352 	go = 0;
353 
354 	for(;;) {
355 		switch( g = getchar() ){
356 
357 		case 'p':
358 		case 'P':
359 			++proflag;
360 			continue;
361 
362 		case '2':
363 		case '3':
364 		case '4':
365 		case '5':
366 		case '6':
367 		case '7':
368 		case '8':
369 		case '9':
370 			G(g-'0');
371 			continue;
372 
373 		case 'a':
374 		case 'A':
375 			G(1);
376 			continue;
377 
378 		case '1':
379 			G(10);
380 			continue;
381 
382 		case '0':
383 			if( go != 10 ) goto err;
384 			continue;
385 
386 		case 'J':
387 		case 'j':
388 			G(11);
389 			continue;
390 
391 		case 'Q':
392 		case 'q':
393 			G(12);
394 			continue;
395 
396 		case 'K':
397 		case 'k':
398 			G(13);
399 			continue;
400 
401 		case '\n':
402 			if( empty( yourhand ) ) return( NOMORE );
403 			if( go == 0 ){
404 				stats();
405 				continue;
406 				}
407 			return( go );
408 
409 		case ' ':
410 		case '\t':
411 			continue;
412 
413 		default:
414 			err:
415 			while( g != '\n' ) g = getchar();
416 			printf( "what?\n" );
417 			continue;
418 			}
419 		}
420 	}
421 
422 /*	the program's strategy appears from here to the end */
423 
424 char try[100];
425 char ntry;
426 char haveguessed[CTSIZ];
427 
428 char hehas[CTSIZ];
429 
430 start( h ) HAND h; {
431 	;
432 	}
433 
434 hedrew( d ){
435 	++hehas[d];
436 	}
437 
438 heguessed( d ){
439 	++hehas[d];
440 	}
441 
442 myguess(){
443 
444 	register i, lg, t;
445 
446 	if( empty( myhand ) ) return( NOMORE );
447 
448 	/* make a list of those things which i have */
449 	/* leave off any which are books */
450 	/* if something is found that he has, guess it! */
451 
452 	ntry = 0;
453 	for( i=1; i<=CTYPE; ++i ){
454 		if( myhand[i] == 0 || myhand[i] == 4 ) continue;
455 		try[ntry++] = i;
456 		}
457 
458 	if( !proflag ) goto random;
459 
460 	/* get ones he has, if any */
461 
462 	for( i=0; i<ntry; ++i ){
463 		if( hehas[try[i]] ) {
464 			i = try[i];
465 			goto gotguess;
466 			}
467 		}
468 
469 	/* is there one that has never been guessed; if so, guess it */
470 	lg = 101;
471 	for( i=0; i<ntry; ++i ){
472 		if( haveguessed[try[i]] < lg ) lg = haveguessed[try[i]];
473 		}
474 	/* remove all those not guessed longest ago */
475 
476 	t = 0;
477 	for( i=0; i<ntry; ++i ){
478 		if( haveguessed[try[i]] == lg ) try[t++] = try[i];
479 		}
480 	ntry = t;
481 	if( t <= 0 ) error( "bad guessing loop" );
482 
483 	random:
484 	i = choose( try, ntry );  /* make a random choice */
485 
486 	gotguess:  /* do bookkeeping */
487 
488 	hehas[i] = 0;  /* he won't anymore! */
489 	for( t=1; t<=CTYPE; ++t ){
490 		if( haveguessed[t] ) --haveguessed[t];
491 		}
492 	haveguessed[i] = 100;  /* will have guessed it */
493 	return(i);
494 
495 	}
496 
497