bdisp.c revision 1.37
1/* $NetBSD: bdisp.c,v 1.37 2022/05/21 09:25:51 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.37 2022/05/21 09:25:51 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 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/* 55 * Initialize screen display. 56 */ 57void 58cursinit(void) 59{ 60 61 if (initscr() == NULL) { 62 errx(EXIT_FAILURE, "Couldn't initialize screen"); 63 } 64 if ((LINES < SCRNH) || (COLS < SCRNW)) { 65 errx(EXIT_FAILURE, "Screen too small (need %dx%d)", 66 SCRNW, SCRNH); 67 } 68 keypad(stdscr, true); 69 nonl(); 70 noecho(); 71 cbreak(); 72 leaveok(stdscr, false); 73 74#if 0 /* no mouse support in netbsd curses yet */ 75 mousemask(BUTTON1_CLICKED, NULL); 76#endif 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 + 1, "# 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 (movenum > 1 && movelog[movenum - 2] == PT(i, j)) { 175 attron(A_BOLD); 176 addch(c); 177 attroff(A_BOLD); 178 } else 179 addch(c); 180 } 181 } 182 refresh(); 183} 184 185#ifdef DEBUG 186/* 187 * Dump board display to a file. 188 */ 189void 190bdump(FILE *fp) 191{ 192 int c; 193 struct spotstr *sp; 194 195 /* top border */ 196 fprintf(fp, " A B C D E F G H J K L M N O P Q R S T\n"); 197 198 for (int j = BSZ + 1; --j > 0; ) { 199 /* left edge */ 200 fprintf(fp, "%2d ", j); 201 for (int i = 1; i < BSZ + 1; i++) { 202 sp = &board[i + j * (BSZ + 1)]; 203 if (debug > 1 && sp->s_occ == EMPTY) { 204 if ((sp->s_flags & IFLAGALL) != 0) 205 c = '+'; 206 else if ((sp->s_flags & CFLAGALL) != 0) 207 c = '-'; 208 else 209 c = '.'; 210 } else 211 c = pcolor[sp->s_occ]; 212 putc(c, fp); 213 putc(' ', fp); 214 } 215 /* right edge */ 216 fprintf(fp, "%d\n", j); 217 } 218 219 /* bottom border */ 220 fprintf(fp, " A B C D E F G H J K L M N O P Q R S T\n"); 221} 222#endif /* DEBUG */ 223 224/* 225 * Display a transcript entry 226 */ 227void 228dislog(const char *str) 229{ 230 231 if (++lastline >= SCRNH - 1) { 232 /* move 'em up */ 233 lastline = 1; 234 } 235 mvaddnstr(lastline, TRANSCRIPT_COL, str, SCRNW - TRANSCRIPT_COL - 1); 236 clrtoeol(); 237 move(lastline + 1, TRANSCRIPT_COL); 238 clrtoeol(); 239} 240 241/* 242 * Display a question. 243 */ 244 245void 246ask(const char *str) 247{ 248 int len = (int)strlen(str); 249 250 mvaddstr(BSZ + 4, 0, str); 251 clrtoeol(); 252 move(BSZ + 4, len); 253 refresh(); 254} 255 256int 257get_key(const char *allowed) 258{ 259 int ch; 260 261 for (;;) { 262 ch = getch(); 263 if (allowed != NULL && 264 ch != '\0' && strchr(allowed, ch) == NULL) { 265 beep(); 266 refresh(); 267 continue; 268 } 269 break; 270 } 271 return ch; 272} 273 274bool 275get_line(char *buf, int size) 276{ 277 char *cp, *end; 278 int c; 279 280 c = 0; 281 cp = buf; 282 end = buf + size - 1; /* save room for the '\0' */ 283 while (cp < end && (c = getchar()) != EOF && c != '\n' && c != '\r') { 284 *cp++ = c; 285 if (interactive) { 286 switch (c) { 287 case 0x0c: /* ^L */ 288 wrefresh(curscr); 289 cp--; 290 continue; 291 case 0x15: /* ^U */ 292 case 0x18: /* ^X */ 293 while (cp > buf) { 294 cp--; 295 addch('\b'); 296 } 297 clrtoeol(); 298 break; 299 case '\b': 300 case 0x7f: /* DEL */ 301 if (cp == buf + 1) { 302 cp--; 303 continue; 304 } 305 cp -= 2; 306 addch('\b'); 307 c = ' '; 308 /* FALLTHROUGH */ 309 default: 310 addch(c); 311 } 312 refresh(); 313 } 314 } 315 *cp = '\0'; 316 return c != EOF; 317} 318 319/* 320 * Decent (n)curses interface for the game, based on Eric S. Raymond's 321 * modifications to the battleship (bs) user interface. 322 */ 323int 324get_coord(void) 325{ 326 /* XXX: These coordinates are 0-based, all others are 1-based. */ 327 static int curx = BSZ / 2; 328 static int cury = BSZ / 2; 329 int ny, nx, ch; 330 331 move(scr_y(cury + 1), scr_x(curx + 1)); 332 refresh(); 333 nx = curx; 334 ny = cury; 335 for (;;) { 336 mvprintw(BSZ + 3, 6, "(%c %d) ", 337 letters[curx + 1], cury + 1); 338 move(scr_y(cury + 1), scr_x(curx + 1)); 339 340 ch = getch(); 341 switch (ch) { 342 case 'k': 343 case '8': 344 case KEY_UP: 345 nx = curx; 346 ny = cury + 1; 347 break; 348 case 'j': 349 case '2': 350 case KEY_DOWN: 351 nx = curx; 352 ny = BSZ + cury - 1; 353 break; 354 case 'h': 355 case '4': 356 case KEY_LEFT: 357 nx = BSZ + curx - 1; 358 ny = cury; 359 break; 360 case 'l': 361 case '6': 362 case KEY_RIGHT: 363 nx = curx + 1; 364 ny = cury; 365 break; 366 case 'y': 367 case '7': 368 case KEY_A1: 369 nx = BSZ + curx - 1; 370 ny = cury + 1; 371 break; 372 case 'b': 373 case '1': 374 case KEY_C1: 375 nx = BSZ + curx - 1; 376 ny = BSZ + cury - 1; 377 break; 378 case 'u': 379 case '9': 380 case KEY_A3: 381 nx = curx + 1; 382 ny = cury + 1; 383 break; 384 case 'n': 385 case '3': 386 case KEY_C3: 387 nx = curx + 1; 388 ny = BSZ + cury - 1; 389 break; 390 case 'K': 391 nx = curx; 392 ny = cury + 5; 393 break; 394 case 'J': 395 nx = curx; 396 ny = BSZ + cury - 5; 397 break; 398 case 'H': 399 nx = BSZ + curx - 5; 400 ny = cury; 401 break; 402 case 'L': 403 nx = curx + 5; 404 ny = cury; 405 break; 406 case 'Y': 407 nx = BSZ + curx - 5; 408 ny = cury + 5; 409 break; 410 case 'B': 411 nx = BSZ + curx - 5; 412 ny = BSZ + cury - 5; 413 break; 414 case 'U': 415 nx = curx + 5; 416 ny = cury + 5; 417 break; 418 case 'N': 419 nx = curx + 5; 420 ny = BSZ + cury - 5; 421 break; 422 case '\f': 423 nx = curx; 424 ny = cury; 425 (void)clearok(stdscr, true); 426 (void)refresh(); 427 break; 428#if 0 /* notyet */ 429 case KEY_MOUSE: 430 { 431 MEVENT myevent; 432 433 getmouse(&myevent); 434 if (myevent.y >= 1 && myevent.y <= BSZ + 1 && 435 myevent.x >= 3 && myevent.x <= 2 * BSZ + 1) { 436 curx = (myevent.x - 3) / 2; 437 cury = BSZ - myevent.y; 438 return PT(curx,cury); 439 } else { 440 beep(); 441 } 442 } 443 break; 444#endif /* 0 */ 445 case 'Q': 446 case 'q': 447 return RESIGN; 448 case 'S': 449 case 's': 450 return SAVE; 451 case ' ': 452 case '\r': 453 (void)mvaddstr(BSZ + 3, 6, " "); 454 return PT(curx + 1, cury + 1); 455 } 456 457 curx = nx % BSZ; 458 cury = ny % BSZ; 459 } 460} 461