Commit | Line | Data |
---|---|---|
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 | ||
11 | typedef char HAND[CTSIZ]; | |
12 | ||
13 | /* data structures */ | |
14 | ||
15 | short debug; | |
16 | ||
17 | HAND myhand; | |
18 | HAND yourhand; | |
19 | char deck[DECK]; | |
20 | short nextcd; | |
21 | int proflag; | |
22 | ||
23 | /* utility and output programs */ | |
24 | ||
25 | shuffle(){ | |
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 | ||
41 | choose( 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 | ||
54 | draw() { | |
55 | if( nextcd >= DECK ) return( NOMORE ); | |
56 | return( deck[nextcd++] ); | |
57 | } | |
58 | ||
59 | error( s ) char *s; { | |
60 | fprintf( stderr, "error: " ); | |
61 | fprintf( stderr, s ); | |
62 | exit( 1 ); | |
63 | } | |
64 | ||
65 | empty( 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 | ||
74 | mark( 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 | ||
84 | deal( hand, n ) HAND hand; { | |
85 | while( n-- ){ | |
86 | if( mark( hand, draw() ) == NOMORE ) error( "deck exhausted" ); | |
87 | } | |
88 | } | |
89 | ||
90 | char *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 | ||
107 | stats(){ | |
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 | ||
130 | phand( 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 | ||
157 | main( 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 | ||
180 | char *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 | ||
208 | instruct(){ | |
209 | register char **cpp; | |
210 | ||
211 | printf( "\n" ); | |
212 | ||
213 | for( cpp = inst; **cpp != '\0'; ++cpp ){ | |
214 | printf( "%s\n", *cpp ); | |
215 | } | |
216 | } | |
217 | ||
218 | game(){ | |
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 | ||
256 | move( 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 | ||
315 | madebook( x ){ | |
316 | printf( "Made a book of %s's\n", cname[x] ); | |
317 | } | |
318 | ||
319 | score(){ | |
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 | ||
350 | guess(){ | |
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 | ||
426 | char try[100]; | |
427 | char ntry; | |
428 | char haveguessed[CTSIZ]; | |
429 | ||
430 | char hehas[CTSIZ]; | |
431 | ||
432 | start( h ) HAND h; { | |
433 | ; | |
434 | } | |
435 | ||
436 | hedrew( d ){ | |
437 | ++hehas[d]; | |
438 | } | |
439 | ||
440 | heguessed( d ){ | |
441 | ++hehas[d]; | |
442 | } | |
443 | ||
444 | myguess(){ | |
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 |