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