bdisp.c revision 1.26
1/*	$NetBSD: bdisp.c,v 1.26 2022/05/16 21:48:45 rillig Exp $	*/
2
3/*
4 * Copyright (c) 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Ralph Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/cdefs.h>
36#ifndef lint
37#if 0
38static char sccsid[] = "@(#)bdisp.c	8.2 (Berkeley) 5/3/95";
39#else
40__RCSID("$NetBSD: bdisp.c,v 1.26 2022/05/16 21:48:45 rillig Exp $");
41#endif
42#endif /* not lint */
43
44#include <curses.h>
45#include <string.h>
46#include <stdlib.h>
47#include <err.h>
48#include "gomoku.h"
49
50#define	SCRNH		24		/* assume 24 lines for the moment */
51#define	SCRNW		80		/* assume 80 chars for the moment */
52
53static	int	lastline;
54static	char	pcolor[] = "*O.?";
55
56/*
57 * Initialize screen display.
58 */
59void
60cursinit(void)
61{
62
63	if (initscr() == NULL) {
64		errx(EXIT_FAILURE, "Couldn't initialize screen");
65	}
66	if ((LINES < SCRNH) || (COLS < SCRNW)) {
67		errx(EXIT_FAILURE, "Screen too small (need %d%xd)",
68		    SCRNW, SCRNH);
69	}
70	keypad(stdscr, true);
71	nonl();
72	noecho();
73	cbreak();
74	leaveok(stdscr, FALSE);
75
76#if 0 /* no mouse support in netbsd curses yet */
77	mousemask(BUTTON1_CLICKED, NULL);
78#endif
79}
80
81/*
82 * Restore screen display.
83 */
84void
85cursfini(void)
86{
87
88	move(BSZ + 4, 0);
89	clrtoeol();
90	refresh();
91	echo();
92	endwin();
93}
94
95/*
96 * Initialize board display.
97 */
98void
99bdisp_init(void)
100{
101	int i, j;
102
103	/* top border */
104	for (i = 1; i < BSZ + 1; i++) {
105		move(0, 2 * i + 1);
106		addch(letters[i]);
107	}
108	/* left and right edges */
109	for (j = BSZ + 1; --j > 0; ) {
110		move(20 - j, 0);
111		printw("%2d ", j);
112		move(20 - j, 2 * (BSZ + 1) + 1);
113		printw("%d ", j);
114	}
115	/* bottom border */
116	for (i = 1; i < BSZ + 1; i++) {
117		move(20, 2 * i + 1);
118		addch(letters[i]);
119	}
120	bdwho(false);
121	move(0, 47);
122	addstr("#  black  white");
123	lastline = 0;
124	bdisp();
125}
126
127/*
128 * Update who is playing whom.
129 */
130void
131bdwho(bool update)
132{
133	int i, j;
134
135	move(21, 0);
136	printw("                                              ");
137	i = (int)strlen(plyr[BLACK]);
138	j = (int)strlen(plyr[WHITE]);
139	if (i + j <= 20) {
140		move(21, 10 - (i + j) / 2);
141		printw("BLACK/%s (*) vs. WHITE/%s (O)",
142		    plyr[BLACK], plyr[WHITE]);
143	} else {
144		move(21, 0);
145		if (i <= 10) {
146			j = 20 - i;
147		} else if (j <= 10) {
148			i = 20 - j;
149		} else {
150			i = j = 10;
151		}
152		printw("BLACK/%.*s (*) vs. WHITE/%.*s (O)",
153		    i, plyr[BLACK], j, plyr[WHITE]);
154	}
155	if (update)
156		refresh();
157}
158
159/*
160 * Update the board display after a move.
161 */
162void
163bdisp(void)
164{
165	int i, j, c;
166	struct spotstr *sp;
167
168	for (j = BSZ + 1; --j > 0; ) {
169		for (i = 1; i < BSZ + 1; i++) {
170			move(BSZ + 1 - j, 2 * i + 1);
171			sp = &board[i + j * (BSZ + 1)];
172			if (debug > 1 && sp->s_occ == EMPTY) {
173				if ((sp->s_flags & IFLAGALL) != 0)
174					c = '+';
175				else if ((sp->s_flags & CFLAGALL) != 0)
176					c = '-';
177				else
178					c = '.';
179			} else
180				c = pcolor[sp->s_occ];
181			addch(c);
182		}
183	}
184	refresh();
185}
186
187#ifdef DEBUG
188/*
189 * Dump board display to a file.
190 */
191void
192bdump(FILE *fp)
193{
194	int i, j, c;
195	struct spotstr *sp;
196
197	/* top border */
198	fprintf(fp, "   A B C D E F G H J K L M N O P Q R S T\n");
199
200	for (j = BSZ + 1; --j > 0; ) {
201		/* left edge */
202		fprintf(fp, "%2d ", j);
203		for (i = 1; i < BSZ + 1; i++) {
204			sp = &board[i + j * (BSZ + 1)];
205			if (debug > 1 && sp->s_occ == EMPTY) {
206				if ((sp->s_flags & IFLAGALL) != 0)
207					c = '+';
208				else if ((sp->s_flags & CFLAGALL) != 0)
209					c = '-';
210				else
211					c = '.';
212			} else
213				c = pcolor[sp->s_occ];
214			putc(c, fp);
215			putc(' ', fp);
216		}
217		/* right edge */
218		fprintf(fp, "%d\n", j);
219	}
220
221	/* bottom border */
222	fprintf(fp, "   A B C D E F G H J K L M N O P Q R S T\n");
223}
224#endif /* DEBUG */
225
226/*
227 * Display a transcript entry
228 */
229void
230dislog(const char *str)
231{
232
233	if (++lastline >= SCRNH - 1) {
234		/* move 'em up */
235		lastline = 1;
236	}
237	move(lastline, TRANSCRIPT_COL);
238	addnstr(str, SCRNW - TRANSCRIPT_COL - 1);
239	clrtoeol();
240	move(lastline + 1, TRANSCRIPT_COL);
241	clrtoeol();
242}
243
244/*
245 * Display a question.
246 */
247
248void
249ask(const char *str)
250{
251	int len = (int)strlen(str);
252
253	move(BSZ + 4, 0);
254	addstr(str);
255	clrtoeol();
256	move(BSZ + 4, len);
257	refresh();
258}
259
260int
261get_key(const char *allowed)
262{
263	int ch;
264
265	for (;;) {
266		ch = getch();
267		if (allowed != NULL &&
268		    ch != '\0' && strchr(allowed, ch) == NULL) {
269			beep();
270			refresh();
271			continue;
272		}
273		break;
274	}
275	return ch;
276}
277
278bool
279get_line(char *buf, int size)
280{
281	char *cp, *end;
282	int c;
283
284	c = 0;
285	cp = buf;
286	end = buf + size - 1;	/* save room for the '\0' */
287	while (cp < end && (c = getchar()) != EOF && c != '\n' && c != '\r') {
288		*cp++ = c;
289		if (interactive) {
290			switch (c) {
291			case 0x0c: /* ^L */
292				wrefresh(curscr);
293				cp--;
294				continue;
295			case 0x15: /* ^U */
296			case 0x18: /* ^X */
297				while (cp > buf) {
298					cp--;
299					addch('\b');
300				}
301				clrtoeol();
302				break;
303			case '\b':
304			case 0x7f: /* DEL */
305				if (cp == buf + 1) {
306					cp--;
307					continue;
308				}
309				cp -= 2;
310				addch('\b');
311				c = ' ';
312				/* FALLTHROUGH */
313			default:
314				addch(c);
315			}
316			refresh();
317		}
318	}
319	*cp = '\0';
320	return c != EOF;
321}
322
323/*
324 * Decent (n)curses interface for the game, based on Eric S. Raymond's
325 * modifications to the battleship (bs) user interface.
326 */
327int
328get_coord(void)
329{
330	static int curx = BSZ / 2;
331	static int cury = BSZ / 2;
332	int ny, nx, ch;
333
334	BGOTO(cury, curx);
335	refresh();
336	nx = curx;
337	ny = cury;
338	for (;;) {
339		mvprintw(BSZ + 3, (BSZ - 6) / 2, "(%c %d) ",
340		    'A' + ((curx > 7) ? (curx + 1) : curx), cury + 1);
341		BGOTO(cury, curx);
342
343		ch = getch();
344		switch (ch) {
345		case 'k':
346		case '8':
347		case KEY_UP:
348			nx = curx;
349			ny = cury + 1;
350			break;
351		case 'j':
352		case '2':
353		case KEY_DOWN:
354			nx = curx;
355			ny = BSZ + cury - 1;
356			break;
357		case 'h':
358		case '4':
359		case KEY_LEFT:
360			nx = BSZ + curx - 1;
361			ny = cury;
362			break;
363		case 'l':
364		case '6':
365		case KEY_RIGHT:
366			nx = curx + 1;
367			ny = cury;
368			break;
369		case 'y':
370		case '7':
371		case KEY_A1:
372			nx = BSZ + curx - 1;
373			ny = cury + 1;
374			break;
375		case 'b':
376		case '1':
377		case KEY_C1:
378			nx = BSZ + curx - 1;
379			ny = BSZ + cury - 1;
380			break;
381		case 'u':
382		case '9':
383		case KEY_A3:
384			nx = curx + 1;
385			ny = cury + 1;
386			break;
387		case 'n':
388		case '3':
389		case KEY_C3:
390			nx = curx + 1;
391			ny = BSZ + cury - 1;
392			break;
393		case 'K':
394			nx = curx;
395			ny = cury + 5;
396			break;
397		case 'J':
398			nx = curx;
399			ny = BSZ + cury - 5;
400			break;
401		case 'H':
402			nx = BSZ + curx - 5;
403			ny = cury;
404			break;
405		case 'L':
406			nx = curx + 5;
407			ny = cury;
408			break;
409		case 'Y':
410			nx = BSZ + curx - 5;
411			ny = cury + 5;
412			break;
413		case 'B':
414			nx = BSZ + curx - 5;
415			ny = BSZ + cury - 5;
416			break;
417		case 'U':
418			nx = curx + 5;
419			ny = cury + 5;
420			break;
421		case 'N':
422			nx = curx + 5;
423			ny = BSZ + cury - 5;
424			break;
425		case '\f':
426			nx = curx;
427			ny = cury;
428			(void)clearok(stdscr, true);
429			(void)refresh();
430			break;
431#if 0 /* notyet */
432		case KEY_MOUSE:
433		{
434			MEVENT	myevent;
435
436			getmouse(&myevent);
437			if (myevent.y >= 1 && myevent.y <= BSZ + 1 &&
438			    myevent.x >= 3 && myevent.x <= 2 * BSZ + 1) {
439				curx = (myevent.x - 3) / 2;
440				cury = BSZ - myevent.y;
441				return PT(curx,cury);
442			} else {
443				beep();
444			}
445		}
446		break;
447#endif /* 0 */
448		case 'Q':
449		case 'q':
450			return RESIGN;
451		case 'S':
452		case 's':
453			return SAVE;
454		case ' ':
455		case '\r':
456			(void)mvaddstr(BSZ + 3, (BSZ - 6) / 2, "      ");
457			return PT(curx + 1, cury + 1);
458		}
459
460		curx = nx % BSZ;
461		cury = ny % BSZ;
462	}
463}
464