BSD 4_2 development
[unix-history] / usr / src / games / fish.c
CommitLineData
d16df88a
C
1
2static 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
14typedef char HAND[CTSIZ];
15
16/* data structures */
17
18short debug;
19
20HAND myhand;
21HAND yourhand;
22char deck[DECK];
23short nextcd;
24int proflag;
25
26/* utility and output programs */
27
28shuffle(){
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
44choose( 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
57draw() {
58 if( nextcd >= DECK ) return( NOMORE );
59 return( deck[nextcd++] );
60 }
61
62error( s ) char *s; {
63 fprintf( stderr, "error: " );
64 fprintf( stderr, s );
65 exit( 1 );
66 }
67
68empty( 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
77mark( 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
87deal( hand, n ) HAND hand; {
88 while( n-- ){
89 if( mark( hand, draw() ) == NOMORE ) error( "deck exhausted" );
90 }
91 }
92
93char *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
110stats(){
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
133phand( 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
160main( 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
183char *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
206instruct(){
207 register char **cpp;
208
209 printf( "\n" );
210
211 for( cpp = inst; **cpp != '\0'; ++cpp ){
212 printf( "%s\n", *cpp );
213 }
214 }
215
216game(){
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
254move( 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
313madebook( x ){
314 printf( "Made a book of %s's\n", cname[x] );
315 }
316
317score(){
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
348guess(){
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
424char try[100];
425char ntry;
426char haveguessed[CTSIZ];
427
428char hehas[CTSIZ];
429
430start( h ) HAND h; {
431 ;
432 }
433
434hedrew( d ){
435 ++hehas[d];
436 }
437
438heguessed( d ){
439 ++hehas[d];
440 }
441
442myguess(){
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