Commit | Line | Data |
---|---|---|
6cca9b39 KM |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
bf870064 KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
6 | * provided that this notice is preserved and that due credit is given | |
7 | * to the University of California at Berkeley. The name of the University | |
8 | * may not be used to endorse or promote products derived from this | |
9 | * software without specific prior written permission. This software | |
10 | * is provided ``as is'' without express or implied warranty. | |
6cca9b39 KM |
11 | */ |
12 | ||
13 | #ifndef lint | |
bf870064 KB |
14 | static char sccsid[] = "@(#)support.c 5.3 (Berkeley) %G%"; |
15 | #endif /* not lint */ | |
9a6fbd6d | 16 | |
5836528f | 17 | #include <curses.h> |
feeca497 KA |
18 | #include "deck.h" |
19 | #include "cribbage.h" | |
5836528f | 20 | #include "cribcur.h" |
feeca497 KA |
21 | |
22 | ||
23 | #define NTV 10 /* number scores to test */ | |
24 | ||
25 | /* score to test reachability of, and order to test them in */ | |
26 | int tv[ NTV ] = { 8, 7, 9, 6, 11, 12, 13, 14, 10, 5 }; | |
27 | ||
28 | ||
29 | /* | |
30 | * computer chooses what to play in pegging... | |
31 | * only called if no playable card will score points | |
32 | */ | |
33 | ||
34 | cchose( h, n, s ) | |
35 | ||
36 | CARD h[]; | |
37 | int n; | |
38 | int s; | |
39 | { | |
40 | register int i, j, l; | |
41 | ||
42 | if( n <= 1 ) return( 0 ); | |
43 | if( s < 4 ) { /* try for good value */ | |
44 | if( ( j = anysumto(h, n, s, 4) ) >= 0 ) return( j ); | |
45 | if( ( j = anysumto(h, n, s, 3) ) >= 0 && s == 0 ) | |
46 | return( j ); | |
47 | } | |
48 | if( s > 0 && s < 20 ) { | |
49 | for( i = 1; i <= 10; i++ ) { /* try for retaliation to 31 */ | |
50 | if( ( j = anysumto(h, n, s, 21-i) ) >= 0 ) { | |
51 | if( ( l = numofval(h, n, i) ) > 0 ) { | |
52 | if( l > 1 || VAL( h[j].rank ) != i ) return( j ); | |
53 | } | |
54 | } | |
55 | } | |
56 | } | |
57 | if( s < 15 ) { | |
58 | for( i = 0; i < NTV; i++ ) { /* for retaliation after 15 */ | |
59 | if( ( j = anysumto(h, n, s, tv[i]) ) >= 0 ) { | |
60 | if( ( l = numofval(h, n, 15-tv[i]) ) > 0 ) { | |
61 | if( l > 1 || VAL( h[j].rank ) != 15-tv[i] ) return( j ); | |
62 | } | |
63 | } | |
64 | } | |
65 | } | |
66 | j = -1; | |
67 | for( i = n - 1; i >= 0; --i ) { /* remember: h is sorted */ | |
68 | l = s + VAL( h[i].rank ); | |
69 | if( l > 31 ) continue; | |
70 | if( l != 5 && l != 10 && l != 21 ) { | |
71 | j = i; | |
72 | break; | |
73 | } | |
74 | } | |
75 | if( j >= 0 ) return( j ); | |
76 | for( i = n - 1; i >= 0; --i ) { | |
77 | l = s + VAL( h[i].rank ); | |
78 | if( l > 31 ) continue; | |
79 | if( j < 0 ) j = i; | |
80 | if( l != 5 && l != 21 ) { | |
81 | j = i; | |
82 | break; | |
83 | } | |
84 | } | |
85 | return( j ); | |
86 | } | |
87 | ||
88 | ||
89 | ||
90 | /* | |
5836528f KA |
91 | * plyrhand: |
92 | * Evaluate and score a player hand or crib | |
feeca497 | 93 | */ |
5836528f KA |
94 | plyrhand(hand, s) |
95 | CARD hand[]; | |
96 | char *s; | |
feeca497 | 97 | { |
0033d0c1 KA |
98 | register int i, j; |
99 | register BOOLEAN win; | |
100 | static char prompt[BUFSIZ]; | |
101 | ||
102 | prhand(hand, CINHAND, Playwin, FALSE); | |
9bd38ba8 | 103 | (void)sprintf(prompt, "Your %s scores ", s); |
f870d435 | 104 | i = scorehand(hand, turnover, CINHAND, strcmp(s, "crib") == 0, explain); |
0033d0c1 KA |
105 | if ((j = number(0, 29, prompt)) == 19) |
106 | j = 0; | |
107 | if (i != j) { | |
108 | if (i < j) { | |
5836528f | 109 | win = chkscr(&pscore, i); |
0033d0c1 KA |
110 | msg("It's really only %d points; I get %d", i, 2); |
111 | if (!win) | |
112 | win = chkscr(&cscore, 2); | |
113 | } | |
114 | else { | |
115 | win = chkscr(&pscore, j); | |
116 | msg("You should have taken %d, not %d!", i, j); | |
117 | } | |
118 | if (explain) | |
119 | msg("Explanation: %s", expl); | |
120 | do_wait(); | |
121 | } | |
122 | else | |
123 | win = chkscr(&pscore, i); | |
124 | return win; | |
feeca497 KA |
125 | } |
126 | ||
5836528f KA |
127 | /* |
128 | * comphand: | |
129 | * Handle scoring and displaying the computers hand | |
130 | */ | |
131 | comphand(h, s) | |
132 | CARD h[]; | |
133 | char *s; | |
134 | { | |
135 | register int j; | |
feeca497 | 136 | |
f870d435 | 137 | j = scorehand(h, turnover, CINHAND, strcmp(s, "crib") == 0, FALSE); |
5dc185f5 | 138 | prhand(h, CINHAND, Compwin, FALSE); |
5836528f KA |
139 | msg("My %s scores %d", s, (j == 0 ? 19 : j)); |
140 | return chkscr(&cscore, j); | |
141 | } | |
feeca497 KA |
142 | |
143 | /* | |
5836528f KA |
144 | * chkscr: |
145 | * Add inc to scr and test for > glimit, printing on the scoring | |
146 | * board while we're at it. | |
feeca497 KA |
147 | */ |
148 | ||
a410e8bc | 149 | int Lastscore[2] = {-1, -1}; |
feeca497 | 150 | |
5836528f KA |
151 | chkscr(scr, inc) |
152 | int *scr, inc; | |
feeca497 | 153 | { |
5836528f | 154 | BOOLEAN myturn; |
feeca497 | 155 | |
5836528f KA |
156 | myturn = (scr == &cscore); |
157 | if (inc != 0) { | |
158 | prpeg(Lastscore[myturn], '.', myturn); | |
159 | Lastscore[myturn] = *scr; | |
a410e8bc KA |
160 | *scr += inc; |
161 | prpeg(*scr, PEG, myturn); | |
3ba687c0 | 162 | refresh(); |
5836528f | 163 | } |
2067fe68 | 164 | return (*scr >= glimit); |
5836528f | 165 | } |
feeca497 KA |
166 | |
167 | /* | |
5836528f | 168 | * prpeg: |
608476cd KA |
169 | * Put out the peg character on the score board and put the |
170 | * score up on the board. | |
feeca497 | 171 | */ |
5836528f KA |
172 | prpeg(score, peg, myturn) |
173 | register int score; | |
174 | char peg; | |
175 | BOOLEAN myturn; | |
feeca497 | 176 | { |
5836528f KA |
177 | register int y, x; |
178 | ||
5836528f KA |
179 | if (!myturn) |
180 | y = SCORE_Y + 2; | |
181 | else | |
182 | y = SCORE_Y + 5; | |
a410e8bc KA |
183 | |
184 | if (score <= 0 || score >= glimit) { | |
185 | if (peg == '.') | |
186 | peg = ' '; | |
187 | if (score == 0) | |
188 | x = SCORE_X + 2; | |
189 | else { | |
190 | x = SCORE_X + 2; | |
191 | y++; | |
192 | } | |
193 | } | |
194 | else { | |
195 | x = (score - 1) % 30; | |
196 | if (score > 90 || (score > 30 && score <= 60)) { | |
197 | y++; | |
198 | x = 29 - x; | |
199 | } | |
200 | x += x / 5; | |
201 | x += SCORE_X + 3; | |
5836528f | 202 | } |
5836528f | 203 | mvaddch(y, x, peg); |
608476cd | 204 | mvprintw(SCORE_Y + (myturn ? 7 : 1), SCORE_X + 10, "%3d", score); |
feeca497 KA |
205 | } |
206 | ||
feeca497 KA |
207 | /* |
208 | * cdiscard -- the computer figures out what is the best discard for | |
209 | * the crib and puts the best two cards at the end | |
210 | */ | |
211 | ||
212 | cdiscard( mycrib ) | |
213 | ||
214 | BOOLEAN mycrib; | |
215 | { | |
216 | CARD d[ CARDS ], h[ FULLHAND ], cb[ 2 ]; | |
217 | register int i, j, k; | |
218 | int nc, ns; | |
219 | long sums[ 15 ]; | |
220 | static int undo1[15] = {0,0,0,0,0,1,1,1,1,2,2,2,3,3,4}; | |
221 | static int undo2[15] = {1,2,3,4,5,2,3,4,5,3,4,5,4,5,5}; | |
222 | ||
223 | makedeck( d ); | |
224 | nc = CARDS; | |
225 | for( i = 0; i < knownum; i++ ) { /* get all other cards */ | |
226 | remove( known[i], d, nc-- ); | |
227 | } | |
228 | for( i = 0; i < 15; i++ ) sums[i] = 0L; | |
229 | ns = 0; | |
230 | for( i = 0; i < (FULLHAND - 1); i++ ) { | |
231 | cb[0] = chand[i]; | |
232 | for( j = i + 1; j < FULLHAND; j++ ) { | |
233 | cb[1] = chand[j]; | |
234 | for( k = 0; k < FULLHAND; k++ ) h[k] = chand[k]; | |
235 | remove( chand[i], h, FULLHAND ); | |
236 | remove( chand[j], h, FULLHAND - 1 ); | |
237 | for( k = 0; k < nc; k++ ) { | |
56b49d73 | 238 | sums[ns] += scorehand( h, d[k], CINHAND, TRUE, FALSE ); |
feeca497 KA |
239 | if( mycrib ) sums[ns] += adjust( cb, d[k] ); |
240 | else sums[ns] -= adjust( cb, d[k] ); | |
241 | } | |
242 | ++ns; | |
243 | } | |
244 | } | |
245 | j = 0; | |
246 | for( i = 1; i < 15; i++ ) if( sums[i] > sums[j] ) j = i; | |
247 | for( k = 0; k < FULLHAND; k++ ) h[k] = chand[k]; | |
248 | remove( h[ undo1[j] ], chand, FULLHAND ); | |
249 | remove( h[ undo2[j] ], chand, FULLHAND - 1 ); | |
250 | chand[4] = h[ undo1[j] ]; | |
251 | chand[5] = h[ undo2[j] ]; | |
252 | } | |
253 | ||
254 | ||
255 | ||
256 | /* | |
257 | * returns true if some card in hand can be played without exceeding 31 | |
258 | */ | |
259 | ||
260 | anymove( hand, n, sum ) | |
261 | ||
262 | CARD hand[]; | |
263 | int n; | |
264 | int sum; | |
265 | { | |
266 | register int i, j; | |
267 | ||
268 | if( n < 1 ) return( FALSE ); | |
269 | j = hand[0].rank; | |
270 | for( i = 1; i < n; i++ ) { | |
271 | if( hand[i].rank < j ) j = hand[i].rank; | |
272 | } | |
273 | return( sum + VAL( j ) <= 31 ); | |
274 | } | |
275 | ||
276 | ||
277 | ||
278 | /* | |
279 | * anysumto returns the index (0 <= i < n) of the card in hand that brings | |
280 | * the s up to t, or -1 if there is none | |
281 | */ | |
282 | ||
283 | anysumto( hand, n, s, t ) | |
284 | ||
285 | CARD hand[]; | |
286 | int n; | |
287 | int s, t; | |
288 | { | |
289 | register int i; | |
290 | ||
291 | for( i = 0; i < n; i++ ) { | |
292 | if( s + VAL( hand[i].rank ) == t ) return( i ); | |
293 | } | |
294 | return( -1 ); | |
295 | } | |
296 | ||
297 | ||
298 | ||
299 | ||
300 | /* | |
301 | * return the number of cards in h having the given rank value | |
302 | */ | |
303 | ||
304 | numofval( h, n, v ) | |
305 | ||
306 | CARD h[]; | |
307 | int n; | |
308 | int v; | |
309 | { | |
310 | register int i, j; | |
311 | ||
312 | j = 0; | |
313 | for( i = 0; i < n; i++ ) { | |
314 | if( VAL( h[i].rank ) == v ) ++j; | |
315 | } | |
316 | return( j ); | |
317 | } | |
318 | ||
319 | ||
320 | ||
321 | /* | |
322 | * makeknown remembers all n cards in h for future recall | |
323 | */ | |
324 | ||
325 | makeknown( h, n ) | |
326 | ||
327 | CARD h[]; | |
328 | int n; | |
329 | { | |
330 | register int i; | |
331 | ||
332 | for( i = 0; i < n; i++ ) { | |
333 | known[ knownum++ ] = h[i]; | |
334 | } | |
335 | } | |
336 |