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