bdisp.c revision 1.36
196904Sgrog/*	$NetBSD: bdisp.c,v 1.36 2022/05/19 22:49:05 rillig Exp $	*/
296904Sgrog
396904Sgrog/*
496904Sgrog * Copyright (c) 1994
596904Sgrog *	The Regents of the University of California.  All rights reserved.
696904Sgrog *
796904Sgrog * This code is derived from software contributed to Berkeley by
896904Sgrog * Ralph Campbell.
996904Sgrog *
1096904Sgrog * Redistribution and use in source and binary forms, with or without
1196904Sgrog * modification, are permitted provided that the following conditions
1296904Sgrog * are met:
1396904Sgrog * 1. Redistributions of source code must retain the above copyright
1496904Sgrog *    notice, this list of conditions and the following disclaimer.
1596904Sgrog * 2. Redistributions in binary form must reproduce the above copyright
1696904Sgrog *    notice, this list of conditions and the following disclaimer in the
1796904Sgrog *    documentation and/or other materials provided with the distribution.
1896904Sgrog * 3. Neither the name of the University nor the names of its contributors
1996904Sgrog *    may be used to endorse or promote products derived from this software
2096904Sgrog *    without specific prior written permission.
2196904Sgrog *
2296904Sgrog * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2396904Sgrog * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2496904Sgrog * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2596904Sgrog * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2696904Sgrog * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2796904Sgrog * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2896904Sgrog * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2996904Sgrog * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3096904Sgrog * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3196904Sgrog * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3296904Sgrog * SUCH DAMAGE.
3396904Sgrog */
3496904Sgrog
3596904Sgrog#include <sys/cdefs.h>
3696895Sgrog/*	@(#)bdisp.c	8.2 (Berkeley) 5/3/95	*/
3796895Sgrog__RCSID("$NetBSD: bdisp.c,v 1.36 2022/05/19 22:49:05 rillig Exp $");
3896895Sgrog
3996895Sgrog#include <curses.h>
4096895Sgrog#include <string.h>
4196895Sgrog#include <stdlib.h>
4296895Sgrog#include <err.h>
4396895Sgrog#include "gomoku.h"
4496895Sgrog
4596895Sgrog#define	SCRNH		24		/* assume 24 lines for the moment */
4696895Sgrog#define	SCRNW		80		/* assume 80 chars for the moment */
4796895Sgrog
4896895Sgrogstatic	int	lastline;
4996895Sgrogstatic	char	pcolor[] = "*O.?";
5096895Sgrog
5196895Sgrog#define	scr_y(by)	(1 + (BSZ - 1) - ((by) - 1))
5296895Sgrog#define	scr_x(bx)	(3 + 2 * ((bx) - 1))
5396895Sgrog
5496895Sgrog/*
5596895Sgrog * Initialize screen display.
5696895Sgrog */
5796895Sgrogvoid
5896895Sgrogcursinit(void)
5996895Sgrog{
6096895Sgrog
6196895Sgrog	if (initscr() == NULL) {
6296895Sgrog		errx(EXIT_FAILURE, "Couldn't initialize screen");
6396895Sgrog	}
6496895Sgrog	if ((LINES < SCRNH) || (COLS < SCRNW)) {
6596895Sgrog		errx(EXIT_FAILURE, "Screen too small (need %dx%d)",
6696895Sgrog		    SCRNW, SCRNH);
6796895Sgrog	}
6896895Sgrog	keypad(stdscr, true);
6996895Sgrog	nonl();
7096895Sgrog	noecho();
7196895Sgrog	cbreak();
7296895Sgrog	leaveok(stdscr, false);
7396895Sgrog
7496895Sgrog#if 0 /* no mouse support in netbsd curses yet */
7596895Sgrog	mousemask(BUTTON1_CLICKED, NULL);
7696895Sgrog#endif
7796895Sgrog}
7896895Sgrog
7996895Sgrog/*
8096895Sgrog * Restore screen display.
8196895Sgrog */
8296895Sgrogvoid
8396895Sgrogcursfini(void)
8496895Sgrog{
8596895Sgrog
8696895Sgrog	move(BSZ + 4, 0);
8796895Sgrog	clrtoeol();
8896895Sgrog	refresh();
8996895Sgrog	echo();
9096895Sgrog	endwin();
9196895Sgrog}
9296895Sgrog
9396895Sgrog/*
9496895Sgrog * Initialize board display.
9596895Sgrog */
9696895Sgrogvoid
9796895Sgrogbdisp_init(void)
9896895Sgrog{
9996895Sgrog
10096895Sgrog	/* top and bottom borders */
10196895Sgrog	for (int i = 1; i < BSZ + 1; i++) {
10296895Sgrog		mvaddch(scr_y(BSZ + 1), scr_x(i), letters[i]);
10396895Sgrog		mvaddch(scr_y(0), scr_x(i), letters[i]);
10496895Sgrog	}
10596895Sgrog
10696895Sgrog	/* left and right edges */
10796895Sgrog	for (int j = BSZ + 1; --j > 0; ) {
10896895Sgrog		mvprintw(scr_y(j), 0, "%2d ", j);
10996895Sgrog		mvprintw(scr_y(j), scr_x(BSZ) + 2, "%d ", j);
11096895Sgrog	}
11196895Sgrog
11296895Sgrog	bdwho(false);
11396895Sgrog	mvaddstr(0, TRANSCRIPT_COL + 1, "#  black  white");
11496895Sgrog	lastline = 0;
11596895Sgrog	bdisp();
11696895Sgrog}
11796895Sgrog
11896895Sgrog/*
11996895Sgrog * Update who is playing whom.
12096895Sgrog */
12196895Sgrogvoid
12296895Sgrogbdwho(bool update)
12396895Sgrog{
12496895Sgrog	int bw = (int)strlen(plyr[BLACK]);
12596895Sgrog	int ww = (int)strlen(plyr[WHITE]);
12696895Sgrog	int available = 3 + (1 + scr_x(BSZ) - scr_x(1)) + 3;
12796895Sgrog	int fixed = (int)sizeof("BLACK/ (*) vs. WHITE/ (O)") - 1;
12896895Sgrog	int total = fixed + bw + ww;
12996895Sgrog
13096895Sgrog	mvhline(BSZ + 2, 0, ' ', available);
13196895Sgrog
13296895Sgrog	if (total <= available) {
13396895Sgrog		mvprintw(BSZ + 2, (available - total) / 2,
13496895Sgrog		    "BLACK/%s (*) vs. WHITE/%s (O)",
13596895Sgrog		    plyr[BLACK], plyr[WHITE]);
13696895Sgrog	} else {
13796895Sgrog		int remaining = available - fixed;
13896895Sgrog		int half = remaining / 2;
13996895Sgrog
14096895Sgrog		if (bw <= half)
14196895Sgrog			ww = remaining - bw;
14296895Sgrog		else if (ww <= half)
14396895Sgrog			bw = remaining - ww;
14496895Sgrog		else
14596895Sgrog			bw = half, ww = remaining - half;
14696895Sgrog
14796895Sgrog		mvprintw(BSZ + 2, 0, "BLACK/%.*s (*) vs. WHITE/%.*s (O)",
14896895Sgrog		    bw, plyr[BLACK], ww, plyr[WHITE]);
14996895Sgrog	}
15096895Sgrog	if (update)
15196895Sgrog		refresh();
15296895Sgrog}
15396895Sgrog
15496895Sgrog/*
15596895Sgrog * Update the board display after a move.
15696895Sgrog */
15796895Sgrogvoid
15896895Sgrogbdisp(void)
15996895Sgrog{
16096895Sgrog	int c;
16196895Sgrog	struct spotstr *sp;
16296895Sgrog
16396895Sgrog	for (int j = BSZ + 1; --j > 0; ) {
16496895Sgrog		for (int i = 1; i < BSZ + 1; i++) {
16596895Sgrog			sp = &board[i + j * (BSZ + 1)];
16696895Sgrog			if (debug > 1 && sp->s_occ == EMPTY) {
16796895Sgrog				if ((sp->s_flags & IFLAGALL) != 0)
16896895Sgrog					c = '+';
16996895Sgrog				else if ((sp->s_flags & CFLAGALL) != 0)
17096895Sgrog					c = '-';
17196895Sgrog				else
17296895Sgrog					c = '.';
17396895Sgrog			} else
17496895Sgrog				c = pcolor[sp->s_occ];
17596895Sgrog
17696895Sgrog			move(scr_y(j), scr_x(i));
17796895Sgrog			if (movenum > 1 && movelog[movenum - 2] == PT(i, j)) {
17896895Sgrog				attron(A_BOLD);
17996895Sgrog				addch(c);
18096895Sgrog				attroff(A_BOLD);
18196895Sgrog			} else
18296895Sgrog				addch(c);
18396895Sgrog		}
18496895Sgrog	}
18596895Sgrog	refresh();
18696895Sgrog}
18796895Sgrog
18896895Sgrog#ifdef DEBUG
18996895Sgrog/*
19096895Sgrog * Dump board display to a file.
19196895Sgrog */
19296895Sgrogvoid
19396895Sgrogbdump(FILE *fp)
19496895Sgrog{
19596895Sgrog	int c;
19696895Sgrog	struct spotstr *sp;
19796895Sgrog
19896895Sgrog	/* top border */
19996895Sgrog	fprintf(fp, "   A B C D E F G H J K L M N O P Q R S T\n");
20096895Sgrog
20196895Sgrog	for (int j = BSZ + 1; --j > 0; ) {
20296895Sgrog		/* left edge */
20396895Sgrog		fprintf(fp, "%2d ", j);
20496895Sgrog		for (int i = 1; i < BSZ + 1; i++) {
20596895Sgrog			sp = &board[i + j * (BSZ + 1)];
20696895Sgrog			if (debug > 1 && sp->s_occ == EMPTY) {
20796895Sgrog				if ((sp->s_flags & IFLAGALL) != 0)
20896895Sgrog					c = '+';
20996895Sgrog				else if ((sp->s_flags & CFLAGALL) != 0)
21096895Sgrog					c = '-';
21196895Sgrog				else
21296895Sgrog					c = '.';
21396895Sgrog			} else
21496895Sgrog				c = pcolor[sp->s_occ];
21596895Sgrog			putc(c, fp);
21696895Sgrog			putc(' ', fp);
21796895Sgrog		}
21896895Sgrog		/* right edge */
21996895Sgrog		fprintf(fp, "%d\n", j);
22096895Sgrog	}
22196895Sgrog
22296895Sgrog	/* bottom border */
22396895Sgrog	fprintf(fp, "   A B C D E F G H J K L M N O P Q R S T\n");
22496895Sgrog}
22596895Sgrog#endif /* DEBUG */
22696895Sgrog
22796895Sgrog/*
22896895Sgrog * Display a transcript entry
22996895Sgrog */
23096895Sgrogvoid
23196895Sgrogdislog(const char *str)
23296895Sgrog{
23396895Sgrog
23496895Sgrog	if (++lastline >= SCRNH - 1) {
23596895Sgrog		/* move 'em up */
23696895Sgrog		lastline = 1;
23796895Sgrog	}
23896895Sgrog	mvaddnstr(lastline, TRANSCRIPT_COL, str, SCRNW - TRANSCRIPT_COL - 1);
23996895Sgrog	clrtoeol();
24096895Sgrog	move(lastline + 1, TRANSCRIPT_COL);
24196895Sgrog	clrtoeol();
24296895Sgrog}
24396895Sgrog
24496895Sgrog/*
24596895Sgrog * Display a question.
24696895Sgrog */
24796895Sgrog
24896895Sgrogvoid
24996895Sgrogask(const char *str)
25096895Sgrog{
25196895Sgrog	int len = (int)strlen(str);
25296895Sgrog
25396895Sgrog	mvaddstr(BSZ + 4, 0, str);
25496895Sgrog	clrtoeol();
25596895Sgrog	move(BSZ + 4, len);
25696895Sgrog	refresh();
25796895Sgrog}
25896895Sgrog
25996895Sgrogint
26096895Sgrogget_key(const char *allowed)
26196895Sgrog{
26296895Sgrog	int ch;
26396895Sgrog
26496895Sgrog	for (;;) {
26596895Sgrog		ch = getch();
26696895Sgrog		if (allowed != NULL &&
26796895Sgrog		    ch != '\0' && strchr(allowed, ch) == NULL) {
26896895Sgrog			beep();
26996895Sgrog			refresh();
27096895Sgrog			continue;
27196895Sgrog		}
27296895Sgrog		break;
27396895Sgrog	}
27496895Sgrog	return ch;
27596895Sgrog}
27696895Sgrog
27796895Sgrogbool
27896895Sgrogget_line(char *buf, int size)
27996895Sgrog{
28096895Sgrog	char *cp, *end;
28196895Sgrog	int c;
28296895Sgrog
28396895Sgrog	c = 0;
28496895Sgrog	cp = buf;
28596895Sgrog	end = buf + size - 1;	/* save room for the '\0' */
28696895Sgrog	while (cp < end && (c = getchar()) != EOF && c != '\n' && c != '\r') {
28796895Sgrog		*cp++ = c;
28896895Sgrog		if (interactive) {
28996895Sgrog			switch (c) {
29096895Sgrog			case 0x0c: /* ^L */
29196895Sgrog				wrefresh(curscr);
29296895Sgrog				cp--;
29396895Sgrog				continue;
29496895Sgrog			case 0x15: /* ^U */
29596895Sgrog			case 0x18: /* ^X */
29696895Sgrog				while (cp > buf) {
29796895Sgrog					cp--;
29896895Sgrog					addch('\b');
29996895Sgrog				}
30096895Sgrog				clrtoeol();
30196895Sgrog				break;
30296895Sgrog			case '\b':
30396895Sgrog			case 0x7f: /* DEL */
30496895Sgrog				if (cp == buf + 1) {
30596895Sgrog					cp--;
30696895Sgrog					continue;
30796895Sgrog				}
30896895Sgrog				cp -= 2;
30996895Sgrog				addch('\b');
31096895Sgrog				c = ' ';
31196895Sgrog				/* FALLTHROUGH */
31296895Sgrog			default:
31396895Sgrog				addch(c);
31496895Sgrog			}
31596895Sgrog			refresh();
31696895Sgrog		}
31796895Sgrog	}
31896895Sgrog	*cp = '\0';
31996895Sgrog	return c != EOF;
32096895Sgrog}
32196895Sgrog
32296895Sgrog/*
32396895Sgrog * Decent (n)curses interface for the game, based on Eric S. Raymond's
32496895Sgrog * modifications to the battleship (bs) user interface.
32596895Sgrog */
32696895Sgrogint
32796895Sgrogget_coord(void)
32896895Sgrog{
32996895Sgrog	/* XXX: These coordinates are 0-based, all others are 1-based. */
33096895Sgrog	static int curx = BSZ / 2;
33196895Sgrog	static int cury = BSZ / 2;
33296895Sgrog	int ny, nx, ch;
33396895Sgrog
33496895Sgrog	move(scr_y(cury + 1), scr_x(curx + 1));
33596895Sgrog	refresh();
33696895Sgrog	nx = curx;
33796895Sgrog	ny = cury;
33896895Sgrog	for (;;) {
33996895Sgrog		mvprintw(BSZ + 3, 6, "(%c %d) ",
34096895Sgrog		    letters[curx + 1], cury + 1);
34196895Sgrog		move(scr_y(cury + 1), scr_x(curx + 1));
34296895Sgrog
34396895Sgrog		ch = getch();
34496895Sgrog		switch (ch) {
34596895Sgrog		case 'k':
34696895Sgrog		case '8':
34796895Sgrog		case KEY_UP:
34896895Sgrog			nx = curx;
34996895Sgrog			ny = cury + 1;
35096895Sgrog			break;
35196895Sgrog		case 'j':
35296895Sgrog		case '2':
35396895Sgrog		case KEY_DOWN:
35496895Sgrog			nx = curx;
35596895Sgrog			ny = BSZ + cury - 1;
35696895Sgrog			break;
35796895Sgrog		case 'h':
35896895Sgrog		case '4':
35996895Sgrog		case KEY_LEFT:
36096895Sgrog			nx = BSZ + curx - 1;
36196895Sgrog			ny = cury;
36296895Sgrog			break;
36396895Sgrog		case 'l':
36496895Sgrog		case '6':
36596895Sgrog		case KEY_RIGHT:
36696895Sgrog			nx = curx + 1;
36796895Sgrog			ny = cury;
36896895Sgrog			break;
36996895Sgrog		case 'y':
37096895Sgrog		case '7':
37196895Sgrog		case KEY_A1:
37296895Sgrog			nx = BSZ + curx - 1;
37396895Sgrog			ny = cury + 1;
37496895Sgrog			break;
37596895Sgrog		case 'b':
37696895Sgrog		case '1':
37796895Sgrog		case KEY_C1:
37896895Sgrog			nx = BSZ + curx - 1;
37996895Sgrog			ny = BSZ + cury - 1;
38096895Sgrog			break;
38196895Sgrog		case 'u':
38296895Sgrog		case '9':
38396895Sgrog		case KEY_A3:
38496895Sgrog			nx = curx + 1;
38596895Sgrog			ny = cury + 1;
38696895Sgrog			break;
38796895Sgrog		case 'n':
38896895Sgrog		case '3':
38996895Sgrog		case KEY_C3:
39096895Sgrog			nx = curx + 1;
39196895Sgrog			ny = BSZ + cury - 1;
39296895Sgrog			break;
39396895Sgrog		case 'K':
39496895Sgrog			nx = curx;
39596895Sgrog			ny = cury + 5;
39696895Sgrog			break;
39796895Sgrog		case 'J':
39896895Sgrog			nx = curx;
39996895Sgrog			ny = BSZ + cury - 5;
40096895Sgrog			break;
40196895Sgrog		case 'H':
40296895Sgrog			nx = BSZ + curx - 5;
40396895Sgrog			ny = cury;
40496895Sgrog			break;
40596895Sgrog		case 'L':
40696895Sgrog			nx = curx + 5;
40796895Sgrog			ny = cury;
40896895Sgrog			break;
40996895Sgrog		case 'Y':
41096895Sgrog			nx = BSZ + curx - 5;
41196895Sgrog			ny = cury + 5;
41296895Sgrog			break;
41396895Sgrog		case 'B':
41496895Sgrog			nx = BSZ + curx - 5;
41596895Sgrog			ny = BSZ + cury - 5;
41696895Sgrog			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, 6, "      ");
457			return PT(curx + 1, cury + 1);
458		}
459
460		curx = nx % BSZ;
461		cury = ny % BSZ;
462	}
463}
464