This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / games / cribbage / io.c
CommitLineData
15637ed4
RG
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifndef lint
35static char sccsid[] = "@(#)io.c 5.8 (Berkeley) 2/28/91";
36#endif /* not lint */
37
38# include <curses.h>
39# include <ctype.h>
40# include <signal.h>
41# include <stdarg.h>
42# include "deck.h"
43# include "cribbage.h"
44# include "cribcur.h"
45
46# define LINESIZE 128
47
48# ifdef CTRL
49# undef CTRL
50# endif
51# define CTRL(X) ('X' - 'A' + 1)
52
53# ifdef notdef /* defined in curses.h */
54# define erasechar() _tty.sg_erase
55# define killchar() _tty.sg_kill
56# endif
57
58char linebuf[ LINESIZE ];
59
60char *rankname[ RANKS ] = { "ACE", "TWO", "THREE", "FOUR",
61 "FIVE", "SIX", "SEVEN", "EIGHT",
62 "NINE", "TEN", "JACK", "QUEEN",
63 "KING" };
64
65char *rankchar[ RANKS ] = { "A", "2", "3", "4", "5", "6", "7",
66 "8", "9", "T", "J", "Q", "K" };
67
68char *suitname[ SUITS ] = { "SPADES", "HEARTS", "DIAMONDS",
69 "CLUBS" };
70
71char *suitchar[ SUITS ] = { "S", "H", "D", "C" };
72
73
74
75/*
76 * msgcard:
77 * Call msgcrd in one of two forms
78 */
79msgcard(c, brief)
80CARD c;
81BOOLEAN brief;
82{
83 if (brief)
84 return msgcrd(c, TRUE, (char *) NULL, TRUE);
85 else
86 return msgcrd(c, FALSE, " of ", FALSE);
87}
88
89
90
91/*
92 * msgcrd:
93 * Print the value of a card in ascii
94 */
95msgcrd(c, brfrank, mid, brfsuit)
96CARD c;
97char *mid;
98BOOLEAN brfrank, brfsuit;
99{
100 if (c.rank == EMPTY || c.suit == EMPTY)
101 return FALSE;
102 if (brfrank)
103 addmsg("%1.1s", rankchar[c.rank]);
104 else
105 addmsg(rankname[c.rank]);
106 if (mid != NULL)
107 addmsg(mid);
108 if (brfsuit)
109 addmsg("%1.1s", suitchar[c.suit]);
110 else
111 addmsg(suitname[c.suit]);
112 return TRUE;
113}
114
115/*
116 * printcard:
117 * Print out a card.
118 */
119printcard(win, cardno, c, blank)
120WINDOW *win;
121int cardno;
122CARD c;
123BOOLEAN blank;
124{
125 prcard(win, cardno * 2, cardno, c, blank);
126}
127
128/*
129 * prcard:
130 * Print out a card on the window at the specified location
131 */
132prcard(win, y, x, c, blank)
133WINDOW *win;
134int y, x;
135CARD c;
136BOOLEAN blank;
137{
138 if (c.rank == EMPTY)
139 return;
140 mvwaddstr(win, y + 0, x, "+-----+");
141 mvwaddstr(win, y + 1, x, "| |");
142 mvwaddstr(win, y + 2, x, "| |");
143 mvwaddstr(win, y + 3, x, "| |");
144 mvwaddstr(win, y + 4, x, "+-----+");
145 if (!blank) {
146 mvwaddch(win, y + 1, x + 1, rankchar[c.rank][0]);
147 waddch(win, suitchar[c.suit][0]);
148 mvwaddch(win, y + 3, x + 4, rankchar[c.rank][0]);
149 waddch(win, suitchar[c.suit][0]);
150 }
151}
152
153/*
154 * prhand:
155 * Print a hand of n cards
156 */
157prhand(h, n, win, blank)
158CARD h[];
159int n;
160WINDOW *win;
161BOOLEAN blank;
162{
163 register int i;
164
165 werase(win);
166 for (i = 0; i < n; i++)
167 printcard(win, i, *h++, blank);
168 wrefresh(win);
169}
170
171
172
173/*
174 * infrom:
175 * reads a card, supposedly in hand, accepting unambigous brief
176 * input, returns the index of the card found...
177 */
178infrom(hand, n, prompt)
179CARD hand[];
180int n;
181char *prompt;
182{
183 register int i, j;
184 CARD crd;
185
186 if (n < 1) {
187 printf("\nINFROM: %d = n < 1!!\n", n);
188 exit(74);
189 }
190 for (;;) {
191 msg(prompt);
192 if (incard(&crd)) { /* if card is full card */
193 if (!isone(crd, hand, n))
194 msg("That's not in your hand");
195 else {
196 for (i = 0; i < n; i++)
197 if (hand[i].rank == crd.rank &&
198 hand[i].suit == crd.suit)
199 break;
200 if (i >= n) {
201 printf("\nINFROM: isone or something messed up\n");
202 exit(77);
203 }
204 return i;
205 }
206 }
207 else /* if not full card... */
208 if (crd.rank != EMPTY) {
209 for (i = 0; i < n; i++)
210 if (hand[i].rank == crd.rank)
211 break;
212 if (i >= n)
213 msg("No such rank in your hand");
214 else {
215 for (j = i + 1; j < n; j++)
216 if (hand[j].rank == crd.rank)
217 break;
218 if (j < n)
219 msg("Ambiguous rank");
220 else
221 return i;
222 }
223 }
224 else
225 msg("Sorry, I missed that");
226 }
227 /* NOTREACHED */
228}
229
230
231
232/*
233 * incard:
234 * Inputs a card in any format. It reads a line ending with a CR
235 * and then parses it.
236 */
237incard(crd)
238CARD *crd;
239{
240 char *getline();
241 register int i;
242 int rnk, sut;
243 char *line, *p, *p1;
244 BOOLEAN retval;
245
246 retval = FALSE;
247 rnk = sut = EMPTY;
248 if (!(line = getline()))
249 goto gotit;
250 p = p1 = line;
251 while( *p1 != ' ' && *p1 != NULL ) ++p1;
252 *p1++ = NULL;
253 if( *p == NULL ) goto gotit;
254 /* IMPORTANT: no real card has 2 char first name */
255 if( strlen(p) == 2 ) { /* check for short form */
256 rnk = EMPTY;
257 for( i = 0; i < RANKS; i++ ) {
258 if( *p == *rankchar[i] ) {
259 rnk = i;
260 break;
261 }
262 }
263 if( rnk == EMPTY ) goto gotit; /* it's nothing... */
264 ++p; /* advance to next char */
265 sut = EMPTY;
266 for( i = 0; i < SUITS; i++ ) {
267 if( *p == *suitchar[i] ) {
268 sut = i;
269 break;
270 }
271 }
272 if( sut != EMPTY ) retval = TRUE;
273 goto gotit;
274 }
275 rnk = EMPTY;
276 for( i = 0; i < RANKS; i++ ) {
277 if( !strcmp( p, rankname[i] ) || !strcmp( p, rankchar[i] ) ) {
278 rnk = i;
279 break;
280 }
281 }
282 if( rnk == EMPTY ) goto gotit;
283 p = p1;
284 while( *p1 != ' ' && *p1 != NULL ) ++p1;
285 *p1++ = NULL;
286 if( *p == NULL ) goto gotit;
287 if( !strcmp( "OF", p ) ) {
288 p = p1;
289 while( *p1 != ' ' && *p1 != NULL ) ++p1;
290 *p1++ = NULL;
291 if( *p == NULL ) goto gotit;
292 }
293 sut = EMPTY;
294 for( i = 0; i < SUITS; i++ ) {
295 if( !strcmp( p, suitname[i] ) || !strcmp( p, suitchar[i] ) ) {
296 sut = i;
297 break;
298 }
299 }
300 if( sut != EMPTY ) retval = TRUE;
301gotit:
302 (*crd).rank = rnk;
303 (*crd).suit = sut;
304 return( retval );
305}
306
307
308
309/*
310 * getuchar:
311 * Reads and converts to upper case
312 */
313getuchar()
314{
315 register int c;
316
317 c = readchar();
318 if (islower(c))
319 c = toupper(c);
320 waddch(Msgwin, c);
321 return c;
322}
323
324/*
325 * number:
326 * Reads in a decimal number and makes sure it is between "lo" and
327 * "hi" inclusive.
328 */
329number(lo, hi, prompt)
330int lo, hi;
331char *prompt;
332{
333 char *getline();
334 register char *p;
335 register int sum;
336
337 sum = 0;
338 for (;;) {
339 msg(prompt);
340 if(!(p = getline()) || *p == NULL) {
341 msg(quiet ? "Not a number" : "That doesn't look like a number");
342 continue;
343 }
344 sum = 0;
345
346 if (!isdigit(*p))
347 sum = lo - 1;
348 else
349 while (isdigit(*p)) {
350 sum = 10 * sum + (*p - '0');
351 ++p;
352 }
353
354 if (*p != ' ' && *p != '\t' && *p != NULL)
355 sum = lo - 1;
356 if (sum >= lo && sum <= hi)
357 return sum;
358 if (sum == lo - 1)
359 msg("that doesn't look like a number, try again --> ");
360 else
361 msg("%d is not between %d and %d inclusive, try again --> ",
362 sum, lo, hi);
363 }
364}
365
366/*
367 * msg:
368 * Display a message at the top of the screen.
369 */
370char Msgbuf[BUFSIZ] = { '\0' };
371
372int Mpos = 0;
373
374static int Newpos = 0;
375
376/* VARARGS1 */
377msg(fmt)
378 char *fmt;
379{
380 va_list ap;
381
382 va_start(ap, fmt);
383 (void)vsprintf(&Msgbuf[Newpos], fmt, ap);
384 va_end(ap);
385 endmsg();
386}
387
388/*
389 * addmsg:
390 * Add things to the current message
391 */
392/* VARARGS1 */
393addmsg(fmt)
394 char *fmt;
395{
396 va_list ap;
397
398 va_start(ap, fmt);
399 (void)vsprintf(&Msgbuf[Newpos], fmt, ap);
400 va_end(ap);
401}
402
403/*
404 * endmsg:
405 * Display a new msg.
406 */
407
408int Lineno = 0;
409
410endmsg()
411{
412 register int len;
413 register char *mp, *omp;
414 static int lastline = 0;
415
416 /*
417 * All messages should start with uppercase
418 */
419 mvaddch(lastline + Y_MSG_START, SCORE_X, ' ');
420 if (islower(Msgbuf[0]) && Msgbuf[1] != ')')
421 Msgbuf[0] = toupper(Msgbuf[0]);
422 mp = Msgbuf;
423 len = strlen(mp);
424 if (len / MSG_X + Lineno >= MSG_Y) {
425 while (Lineno < MSG_Y) {
426 wmove(Msgwin, Lineno++, 0);
427 wclrtoeol(Msgwin);
428 }
429 Lineno = 0;
430 }
431 mvaddch(Lineno + Y_MSG_START, SCORE_X, '*');
432 lastline = Lineno;
433 do {
434 mvwaddstr(Msgwin, Lineno, 0, mp);
435 if ((len = strlen(mp)) > MSG_X) {
436 omp = mp;
437 for (mp = &mp[MSG_X-1]; *mp != ' '; mp--)
438 continue;
439 while (*mp == ' ')
440 mp--;
441 mp++;
442 wmove(Msgwin, Lineno, mp - omp);
443 wclrtoeol(Msgwin);
444 }
445 if (++Lineno >= MSG_Y)
446 Lineno = 0;
447 } while (len > MSG_X);
448 wclrtoeol(Msgwin);
449 Mpos = len;
450 Newpos = 0;
451 wrefresh(Msgwin);
452 refresh();
453 wrefresh(Msgwin);
454}
455
456#ifdef notdef
457/*
458 * doadd:
459 * Perform an add onto the message buffer
460 */
461doadd(fmt, args)
462char *fmt;
463int *args;
464{
465 static FILE junk;
466
467 /*
468 * Do the printf into Msgbuf
469 */
470 junk._flag = _IOWRT + _IOSTRG;
471 junk._ptr = &Msgbuf[Newpos];
472 junk._cnt = 32767;
473 _doprnt(fmt, args, &junk);
474 putc('\0', &junk);
475 Newpos = strlen(Msgbuf);
476}
477#endif
478
479/*
480 * do_wait:
481 * Wait for the user to type ' ' before doing anything else
482 */
483do_wait()
484{
485 register int line;
486 static char prompt[] = { '-', '-', 'M', 'o', 'r', 'e', '-', '-', '\0' };
487
488 if (Mpos + sizeof prompt < MSG_X)
489 wmove(Msgwin, Lineno > 0 ? Lineno - 1 : MSG_Y - 1, Mpos);
490 else {
491 mvwaddch(Msgwin, Lineno, 0, ' ');
492 wclrtoeol(Msgwin);
493 if (++Lineno >= MSG_Y)
494 Lineno = 0;
495 }
496 waddstr(Msgwin, prompt);
497 wrefresh(Msgwin);
498 wait_for(' ');
499}
500
501/*
502 * wait_for
503 * Sit around until the guy types the right key
504 */
505wait_for(ch)
506register char ch;
507{
508 register char c;
509
510 if (ch == '\n')
511 while ((c = readchar()) != '\n')
512 continue;
513 else
514 while (readchar() != ch)
515 continue;
516}
517
518/*
519 * readchar:
520 * Reads and returns a character, checking for gross input errors
521 */
522readchar()
523{
524 register int cnt, y, x;
525 auto char c;
526
527over:
528 cnt = 0;
529 while (read(0, &c, 1) <= 0)
530 if (cnt++ > 100) { /* if we are getting infinite EOFs */
531 bye(); /* quit the game */
532 exit(1);
533 }
534 if (c == CTRL(L)) {
535 wrefresh(curscr);
536 goto over;
537 }
538 if (c == '\r')
539 return '\n';
540 else
541 return c;
542}
543
544/*
545 * getline:
546 * Reads the next line up to '\n' or EOF. Multiple spaces are
547 * compressed to one space; a space is inserted before a ','
548 */
549char *
550getline()
551{
552 register char *sp;
553 register int c, oy, ox;
554 register WINDOW *oscr;
555
556 oscr = stdscr;
557 stdscr = Msgwin;
558 getyx(stdscr, oy, ox);
559 refresh();
560 /*
561 * loop reading in the string, and put it in a temporary buffer
562 */
563 for (sp = linebuf; (c = readchar()) != '\n'; clrtoeol(), refresh()) {
564 if (c == -1)
565 continue;
566 else if (c == erasechar()) { /* process erase character */
567 if (sp > linebuf) {
568 register int i;
569
570 sp--;
571 for (i = strlen(unctrl(*sp)); i; i--)
572 addch('\b');
573 }
574 continue;
575 }
576 else if (c == killchar()) { /* process kill character */
577 sp = linebuf;
578 move(oy, ox);
579 continue;
580 }
581 else if (sp == linebuf && c == ' ')
582 continue;
583 if (sp >= &linebuf[LINESIZE-1] || !(isprint(c) || c == ' '))
584 putchar(CTRL(G));
585 else {
586 if (islower(c))
587 c = toupper(c);
588 *sp++ = c;
589 addstr(unctrl(c));
590 Mpos++;
591 }
592 }
593 *sp = '\0';
594 stdscr = oscr;
595 return linebuf;
596}
597
598rint()
599{
600 bye();
601 exit(1);
602}
603
604/*
605 * bye:
606 * Leave the program, cleaning things up as we go.
607 */
608bye()
609{
610 signal(SIGINT, SIG_IGN);
611 mvcur(0, COLS - 1, LINES - 1, 0);
612 fflush(stdout);
613 endwin();
614 putchar('\n');
615}