date and time created 90/05/02 08:40:48 by bostic
[unix-history] / usr / src / games / fish / fish.c
CommitLineData
e0bbfbf9
DF
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
8char 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
4e768cda 14static char sccsid[] = "@(#)fish.c 5.2 (Berkeley) %G%";
e0bbfbf9 15#endif not lint
32029695
KM
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
27typedef char HAND[CTSIZ];
28
29/* data structures */
30
31short debug;
32
33HAND myhand;
34HAND yourhand;
35char deck[DECK];
36short nextcd;
37int proflag;
38
39/* utility and output programs */
40
41shuffle(){
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
57choose( 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
70draw() {
71 if( nextcd >= DECK ) return( NOMORE );
72 return( deck[nextcd++] );
73 }
74
75error( s ) char *s; {
76 fprintf( stderr, "error: " );
77 fprintf( stderr, s );
78 exit( 1 );
79 }
80
81empty( 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
4e768cda 90mark( hand, cd ) HAND hand; {
32029695
KM
91 if( cd != NOMORE ){
92 ++hand[cd];
93 if( hand[cd] > 4 ){
94 error( "mark overflow" );
95 }
96 }
97 return( cd );
98 }
99
100deal( hand, n ) HAND hand; {
101 while( n-- ){
102 if( mark( hand, draw() ) == NOMORE ) error( "deck exhausted" );
103 }
104 }
105
106char *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
123stats(){
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
146phand( 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
173main( 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
196char *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
219instruct(){
220 register char **cpp;
221
222 printf( "\n" );
223
224 for( cpp = inst; **cpp != '\0'; ++cpp ){
225 printf( "%s\n", *cpp );
226 }
227 }
228
229game(){
230
231 shuffle();
232
233 deal( myhand, 7 );
234 deal( yourhand, 7 );
235
32029695
KM
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
265move( 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
324madebook( x ){
325 printf( "Made a book of %s's\n", cname[x] );
326 }
327
328score(){
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
359guess(){
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
435char try[100];
436char ntry;
437char haveguessed[CTSIZ];
438
439char hehas[CTSIZ];
440
32029695
KM
441hedrew( d ){
442 ++hehas[d];
443 }
444
445heguessed( d ){
446 ++hehas[d];
447 }
448
449myguess(){
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