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