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