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