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