bdisp.c revision 1.43
1/* $NetBSD: bdisp.c,v 1.43 2022/05/22 08:12:15 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.43 2022/05/22 08:12:15 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#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 and bottom borders */ 103 for (int i = 1; i < BSZ + 1; i++) { 104 mvaddch(scr_y(BSZ + 1), scr_x(i), letters[i]); 105 mvaddch(scr_y(0), scr_x(i), letters[i]); 106 } 107 108 /* left and right edges */ 109 for (int j = BSZ + 1; --j > 0; ) { 110 mvprintw(scr_y(j), 0, "%2d", j); 111 mvprintw(scr_y(j), scr_x(BSZ) + 2, "%d", j); 112 } 113 114 bdwho(); 115 mvaddstr(0, TRANSCRIPT_COL, " # black white"); 116 lastline = 0; 117 bdisp(); 118} 119 120/* 121 * Update who is playing whom. 122 */ 123void 124bdwho(void) 125{ 126 int bw = (int)strlen(plyr[BLACK]); 127 int ww = (int)strlen(plyr[WHITE]); 128 int available = 3 + (1 + scr_x(BSZ) - scr_x(1)) + 3; 129 int fixed = (int)sizeof("BLACK/ (*) vs. WHITE/ (O)") - 1; 130 int total = fixed + bw + ww; 131 int x; 132 133 if (total <= available) 134 x = (available - total) / 2; 135 else { 136 int remaining = available - fixed; 137 int half = remaining / 2; 138 139 if (bw <= half) 140 ww = remaining - bw; 141 else if (ww <= half) 142 bw = remaining - ww; 143 else 144 bw = half, ww = remaining - half; 145 x = 0; 146 } 147 148 mvhline(BSZ + 2, 0, ' ', available); 149 mvprintw(BSZ + 2, x, "BLACK/%.*s (*) vs. WHITE/%.*s (O)", 150 bw, plyr[BLACK], ww, plyr[WHITE]); 151} 152 153/* 154 * Update the board display after a move. 155 */ 156void 157bdisp(void) 158{ 159 int c; 160 struct spotstr *sp; 161 162 for (int j = BSZ + 1; --j > 0; ) { 163 for (int i = 1; i < BSZ + 1; i++) { 164 sp = &board[i + j * (BSZ + 1)]; 165 if (debug > 1 && sp->s_occ == EMPTY) { 166 if ((sp->s_flags & IFLAGALL) != 0) 167 c = '+'; 168 else if ((sp->s_flags & CFLAGALL) != 0) 169 c = '-'; 170 else 171 c = '.'; 172 } else 173 c = pcolor[sp->s_occ]; 174 175 move(scr_y(j), scr_x(i)); 176 if (movenum > 1 && movelog[movenum - 2] == PT(i, j)) { 177 attron(A_BOLD); 178 addch(c); 179 attroff(A_BOLD); 180 } else 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 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 (int j = BSZ + 1; --j > 0; ) { 201 /* left edge */ 202 fprintf(fp, "%2d ", j); 203 for (int 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 mvaddnstr(lastline, TRANSCRIPT_COL, str, SCRNW - TRANSCRIPT_COL - 1); 238 clrtoeol(); 239 move(lastline + 1, TRANSCRIPT_COL); 240 clrtoeol(); 241} 242 243/* 244 * Display a question. 245 */ 246 247void 248ask(const char *str) 249{ 250 int len = (int)strlen(str); 251 252 mvaddstr(BSZ + 4, 0, str); 253 clrtoeol(); 254 move(BSZ + 4, len); 255 refresh(); 256} 257 258int 259get_key(const char *allowed) 260{ 261 int ch; 262 263 for (;;) { 264 ch = getch(); 265 if (allowed != NULL && 266 ch != '\0' && strchr(allowed, ch) == NULL) { 267 beep(); 268 refresh(); 269 continue; 270 } 271 break; 272 } 273 return ch; 274} 275 276bool 277get_line(char *buf, int size, void (*on_change)(const char *)) 278{ 279 char *cp, *end; 280 int c; 281 282 c = 0; 283 cp = buf; 284 end = buf + size - 1; /* save room for the '\0' */ 285 while ((c = getchar()) != EOF && c != '\n' && c != '\r') { 286 if (!interactive && cp < end) { 287 *cp++ = c; 288 continue; 289 } 290 if (!interactive) 291 errx(EXIT_FAILURE, "line too long"); 292 293 switch (c) { 294 case 0x0c: /* ^L */ 295 wrefresh(curscr); 296 continue; 297 case 0x15: /* ^U */ 298 case 0x18: /* ^X */ 299 for (; cp > buf; cp--) 300 addstr("\b \b"); 301 break; 302 case '\b': 303 case 0x7f: /* DEL */ 304 if (cp == buf) 305 continue; 306 cp--; 307 addstr("\b \b"); 308 break; 309 default: 310 if (cp < end) { 311 *cp++ = c; 312 addch(c); 313 } else 314 beep(); 315 } 316 if (on_change != NULL) { 317 *cp = '\0'; 318 on_change(buf); 319 } 320 refresh(); 321 } 322 *cp = '\0'; 323 return c != EOF; 324} 325 326/* 327 * Ask the user for the coordinate of a move, or return RESIGN or SAVE. 328 * 329 * Based on Eric S. Raymond's modifications to the battleship (bs) user 330 * interface. 331 */ 332int 333get_coord(void) 334{ 335 /* XXX: These coordinates are 0-based, all others are 1-based. */ 336 static int curx = BSZ / 2; 337 static int cury = BSZ / 2; 338 int ny, nx, ch; 339 340 move(scr_y(cury + 1), scr_x(curx + 1)); 341 refresh(); 342 nx = curx; 343 ny = cury; 344 for (;;) { 345 mvprintw(BSZ + 3, 6, "(%c %d) ", 346 letters[curx + 1], cury + 1); 347 move(scr_y(cury + 1), scr_x(curx + 1)); 348 349 ch = getch(); 350 switch (ch) { 351 case 'k': 352 case '8': 353 case KEY_UP: 354 nx = curx; 355 ny = cury + 1; 356 break; 357 case 'j': 358 case '2': 359 case KEY_DOWN: 360 nx = curx; 361 ny = BSZ + cury - 1; 362 break; 363 case 'h': 364 case '4': 365 case KEY_LEFT: 366 nx = BSZ + curx - 1; 367 ny = cury; 368 break; 369 case 'l': 370 case '6': 371 case KEY_RIGHT: 372 nx = curx + 1; 373 ny = cury; 374 break; 375 case 'y': 376 case '7': 377 case KEY_A1: 378 nx = BSZ + curx - 1; 379 ny = cury + 1; 380 break; 381 case 'b': 382 case '1': 383 case KEY_C1: 384 nx = BSZ + curx - 1; 385 ny = BSZ + cury - 1; 386 break; 387 case 'u': 388 case '9': 389 case KEY_A3: 390 nx = curx + 1; 391 ny = cury + 1; 392 break; 393 case 'n': 394 case '3': 395 case KEY_C3: 396 nx = curx + 1; 397 ny = BSZ + cury - 1; 398 break; 399 case 'K': 400 nx = curx; 401 ny = cury + 5; 402 break; 403 case 'J': 404 nx = curx; 405 ny = BSZ + cury - 5; 406 break; 407 case 'H': 408 nx = BSZ + curx - 5; 409 ny = cury; 410 break; 411 case 'L': 412 nx = curx + 5; 413 ny = cury; 414 break; 415 case 'Y': 416 nx = BSZ + curx - 5; 417 ny = cury + 5; 418 break; 419 case 'B': 420 nx = BSZ + curx - 5; 421 ny = BSZ + cury - 5; 422 break; 423 case 'U': 424 nx = curx + 5; 425 ny = cury + 5; 426 break; 427 case 'N': 428 nx = curx + 5; 429 ny = BSZ + cury - 5; 430 break; 431 case '\f': 432 nx = curx; 433 ny = cury; 434 (void)clearok(stdscr, true); 435 (void)refresh(); 436 break; 437#if 0 /* notyet */ 438 case KEY_MOUSE: 439 { 440 MEVENT myevent; 441 442 getmouse(&myevent); 443 if (myevent.y >= 1 && myevent.y <= BSZ + 1 && 444 myevent.x >= 3 && myevent.x <= 2 * BSZ + 1) { 445 curx = (myevent.x - 3) / 2; 446 cury = BSZ - myevent.y; 447 return PT(curx,cury); 448 } else { 449 beep(); 450 } 451 } 452 break; 453#endif /* 0 */ 454 case 'Q': 455 case 'q': 456 return RESIGN; 457 case 'S': 458 case 's': 459 return SAVE; 460 case ' ': 461 case '\r': 462 (void)mvaddstr(BSZ + 3, 6, " "); 463 return PT(curx + 1, cury + 1); 464 } 465 466 curx = nx % BSZ; 467 cury = ny % BSZ; 468 } 469} 470