Berkeley copyright
[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
14static char sccsid[] = "@(#)fish.c 5.1 (Berkeley) %G%";
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
90mark( cd, hand ) 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
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
236 start( myhand );
237
238 for(;;){
239
240 register g;
241
242
243 /* you make repeated guesses */
244
245 for(;;) {
246 printf( "your hand is: " );
247 phand( yourhand );
248 printf( "you ask me for: " );
249 if( !move( yourhand, myhand, g=guess(), 0 ) ) break;
250 printf( "Guess again\n" );
251 }
252
253 /* I make repeated guesses */
254
255 for(;;) {
256 if( (g=myguess()) != NOMORE ){
257 printf( "I ask you for: %s\n", cname[g] );
258 }
259 if( !move( myhand, yourhand, g, 1 ) ) break;
260 printf( "I get another guess\n" );
261 }
262 }
263 }
264
265/* reflect the effect of a move on the hands */
266
267move( hs, ht, g, v ) HAND hs, ht; {
268 /* hand hs has made a guess, g, directed towards ht */
269 /* v on indicates that the guess was made by the machine */
270 register d;
271 char *sp, *tp;
272
273 sp = tp = "I";
274 if( v ) tp = "You";
275 else sp = "You";
276
277 if( g == NOMORE ){
278 d = draw();
279 if( d == NOMORE ) score();
280 else {
281
282 printf( "Empty Hand\n" );
283 if( !v ) printf( "You draw %s\n", cname[d] );
284 mark( hs, d );
285 }
286 return( 0 );
287 }
288
289 if( !v ) heguessed( g );
290
291 if( hs[g] == 0 ){
292 if( v ) error( "Rotten Guess" );
293 printf( "You don't have any %s's\n", cname[g] );
294 return(1);
295 }
296
297 if( ht[g] ){ /* successful guess */
298 printf( "%s have %d %s%s\n", tp, ht[g], cname[g], ht[g]>1?"'s":"" );
299 hs[g] += ht[g];
300 ht[g] = 0;
301 if( hs[g] == 4 ) madebook(g);
302 return(1);
303 }
304
305 /* GO FISH! */
306
307 printf( "%s say \"GO FISH!\"\n", tp );
308
309 newdraw:
310 d = draw();
311 if( d == NOMORE ) {
312 printf( "No more cards\n" );
313 return(0);
314 }
315 mark( hs, d );
316 if( !v ) printf( "You draw %s\n", cname[d] );
317 if( hs[d] == 4 ) madebook(d);
318 if( d == g ){
319 printf( "%s drew the guess, so draw again\n", sp );
320 if( !v ) hedrew( d );
321 goto newdraw;
322 }
323 return( 0 );
324 }
325
326madebook( x ){
327 printf( "Made a book of %s's\n", cname[x] );
328 }
329
330score(){
331 register my, your, i;
332
333 my = your = 0;
334
335 printf( "The game is over.\nMy books: " );
336
337 for( i=1; i<=CTYPE;++i ){
338 if( myhand[i] == 4 ){
339 ++my;
340 printf( "%s ", cname[i] );
341 }
342 }
343
344 printf( "\nYour books: " );
345
346 for( i=1; i<=CTYPE;++i ){
347 if( yourhand[i] == 4 ){
348 ++your;
349 printf( "%s ", cname[i] );
350 }
351 }
352
353 printf( "\n\nI have %d, you have %d\n", my, your );
354
355 printf( "\n%s win!!!\n", my>your?"I":"You" );
356 exit(0);
357 }
358
359# define G(x) { if(go) goto err; else go = x; }
360
361guess(){
362 /* get the guess from the tty and return it... */
363 register g, go;
364
365 go = 0;
366
367 for(;;) {
368 switch( g = getchar() ){
369
370 case 'p':
371 case 'P':
372 ++proflag;
373 continue;
374
375 case '2':
376 case '3':
377 case '4':
378 case '5':
379 case '6':
380 case '7':
381 case '8':
382 case '9':
383 G(g-'0');
384 continue;
385
386 case 'a':
387 case 'A':
388 G(1);
389 continue;
390
391 case '1':
392 G(10);
393 continue;
394
395 case '0':
396 if( go != 10 ) goto err;
397 continue;
398
399 case 'J':
400 case 'j':
401 G(11);
402 continue;
403
404 case 'Q':
405 case 'q':
406 G(12);
407 continue;
408
409 case 'K':
410 case 'k':
411 G(13);
412 continue;
413
414 case '\n':
415 if( empty( yourhand ) ) return( NOMORE );
416 if( go == 0 ){
417 stats();
418 continue;
419 }
420 return( go );
421
422 case ' ':
423 case '\t':
424 continue;
425
426 default:
427 err:
428 while( g != '\n' ) g = getchar();
429 printf( "what?\n" );
430 continue;
431 }
432 }
433 }
434
435/* the program's strategy appears from here to the end */
436
437char try[100];
438char ntry;
439char haveguessed[CTSIZ];
440
441char hehas[CTSIZ];
442
443start( h ) HAND h; {
444 ;
445 }
446
447hedrew( d ){
448 ++hehas[d];
449 }
450
451heguessed( d ){
452 ++hehas[d];
453 }
454
455myguess(){
456
457 register i, lg, t;
458
459 if( empty( myhand ) ) return( NOMORE );
460
461 /* make a list of those things which i have */
462 /* leave off any which are books */
463 /* if something is found that he has, guess it! */
464
465 ntry = 0;
466 for( i=1; i<=CTYPE; ++i ){
467 if( myhand[i] == 0 || myhand[i] == 4 ) continue;
468 try[ntry++] = i;
469 }
470
471 if( !proflag ) goto random;
472
473 /* get ones he has, if any */
474
475 for( i=0; i<ntry; ++i ){
476 if( hehas[try[i]] ) {
477 i = try[i];
478 goto gotguess;
479 }
480 }
481
482 /* is there one that has never been guessed; if so, guess it */
483 lg = 101;
484 for( i=0; i<ntry; ++i ){
485 if( haveguessed[try[i]] < lg ) lg = haveguessed[try[i]];
486 }
487 /* remove all those not guessed longest ago */
488
489 t = 0;
490 for( i=0; i<ntry; ++i ){
491 if( haveguessed[try[i]] == lg ) try[t++] = try[i];
492 }
493 ntry = t;
494 if( t <= 0 ) error( "bad guessing loop" );
495
496 random:
497 i = choose( try, ntry ); /* make a random choice */
498
499 gotguess: /* do bookkeeping */
500
501 hehas[i] = 0; /* he won't anymore! */
502 for( t=1; t<=CTYPE; ++t ){
503 if( haveguessed[t] ) --haveguessed[t];
504 }
505 haveguessed[i] = 100; /* will have guessed it */
506 return(i);
507
508 }
509