Commit | Line | Data |
---|---|---|
5836528f KA |
1 | # include <curses.h> |
2 | # include <ctype.h> | |
3 | # include <unctrl.h> | |
4 | # include "deck.h" | |
5 | # include "cribbage.h" | |
cd994cb6 | 6 | |
5836528f | 7 | # define LINESIZE 128 |
cd994cb6 | 8 | |
5836528f KA |
9 | # define CTRL(X) ('X' - 'A' + 1) |
10 | ||
11 | # ifndef attron | |
12 | # define erasechar() _tty.sg_erase | |
13 | # define killchar() _tty.sg_kill | |
14 | # endif attron | |
cd994cb6 KA |
15 | |
16 | char linebuf[ LINESIZE ]; | |
17 | ||
18 | char *rankname[ RANKS ] = { "ACE", "TWO", "THREE", "FOUR", | |
5836528f KA |
19 | "FIVE", "SIX", "SEVEN", "EIGHT", |
20 | "NINE", "TEN", "JACK", "QUEEN", | |
21 | "KING" }; | |
cd994cb6 KA |
22 | |
23 | char *rankchar[ RANKS ] = { "A", "2", "3", "4", "5", "6", "7", | |
5836528f | 24 | "8", "9", "T", "J", "Q", "K" }; |
cd994cb6 KA |
25 | |
26 | char *suitname[ SUITS ] = { "SPADES", "HEARTS", "DIAMONDS", | |
5836528f | 27 | "CLUBS" }; |
cd994cb6 KA |
28 | |
29 | char *suitchar[ SUITS ] = { "S", "H", "D", "C" }; | |
30 | ||
31 | ||
32 | ||
33 | /* | |
5836528f KA |
34 | * msgcard: |
35 | * Call msgcrd in one of two forms | |
cd994cb6 | 36 | */ |
5836528f KA |
37 | msgcard(c, brief) |
38 | CARD c; | |
39 | BOOLEAN brief; | |
cd994cb6 | 40 | { |
5836528f KA |
41 | if (brief) |
42 | return msgcrd(c, TRUE, (char *) NULL, TRUE); | |
43 | else | |
44 | return msgcrd(c, FALSE, " of ", FALSE); | |
cd994cb6 KA |
45 | } |
46 | ||
47 | ||
48 | ||
49 | /* | |
5836528f KA |
50 | * msgcrd: |
51 | * Print the value of a card in ascii | |
cd994cb6 | 52 | */ |
5836528f KA |
53 | msgcrd(c, brfrank, mid, brfsuit) |
54 | CARD c; | |
55 | char *mid; | |
56 | BOOLEAN brfrank, brfsuit; | |
cd994cb6 | 57 | { |
5836528f KA |
58 | if (c.rank == EMPTY || c.suit == EMPTY) |
59 | return FALSE; | |
60 | if (brfrank) | |
61 | addmsg("%1.1s", rankchar[c.rank]); | |
62 | else | |
63 | addmsg(rankname[c.rank]); | |
64 | if (mid != NULL) | |
65 | addmsg(mid); | |
66 | if (brfsuit) | |
67 | addmsg("%1.1s", suitchar[c.suit]); | |
68 | else | |
69 | addmsg(suitname[c.suit]); | |
70 | return TRUE; | |
cd994cb6 KA |
71 | } |
72 | ||
cd994cb6 | 73 | /* |
5836528f KA |
74 | * printcard: |
75 | * Print out a card. | |
cd994cb6 | 76 | */ |
5836528f KA |
77 | printcard(win, cardno, c) |
78 | WINDOW *win; | |
79 | int cardno; | |
80 | CARD c; | |
81 | { | |
f62fed8c | 82 | prcard(win, cardno * 2, cardno, c, FALSE); |
5836528f | 83 | } |
cd994cb6 | 84 | |
5836528f KA |
85 | /* |
86 | * prcard: | |
87 | * Print out a card on the window at the specified location | |
88 | */ | |
f62fed8c | 89 | prcard(win, y, x, c, blank) |
5836528f KA |
90 | WINDOW *win; |
91 | int y, x; | |
92 | CARD c; | |
f62fed8c | 93 | BOOLEAN blank; |
5836528f KA |
94 | { |
95 | if (c.rank == EMPTY) | |
96 | return; | |
97 | mvwaddstr(win, y + 0, x, "+-----+"); | |
98 | mvwaddstr(win, y + 1, x, "| |"); | |
99 | mvwaddstr(win, y + 2, x, "| |"); | |
100 | mvwaddstr(win, y + 3, x, "| |"); | |
101 | mvwaddstr(win, y + 4, x, "+-----+"); | |
f62fed8c KA |
102 | if (!blank) { |
103 | mvwaddch(win, y + 1, x + 1, rankchar[c.rank][0]); | |
104 | waddch(win, suitchar[c.suit][0]); | |
105 | mvwaddch(win, y + 3, x + 4, rankchar[c.rank][0]); | |
106 | waddch(win, suitchar[c.suit][0]); | |
107 | } | |
5836528f | 108 | } |
cd994cb6 | 109 | |
5836528f KA |
110 | /* |
111 | * prhand: | |
112 | * Print a hand of n cards | |
113 | */ | |
114 | prhand(h, n, win) | |
115 | CARD h[]; | |
116 | int n; | |
117 | WINDOW *win; | |
cd994cb6 | 118 | { |
5836528f KA |
119 | register int i; |
120 | ||
121 | werase(win); | |
122 | for (i = 0; i < n; i++) | |
123 | printcard(win, i, h[i]); | |
124 | wrefresh(win); | |
cd994cb6 KA |
125 | } |
126 | ||
127 | ||
128 | ||
129 | /* | |
5836528f KA |
130 | * infrom: |
131 | * reads a card, supposedly in hand, accepting unambigous brief | |
132 | * input, returns the index of the card found... | |
cd994cb6 | 133 | */ |
5836528f KA |
134 | infrom(hand, n, prompt) |
135 | CARD hand[]; | |
136 | int n; | |
137 | char *prompt; | |
cd994cb6 | 138 | { |
5836528f KA |
139 | register int i, j; |
140 | CARD crd; | |
141 | ||
142 | if (n < 1) { | |
143 | printf("\nINFROM: %d = n < 1!!\n", n); | |
144 | exit(74); | |
145 | } | |
146 | for (;;) { | |
59d2ab16 | 147 | msg(prompt); |
5836528f KA |
148 | if (incard(&crd)) { /* if card is full card */ |
149 | if (!isone(crd, hand, n)) | |
150 | msg("That's not in your hand"); | |
151 | else { | |
152 | for (i = 0; i < n; i++) | |
153 | if (hand[i].rank == crd.rank && | |
154 | hand[i].suit == crd.suit) | |
155 | break; | |
156 | if (i >= n) { | |
157 | printf("\nINFROM: isone or something messed up\n"); | |
158 | exit(77); | |
159 | } | |
160 | return i; | |
161 | } | |
162 | } | |
163 | else /* if not full card... */ | |
164 | if (crd.rank != EMPTY) { | |
165 | for (i = 0; i < n; i++) | |
166 | if (hand[i].rank == crd.rank) | |
167 | break; | |
168 | if (i >= n) | |
169 | msg("No such rank in your hand"); | |
170 | else { | |
171 | for (j = i + 1; j < n; j++) | |
172 | if (hand[j].rank == crd.rank) | |
173 | break; | |
174 | if (j < n) | |
175 | msg("Ambiguous rank"); | |
176 | else | |
177 | return i; | |
178 | } | |
179 | } | |
180 | else | |
181 | msg("Sorry, I missed that"); | |
5836528f KA |
182 | } |
183 | /* NOTREACHED */ | |
cd994cb6 KA |
184 | } |
185 | ||
186 | ||
187 | ||
188 | /* | |
5836528f KA |
189 | * incard: |
190 | * Inputs a card in any format. It reads a line ending with a CR | |
191 | * and then parses it. | |
cd994cb6 | 192 | */ |
5836528f KA |
193 | incard(crd) |
194 | CARD *crd; | |
cd994cb6 | 195 | { |
5836528f KA |
196 | char *getline(); |
197 | register int i; | |
198 | int rnk, sut; | |
199 | char *line, *p, *p1; | |
200 | BOOLEAN retval; | |
201 | ||
202 | retval = FALSE; | |
203 | rnk = sut = EMPTY; | |
204 | if (!(line = getline())) | |
205 | goto gotit; | |
206 | p = p1 = line; | |
207 | while( *p1 != ' ' && *p1 != NULL ) ++p1; | |
208 | *p1++ = NULL; | |
209 | if( *p == NULL ) goto gotit; | |
210 | /* IMPORTANT: no real card has 2 char first name */ | |
211 | if( strlen(p) == 2 ) { /* check for short form */ | |
212 | rnk = EMPTY; | |
213 | for( i = 0; i < RANKS; i++ ) { | |
214 | if( *p == *rankchar[i] ) { | |
215 | rnk = i; | |
216 | break; | |
217 | } | |
218 | } | |
219 | if( rnk == EMPTY ) goto gotit; /* it's nothing... */ | |
220 | ++p; /* advance to next char */ | |
221 | sut = EMPTY; | |
222 | for( i = 0; i < SUITS; i++ ) { | |
223 | if( *p == *suitchar[i] ) { | |
224 | sut = i; | |
225 | break; | |
226 | } | |
227 | } | |
228 | if( sut != EMPTY ) retval = TRUE; | |
229 | goto gotit; | |
230 | } | |
231 | rnk = EMPTY; | |
232 | for( i = 0; i < RANKS; i++ ) { | |
233 | if( !strcmp( p, rankname[i] ) || !strcmp( p, rankchar[i] ) ) { | |
234 | rnk = i; | |
235 | break; | |
236 | } | |
237 | } | |
238 | if( rnk == EMPTY ) goto gotit; | |
239 | p = p1; | |
240 | while( *p1 != ' ' && *p1 != NULL ) ++p1; | |
241 | *p1++ = NULL; | |
242 | if( *p == NULL ) goto gotit; | |
243 | if( !strcmp( "OF", p ) ) { | |
244 | p = p1; | |
245 | while( *p1 != ' ' && *p1 != NULL ) ++p1; | |
246 | *p1++ = NULL; | |
247 | if( *p == NULL ) goto gotit; | |
248 | } | |
249 | sut = EMPTY; | |
250 | for( i = 0; i < SUITS; i++ ) { | |
251 | if( !strcmp( p, suitname[i] ) || !strcmp( p, suitchar[i] ) ) { | |
252 | sut = i; | |
253 | break; | |
254 | } | |
255 | } | |
256 | if( sut != EMPTY ) retval = TRUE; | |
cd994cb6 | 257 | gotit: |
5836528f KA |
258 | (*crd).rank = rnk; |
259 | (*crd).suit = sut; | |
260 | return( retval ); | |
cd994cb6 KA |
261 | } |
262 | ||
263 | ||
264 | ||
265 | /* | |
5836528f KA |
266 | * getuchar: |
267 | * Reads and converts to upper case | |
cd994cb6 | 268 | */ |
cd994cb6 KA |
269 | getuchar() |
270 | { | |
5836528f | 271 | register int c; |
cd994cb6 | 272 | |
5836528f KA |
273 | c = readchar(); |
274 | if (islower(c)) | |
275 | c = toupper(c); | |
276 | addch(c); | |
277 | return c; | |
cd994cb6 KA |
278 | } |
279 | ||
cd994cb6 | 280 | /* |
d864f6e8 KA |
281 | * number: |
282 | * Reads in a decimal number and makes sure it is between "lo" and | |
283 | * "hi" inclusive. | |
cd994cb6 | 284 | */ |
d864f6e8 KA |
285 | number(lo, hi, prompt) |
286 | int lo, hi; | |
287 | char *prompt; | |
cd994cb6 | 288 | { |
d864f6e8 KA |
289 | char *getline(); |
290 | register char *p; | |
291 | register int sum; | |
5836528f KA |
292 | |
293 | sum = 0; | |
d864f6e8 KA |
294 | for (;;) { |
295 | msg(prompt); | |
296 | if(!(p = getline()) || *p == NULL) { | |
297 | msg(quiet ? "Not a number" : "That doesn't look like a number"); | |
298 | continue; | |
299 | } | |
5836528f | 300 | sum = 0; |
d864f6e8 KA |
301 | |
302 | if (!isdigit(*p)) | |
5836528f | 303 | sum = lo - 1; |
d864f6e8 KA |
304 | else |
305 | while (isdigit(*p)) { | |
306 | sum = 10 * sum + (*p - '0'); | |
5836528f | 307 | ++p; |
d864f6e8 KA |
308 | } |
309 | ||
310 | if (*p != ' ' && *p != '\t' && *p != NULL) | |
311 | sum = lo - 1; | |
312 | if (sum >= lo && sum <= hi) | |
313 | return sum; | |
314 | if (sum == lo - 1) | |
315 | msg("that doesn't look like a number, try again --> "); | |
316 | else | |
317 | msg("%d is not between %d and %d inclusive, try again --> ", | |
318 | sum, lo, hi); | |
319 | } | |
cd994cb6 KA |
320 | } |
321 | ||
5836528f KA |
322 | /* |
323 | * msg: | |
324 | * Display a message at the top of the screen. | |
325 | */ | |
326 | char Msgbuf[BUFSIZ] = ""; | |
327 | ||
328 | int Mpos = 0; | |
cd994cb6 | 329 | |
5836528f KA |
330 | static int Newpos = 0; |
331 | ||
332 | /* VARARGS1 */ | |
333 | msg(fmt, args) | |
334 | char *fmt; | |
335 | int args; | |
336 | { | |
337 | /* | |
338 | * if the string is "", just clear the line | |
339 | */ | |
340 | if (*fmt == '\0') { | |
341 | move(LINES - 1, 0); | |
342 | clrtoeol(); | |
343 | Mpos = 0; | |
344 | Hasread = TRUE; | |
345 | return; | |
346 | } | |
347 | /* | |
348 | * otherwise add to the message and flush it out | |
349 | */ | |
350 | doadd(fmt, &args); | |
351 | endmsg(); | |
352 | } | |
cd994cb6 KA |
353 | |
354 | /* | |
5836528f KA |
355 | * addmsg: |
356 | * Add things to the current message | |
cd994cb6 | 357 | */ |
5836528f KA |
358 | /* VARARGS1 */ |
359 | addmsg(fmt, args) | |
360 | char *fmt; | |
361 | int args; | |
362 | { | |
363 | doadd(fmt, &args); | |
364 | } | |
cd994cb6 | 365 | |
5836528f KA |
366 | /* |
367 | * endmsg: | |
368 | * Display a new msg (giving him a chance to see the previous one | |
369 | * if it is up there with the --More--) | |
370 | */ | |
371 | endmsg() | |
cd994cb6 | 372 | { |
5836528f KA |
373 | if (!Hasread) { |
374 | move(LINES - 1, Mpos); | |
375 | addstr("--More--"); | |
376 | refresh(); | |
377 | wait_for(' '); | |
378 | } | |
379 | /* | |
380 | * All messages should start with uppercase, except ones that | |
381 | * start with a pack addressing character | |
382 | */ | |
383 | if (islower(Msgbuf[0]) && Msgbuf[1] != ')') | |
384 | Msgbuf[0] = toupper(Msgbuf[0]); | |
385 | mvaddstr(LINES - 1, 0, Msgbuf); | |
386 | clrtoeol(); | |
387 | Mpos = Newpos; | |
388 | Newpos = 0; | |
389 | refresh(); | |
390 | Hasread = FALSE; | |
cd994cb6 KA |
391 | } |
392 | ||
5836528f KA |
393 | /* |
394 | * doadd: | |
395 | * Perform an add onto the message buffer | |
396 | */ | |
397 | doadd(fmt, args) | |
398 | char *fmt; | |
399 | int *args; | |
400 | { | |
401 | static FILE junk; | |
402 | ||
403 | /* | |
404 | * Do the printf into Msgbuf | |
405 | */ | |
406 | junk._flag = _IOWRT + _IOSTRG; | |
407 | junk._ptr = &Msgbuf[Newpos]; | |
408 | junk._cnt = 32767; | |
409 | _doprnt(fmt, args, &junk); | |
410 | putc('\0', &junk); | |
411 | Newpos = strlen(Msgbuf); | |
412 | } | |
cd994cb6 | 413 | |
5836528f KA |
414 | /* |
415 | * wait_for | |
416 | * Sit around until the guy types the right key | |
417 | */ | |
418 | wait_for(ch) | |
419 | register char ch; | |
420 | { | |
421 | register char c; | |
422 | ||
423 | if (ch == '\n') | |
424 | while ((c = readchar()) != '\n') | |
425 | continue; | |
426 | else | |
427 | while (readchar() != ch) | |
428 | continue; | |
429 | } | |
cd994cb6 | 430 | |
5836528f KA |
431 | /* |
432 | * readchar: | |
433 | * Reads and returns a character, checking for gross input errors | |
434 | */ | |
435 | readchar() | |
436 | { | |
437 | register int cnt, y, x; | |
438 | auto char c; | |
439 | ||
440 | over: | |
441 | cnt = 0; | |
442 | while (read(0, &c, 1) <= 0) | |
443 | if (cnt++ > 100) /* if we are getting infinite EOFs */ | |
444 | bye(); /* quit the game */ | |
445 | if (c == CTRL(L)) { | |
446 | wrefresh(curscr); | |
447 | goto over; | |
448 | } | |
449 | Hasread = TRUE; | |
450 | if (c == '\r') | |
451 | return '\n'; | |
452 | else | |
453 | return c; | |
454 | } | |
cd994cb6 | 455 | |
5836528f KA |
456 | /* |
457 | * getline: | |
458 | * Reads the next line up to '\n' or EOF. Multiple spaces are | |
459 | * compressed to one space; a space is inserted before a ',' | |
460 | */ | |
461 | char * | |
462 | getline() | |
463 | { | |
464 | register char *sp; | |
465 | register int c, oy, ox; | |
466 | ||
467 | getyx(stdscr, oy, ox); | |
468 | refresh(); | |
469 | /* | |
470 | * loop reading in the string, and put it in a temporary buffer | |
471 | */ | |
472 | for (sp = linebuf; (c = readchar()) != '\n'; clrtoeol(), refresh()) { | |
473 | if (c == -1) | |
474 | continue; | |
475 | else if (c == erasechar()) { /* process erase character */ | |
476 | if (sp > linebuf) { | |
477 | register int i; | |
478 | ||
479 | sp--; | |
480 | for (i = strlen(unctrl(*sp)); i; i--) | |
481 | addch('\b'); | |
482 | } | |
483 | continue; | |
484 | } | |
485 | else if (c == killchar()) { /* process kill character */ | |
486 | sp = linebuf; | |
487 | move(oy, ox); | |
488 | continue; | |
489 | } | |
490 | else if (sp == linebuf && c == ' ') | |
491 | continue; | |
492 | if (sp >= &linebuf[LINESIZE-1] || !(isprint(c) || c == ' ')) | |
493 | putchar(CTRL(G)); | |
494 | else { | |
495 | if (islower(c)) | |
496 | c = toupper(c); | |
497 | *sp++ = c; | |
498 | addstr(unctrl(c)); | |
499 | /*###366 [cc] Mpos undefined %%%*/ | |
500 | Mpos++; | |
501 | } | |
502 | } | |
503 | *sp = '\0'; | |
504 | return linebuf; | |
505 | } |