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