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