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