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