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