Commit | Line | Data |
---|---|---|
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 | |
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.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 | ||
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( 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 | ||
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 | 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 | ||
267 | move( 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 | ||
326 | madebook( x ){ | |
327 | printf( "Made a book of %s's\n", cname[x] ); | |
328 | } | |
329 | ||
330 | score(){ | |
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 | ||
361 | guess(){ | |
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 | ||
437 | char try[100]; | |
438 | char ntry; | |
439 | char haveguessed[CTSIZ]; | |
440 | ||
441 | char hehas[CTSIZ]; | |
442 | ||
443 | start( h ) HAND h; { | |
444 | ; | |
445 | } | |
446 | ||
447 | hedrew( d ){ | |
448 | ++hehas[d]; | |
449 | } | |
450 | ||
451 | heguessed( d ){ | |
452 | ++hehas[d]; | |
453 | } | |
454 | ||
455 | myguess(){ | |
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 |