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