bdisp.c revision 1.28
1/*	$NetBSD: bdisp.c,v 1.28 2022/05/18 22:30:19 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.28 2022/05/18 22:30:19 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
102	/* top border */
103	for (int i = 1; i < BSZ + 1; i++) {
104		move(0, 2 * i + 1);
105		addch(letters[i]);
106	}
107	/* left and right edges */
108	for (int j = BSZ + 1; --j > 0; ) {
109		move(20 - j, 0);
110		printw("%2d ", j);
111		move(20 - j, 2 * (BSZ + 1) + 1);
112		printw("%d ", j);
113	}
114	/* bottom border */
115	for (int i = 1; i < BSZ + 1; i++) {
116		move(20, 2 * i + 1);
117		addch(letters[i]);
118	}
119	bdwho(false);
120	move(0, 47);
121	addstr("#  black  white");
122	lastline = 0;
123	bdisp();
124}
125
126/*
127 * Update who is playing whom.
128 */
129void
130bdwho(bool update)
131{
132	int i, j;
133
134	move(21, 0);
135	printw("                                              ");
136	i = (int)strlen(plyr[BLACK]);
137	j = (int)strlen(plyr[WHITE]);
138	if (i + j <= 20) {
139		move(21, 10 - (i + j) / 2);
140		printw("BLACK/%s (*) vs. WHITE/%s (O)",
141		    plyr[BLACK], plyr[WHITE]);
142	} else {
143		move(21, 0);
144		if (i <= 10) {
145			j = 20 - i;
146		} else if (j <= 10) {
147			i = 20 - j;
148		} else {
149			i = j = 10;
150		}
151		printw("BLACK/%.*s (*) vs. WHITE/%.*s (O)",
152		    i, plyr[BLACK], j, plyr[WHITE]);
153	}
154	if (update)
155		refresh();
156}
157
158/*
159 * Update the board display after a move.
160 */
161void
162bdisp(void)
163{
164	int c;
165	struct spotstr *sp;
166
167	for (int j = BSZ + 1; --j > 0; ) {
168		for (int i = 1; i < BSZ + 1; i++) {
169			move(BSZ + 1 - j, 2 * i + 1);
170			sp = &board[i + j * (BSZ + 1)];
171			if (debug > 1 && sp->s_occ == EMPTY) {
172				if ((sp->s_flags & IFLAGALL) != 0)
173					c = '+';
174				else if ((sp->s_flags & CFLAGALL) != 0)
175					c = '-';
176				else
177					c = '.';
178			} else
179				c = pcolor[sp->s_occ];
180			if (movenum > 1 && movelog[movenum - 2] == PT(i, j)) {
181				attron(A_BOLD);
182				addch(c);
183				attroff(A_BOLD);
184			} else
185				addch(c);
186		}
187	}
188	refresh();
189}
190
191#ifdef DEBUG
192/*
193 * Dump board display to a file.
194 */
195void
196bdump(FILE *fp)
197{
198	int c;
199	struct spotstr *sp;
200
201	/* top border */
202	fprintf(fp, "   A B C D E F G H J K L M N O P Q R S T\n");
203
204	for (int j = BSZ + 1; --j > 0; ) {
205		/* left edge */
206		fprintf(fp, "%2d ", j);
207		for (int i = 1; i < BSZ + 1; i++) {
208			sp = &board[i + j * (BSZ + 1)];
209			if (debug > 1 && sp->s_occ == EMPTY) {
210				if ((sp->s_flags & IFLAGALL) != 0)
211					c = '+';
212				else if ((sp->s_flags & CFLAGALL) != 0)
213					c = '-';
214				else
215					c = '.';
216			} else
217				c = pcolor[sp->s_occ];
218			putc(c, fp);
219			putc(' ', fp);
220		}
221		/* right edge */
222		fprintf(fp, "%d\n", j);
223	}
224
225	/* bottom border */
226	fprintf(fp, "   A B C D E F G H J K L M N O P Q R S T\n");
227}
228#endif /* DEBUG */
229
230/*
231 * Display a transcript entry
232 */
233void
234dislog(const char *str)
235{
236
237	if (++lastline >= SCRNH - 1) {
238		/* move 'em up */
239		lastline = 1;
240	}
241	move(lastline, TRANSCRIPT_COL);
242	addnstr(str, SCRNW - TRANSCRIPT_COL - 1);
243	clrtoeol();
244	move(lastline + 1, TRANSCRIPT_COL);
245	clrtoeol();
246}
247
248/*
249 * Display a question.
250 */
251
252void
253ask(const char *str)
254{
255	int len = (int)strlen(str);
256
257	move(BSZ + 4, 0);
258	addstr(str);
259	clrtoeol();
260	move(BSZ + 4, len);
261	refresh();
262}
263
264int
265get_key(const char *allowed)
266{
267	int ch;
268
269	for (;;) {
270		ch = getch();
271		if (allowed != NULL &&
272		    ch != '\0' && strchr(allowed, ch) == NULL) {
273			beep();
274			refresh();
275			continue;
276		}
277		break;
278	}
279	return ch;
280}
281
282bool
283get_line(char *buf, int size)
284{
285	char *cp, *end;
286	int c;
287
288	c = 0;
289	cp = buf;
290	end = buf + size - 1;	/* save room for the '\0' */
291	while (cp < end && (c = getchar()) != EOF && c != '\n' && c != '\r') {
292		*cp++ = c;
293		if (interactive) {
294			switch (c) {
295			case 0x0c: /* ^L */
296				wrefresh(curscr);
297				cp--;
298				continue;
299			case 0x15: /* ^U */
300			case 0x18: /* ^X */
301				while (cp > buf) {
302					cp--;
303					addch('\b');
304				}
305				clrtoeol();
306				break;
307			case '\b':
308			case 0x7f: /* DEL */
309				if (cp == buf + 1) {
310					cp--;
311					continue;
312				}
313				cp -= 2;
314				addch('\b');
315				c = ' ';
316				/* FALLTHROUGH */
317			default:
318				addch(c);
319			}
320			refresh();
321		}
322	}
323	*cp = '\0';
324	return c != EOF;
325}
326
327/*
328 * Decent (n)curses interface for the game, based on Eric S. Raymond's
329 * modifications to the battleship (bs) user interface.
330 */
331int
332get_coord(void)
333{
334	static int curx = BSZ / 2;
335	static int cury = BSZ / 2;
336	int ny, nx, ch;
337
338	BGOTO(cury, curx);
339	refresh();
340	nx = curx;
341	ny = cury;
342	for (;;) {
343		mvprintw(BSZ + 3, (BSZ - 6) / 2, "(%c %d) ",
344		    'A' + ((curx > 7) ? (curx + 1) : curx), cury + 1);
345		BGOTO(cury, curx);
346
347		ch = getch();
348		switch (ch) {
349		case 'k':
350		case '8':
351		case KEY_UP:
352			nx = curx;
353			ny = cury + 1;
354			break;
355		case 'j':
356		case '2':
357		case KEY_DOWN:
358			nx = curx;
359			ny = BSZ + cury - 1;
360			break;
361		case 'h':
362		case '4':
363		case KEY_LEFT:
364			nx = BSZ + curx - 1;
365			ny = cury;
366			break;
367		case 'l':
368		case '6':
369		case KEY_RIGHT:
370			nx = curx + 1;
371			ny = cury;
372			break;
373		case 'y':
374		case '7':
375		case KEY_A1:
376			nx = BSZ + curx - 1;
377			ny = cury + 1;
378			break;
379		case 'b':
380		case '1':
381		case KEY_C1:
382			nx = BSZ + curx - 1;
383			ny = BSZ + cury - 1;
384			break;
385		case 'u':
386		case '9':
387		case KEY_A3:
388			nx = curx + 1;
389			ny = cury + 1;
390			break;
391		case 'n':
392		case '3':
393		case KEY_C3:
394			nx = curx + 1;
395			ny = BSZ + cury - 1;
396			break;
397		case 'K':
398			nx = curx;
399			ny = cury + 5;
400			break;
401		case 'J':
402			nx = curx;
403			ny = BSZ + cury - 5;
404			break;
405		case 'H':
406			nx = BSZ + curx - 5;
407			ny = cury;
408			break;
409		case 'L':
410			nx = curx + 5;
411			ny = cury;
412			break;
413		case 'Y':
414			nx = BSZ + curx - 5;
415			ny = cury + 5;
416			break;
417		case 'B':
418			nx = BSZ + curx - 5;
419			ny = BSZ + cury - 5;
420			break;
421		case 'U':
422			nx = curx + 5;
423			ny = cury + 5;
424			break;
425		case 'N':
426			nx = curx + 5;
427			ny = BSZ + cury - 5;
428			break;
429		case '\f':
430			nx = curx;
431			ny = cury;
432			(void)clearok(stdscr, true);
433			(void)refresh();
434			break;
435#if 0 /* notyet */
436		case KEY_MOUSE:
437		{
438			MEVENT	myevent;
439
440			getmouse(&myevent);
441			if (myevent.y >= 1 && myevent.y <= BSZ + 1 &&
442			    myevent.x >= 3 && myevent.x <= 2 * BSZ + 1) {
443				curx = (myevent.x - 3) / 2;
444				cury = BSZ - myevent.y;
445				return PT(curx,cury);
446			} else {
447				beep();
448			}
449		}
450		break;
451#endif /* 0 */
452		case 'Q':
453		case 'q':
454			return RESIGN;
455		case 'S':
456		case 's':
457			return SAVE;
458		case ' ':
459		case '\r':
460			(void)mvaddstr(BSZ + 3, (BSZ - 6) / 2, "      ");
461			return PT(curx + 1, cury + 1);
462		}
463
464		curx = nx % BSZ;
465		cury = ny % BSZ;
466	}
467}
468