bdisp.c revision 1.48
1/* $NetBSD: bdisp.c,v 1.48 2022/05/28 08:19:18 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/* @(#)bdisp.c 8.2 (Berkeley) 5/3/95 */ 37__RCSID("$NetBSD: bdisp.c,v 1.48 2022/05/28 08:19:18 rillig Exp $"); 38 39#include <curses.h> 40#include <string.h> 41#include <stdlib.h> 42#include <err.h> 43#include "gomoku.h" 44 45#define SCRNH 24 /* assume 24 lines for the moment */ 46#define SCRNW 80 /* assume 80 chars for the moment */ 47 48static int lastline; 49static const char pcolor[] = "*O.?"; 50 51#define scr_y(by) (1 + (BSZ - 1) - ((by) - 1)) 52#define scr_x(bx) (3 + 2 * ((bx) - 1)) 53 54#define TRANSCRIPT_COL (3 + (2 * BSZ - 1) + 3 + 3) 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 %dx%d)", 68 SCRNW, SCRNH); 69 } 70 keypad(stdscr, true); 71 nonl(); 72 noecho(); 73 cbreak(); 74 leaveok(stdscr, false); 75 76 mousemask(BUTTON1_CLICKED, NULL); 77} 78 79/* 80 * Restore screen display. 81 */ 82void 83cursfini(void) 84{ 85 86 move(BSZ + 4, 0); 87 clrtoeol(); 88 refresh(); 89 echo(); 90 endwin(); 91} 92 93/* 94 * Initialize board display. 95 */ 96void 97bdisp_init(void) 98{ 99 100 /* top and bottom borders */ 101 for (int i = 1; i < BSZ + 1; i++) { 102 mvaddch(scr_y(BSZ + 1), scr_x(i), letters[i]); 103 mvaddch(scr_y(0), scr_x(i), letters[i]); 104 } 105 106 /* left and right edges */ 107 for (int j = BSZ + 1; --j > 0; ) { 108 mvprintw(scr_y(j), 0, "%2d", j); 109 mvprintw(scr_y(j), scr_x(BSZ) + 2, "%d", j); 110 } 111 112 bdwho(); 113 mvaddstr(0, TRANSCRIPT_COL, " # black white"); 114 lastline = 0; 115 bdisp(); 116} 117 118/* 119 * Update who is playing whom. 120 */ 121void 122bdwho(void) 123{ 124 int bw = (int)strlen(plyr[BLACK]); 125 int ww = (int)strlen(plyr[WHITE]); 126 int available = 3 + (1 + scr_x(BSZ) - scr_x(1)) + 3; 127 int fixed = (int)sizeof("BLACK/ (*) vs. WHITE/ (O)") - 1; 128 int total = fixed + bw + ww; 129 int x; 130 131 if (total <= available) 132 x = (available - total) / 2; 133 else { 134 int remaining = available - fixed; 135 int half = remaining / 2; 136 137 if (bw <= half) 138 ww = remaining - bw; 139 else if (ww <= half) 140 bw = remaining - ww; 141 else 142 bw = half, ww = remaining - half; 143 x = 0; 144 } 145 146 mvhline(BSZ + 2, 0, ' ', available); 147 mvprintw(BSZ + 2, x, "BLACK/%.*s (*) vs. WHITE/%.*s (O)", 148 bw, plyr[BLACK], ww, plyr[WHITE]); 149} 150 151/* 152 * Update the board display after a move. 153 */ 154void 155bdisp(void) 156{ 157 int c; 158 struct spotstr *sp; 159 160 for (int j = BSZ + 1; --j > 0; ) { 161 for (int i = 1; i < BSZ + 1; i++) { 162 sp = &board[i + j * (BSZ + 1)]; 163 if (debug > 1 && sp->s_occ == EMPTY) { 164 if ((sp->s_flags & IFLAGALL) != 0) 165 c = '+'; 166 else if ((sp->s_flags & CFLAGALL) != 0) 167 c = '-'; 168 else 169 c = '.'; 170 } else 171 c = pcolor[sp->s_occ]; 172 173 move(scr_y(j), scr_x(i)); 174 if (game.nmoves > 0 && 175 game.moves[game.nmoves - 1] == PT(i, j)) { 176 attron(A_BOLD); 177 addch(c); 178 attroff(A_BOLD); 179 } else 180 addch(c); 181 } 182 } 183 refresh(); 184} 185 186#ifdef DEBUG 187/* 188 * Dump board display to a file. 189 */ 190void 191bdump(FILE *fp) 192{ 193 int c; 194 struct spotstr *sp; 195 196 /* top border */ 197 fprintf(fp, " A B C D E F G H J K L M N O P Q R S T\n"); 198 199 for (int j = BSZ + 1; --j > 0; ) { 200 /* left edge */ 201 fprintf(fp, "%2d ", j); 202 for (int i = 1; i < BSZ + 1; i++) { 203 sp = &board[i + j * (BSZ + 1)]; 204 if (debug > 1 && sp->s_occ == EMPTY) { 205 if ((sp->s_flags & IFLAGALL) != 0) 206 c = '+'; 207 else if ((sp->s_flags & CFLAGALL) != 0) 208 c = '-'; 209 else 210 c = '.'; 211 } else 212 c = pcolor[sp->s_occ]; 213 putc(c, fp); 214 putc(' ', fp); 215 } 216 /* right edge */ 217 fprintf(fp, "%d\n", j); 218 } 219 220 /* bottom border */ 221 fprintf(fp, " A B C D E F G H J K L M N O P Q R S T\n"); 222} 223#endif /* DEBUG */ 224 225/* 226 * Display a transcript entry 227 */ 228void 229dislog(const char *str) 230{ 231 232 if (++lastline >= SCRNH - 1) { 233 /* move 'em up */ 234 lastline = 1; 235 } 236 mvaddnstr(lastline, TRANSCRIPT_COL, str, SCRNW - TRANSCRIPT_COL - 1); 237 clrtoeol(); 238 move(lastline + 1, TRANSCRIPT_COL); 239 clrtoeol(); 240} 241 242/* 243 * Display a question. 244 */ 245 246void 247ask(const char *str) 248{ 249 int len = (int)strlen(str); 250 251 mvaddstr(BSZ + 4, 0, str); 252 clrtoeol(); 253 move(BSZ + 4, len); 254 refresh(); 255} 256 257int 258get_key(const char *allowed) 259{ 260 int ch; 261 262 for (;;) { 263 ch = getch(); 264 if (allowed != NULL && 265 ch != '\0' && strchr(allowed, ch) == NULL) { 266 beep(); 267 refresh(); 268 continue; 269 } 270 break; 271 } 272 return ch; 273} 274 275bool 276get_line(char *buf, int size, void (*on_change)(const char *)) 277{ 278 char *cp, *end; 279 int c; 280 281 c = 0; 282 cp = buf; 283 end = buf + size - 1; /* save room for the '\0' */ 284 while ((c = getchar()) != EOF && c != '\n' && c != '\r') { 285 if (!interactive && cp < end) { 286 *cp++ = c; 287 continue; 288 } 289 if (!interactive) 290 errx(EXIT_FAILURE, "line too long"); 291 292 switch (c) { 293 case 0x0c: /* ^L */ 294 wrefresh(curscr); 295 continue; 296 case 0x15: /* ^U */ 297 case 0x18: /* ^X */ 298 for (; cp > buf; cp--) 299 addstr("\b \b"); 300 break; 301 case '\b': 302 case 0x7f: /* DEL */ 303 if (cp == buf) 304 continue; 305 cp--; 306 addstr("\b \b"); 307 break; 308 default: 309 if (cp < end) { 310 *cp++ = c; 311 addch(c); 312 } else 313 beep(); 314 } 315 if (on_change != NULL) { 316 *cp = '\0'; 317 on_change(buf); 318 } 319 refresh(); 320 } 321 *cp = '\0'; 322 return c != EOF; 323} 324 325static bool 326get_coord_mouse(int *x, int *y) 327{ 328 MEVENT ev; 329 330 if (getmouse(&ev) == OK && 331 (ev.bstate & (BUTTON1_RELEASED | BUTTON1_CLICKED)) != 0 && 332 ev.y >= scr_y(BSZ) && ev.y <= scr_y(1) && 333 ev.x >= scr_x(1) && ev.x <= scr_x(BSZ) && 334 (ev.x - scr_x(1)) % (scr_x(2) - scr_x(1)) == 0) { 335 *x = 1 + (ev.x - scr_x(1)) / (scr_x(2) - scr_x(1)); 336 *y = 1 + (scr_y(1) - ev.y) / (scr_y(1) - scr_y(2)); 337 return true; 338 } 339 return false; 340} 341 342/* 343 * Ask the user for the coordinate of a move, or return RESIGN or SAVE. 344 * 345 * Based on Eric S. Raymond's modifications to the battleship (bs) user 346 * interface. 347 */ 348int 349get_coord(void) 350{ 351 static int x = 1 + (BSZ - 1) / 2; 352 static int y = 1 + (BSZ - 1) / 2; 353 354 move(scr_y(y), scr_x(x)); 355 refresh(); 356 for (;;) { 357 mvprintw(BSZ + 3, 6, "(%c %d) ", letters[x], y); 358 move(scr_y(y), scr_x(x)); 359 360 int ch = getch(); 361 switch (ch) { 362 case 'k': 363 case '8': 364 case KEY_UP: 365 y++; 366 break; 367 case 'j': 368 case '2': 369 case KEY_DOWN: 370 y--; 371 break; 372 case 'h': 373 case '4': 374 case KEY_LEFT: 375 x--; 376 break; 377 case 'l': 378 case '6': 379 case KEY_RIGHT: 380 x++; 381 break; 382 case 'y': 383 case '7': 384 case KEY_A1: 385 x--; 386 y++; 387 break; 388 case 'b': 389 case '1': 390 case KEY_C1: 391 x--; 392 y--; 393 break; 394 case 'u': 395 case '9': 396 case KEY_A3: 397 x++; 398 y++; 399 break; 400 case 'n': 401 case '3': 402 case KEY_C3: 403 x++; 404 y--; 405 break; 406 case 'K': 407 y += 5; 408 break; 409 case 'J': 410 y -= 5; 411 break; 412 case 'H': 413 x -= 5; 414 break; 415 case 'L': 416 x += 5; 417 break; 418 case 'Y': 419 x -= 5; 420 y += 5; 421 break; 422 case 'B': 423 x -= 5; 424 y -= 5; 425 break; 426 case 'U': 427 x += 5; 428 y += 5; 429 break; 430 case 'N': 431 x += 5; 432 y -= 5; 433 break; 434 case 0x0c: /* ^L */ 435 (void)clearok(stdscr, true); 436 (void)refresh(); 437 break; 438 case KEY_MOUSE: 439 if (get_coord_mouse(&x, &y)) 440 return PT(x, y); 441 beep(); 442 break; 443 case 'Q': 444 case 'q': 445 return RESIGN; 446 case 'S': 447 case 's': 448 return SAVE; 449 case ' ': 450 case '\r': 451 (void)mvhline(BSZ + 3, 6, ' ', 6); 452 return PT(x, y); 453 } 454 455 x = 1 + (x + BSZ - 1) % BSZ; 456 y = 1 + (y + BSZ - 1) % BSZ; 457 } 458} 459