1 1.55 rillig /* $NetBSD: bdisp.c,v 1.55 2022/05/29 17:01:42 rillig Exp $ */ 2 1.4 cgd 3 1.1 tls /* 4 1.1 tls * Copyright (c) 1994 5 1.1 tls * The Regents of the University of California. All rights reserved. 6 1.1 tls * 7 1.1 tls * This code is derived from software contributed to Berkeley by 8 1.1 tls * Ralph Campbell. 9 1.1 tls * 10 1.1 tls * Redistribution and use in source and binary forms, with or without 11 1.1 tls * modification, are permitted provided that the following conditions 12 1.1 tls * are met: 13 1.1 tls * 1. Redistributions of source code must retain the above copyright 14 1.1 tls * notice, this list of conditions and the following disclaimer. 15 1.1 tls * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 tls * notice, this list of conditions and the following disclaimer in the 17 1.1 tls * documentation and/or other materials provided with the distribution. 18 1.8 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 tls * may be used to endorse or promote products derived from this software 20 1.1 tls * without specific prior written permission. 21 1.1 tls * 22 1.1 tls * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 tls * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 tls * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 tls * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 tls * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 tls * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 tls * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 tls * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 tls * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 tls * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 tls * SUCH DAMAGE. 33 1.1 tls */ 34 1.1 tls 35 1.5 lukem #include <sys/cdefs.h> 36 1.34 rillig /* @(#)bdisp.c 8.2 (Berkeley) 5/3/95 */ 37 1.55 rillig __RCSID("$NetBSD: bdisp.c,v 1.55 2022/05/29 17:01:42 rillig Exp $"); 38 1.1 tls 39 1.5 lukem #include <curses.h> 40 1.5 lukem #include <string.h> 41 1.9 drochner #include <stdlib.h> 42 1.13 dholland #include <err.h> 43 1.1 tls #include "gomoku.h" 44 1.1 tls 45 1.1 tls #define SCRNH 24 /* assume 24 lines for the moment */ 46 1.1 tls #define SCRNW 80 /* assume 80 chars for the moment */ 47 1.1 tls 48 1.1 tls static int lastline; 49 1.42 rillig static const char pcolor[] = "*O.?"; 50 1.1 tls 51 1.31 rillig #define scr_y(by) (1 + (BSZ - 1) - ((by) - 1)) 52 1.31 rillig #define scr_x(bx) (3 + 2 * ((bx) - 1)) 53 1.31 rillig 54 1.41 rillig #define TRANSCRIPT_COL (3 + (2 * BSZ - 1) + 3 + 3) 55 1.41 rillig 56 1.1 tls /* 57 1.1 tls * Initialize screen display. 58 1.1 tls */ 59 1.5 lukem void 60 1.10 dholland cursinit(void) 61 1.1 tls { 62 1.1 tls 63 1.50 rillig if (initscr() == NULL) 64 1.13 dholland errx(EXIT_FAILURE, "Couldn't initialize screen"); 65 1.50 rillig 66 1.50 rillig if (LINES < SCRNH || COLS < SCRNW) 67 1.30 rillig errx(EXIT_FAILURE, "Screen too small (need %dx%d)", 68 1.14 dholland SCRNW, SCRNH); 69 1.50 rillig 70 1.24 rillig keypad(stdscr, true); 71 1.14 dholland nonl(); 72 1.1 tls noecho(); 73 1.1 tls cbreak(); 74 1.29 rillig leaveok(stdscr, false); 75 1.14 dholland 76 1.14 dholland mousemask(BUTTON1_CLICKED, NULL); 77 1.1 tls } 78 1.1 tls 79 1.1 tls /* 80 1.1 tls * Restore screen display. 81 1.1 tls */ 82 1.5 lukem void 83 1.10 dholland cursfini(void) 84 1.1 tls { 85 1.1 tls 86 1.22 rillig move(BSZ + 4, 0); 87 1.1 tls clrtoeol(); 88 1.1 tls refresh(); 89 1.14 dholland echo(); 90 1.1 tls endwin(); 91 1.1 tls } 92 1.1 tls 93 1.1 tls /* 94 1.1 tls * Initialize board display. 95 1.1 tls */ 96 1.5 lukem void 97 1.10 dholland bdisp_init(void) 98 1.1 tls { 99 1.1 tls 100 1.36 rillig /* top and bottom borders */ 101 1.52 rillig for (int col = 1; col <= BSZ; col++) { 102 1.52 rillig mvaddch(scr_y(BSZ + 1), scr_x(col), letters[col]); 103 1.52 rillig mvaddch(scr_y(0), scr_x(col), letters[col]); 104 1.1 tls } 105 1.36 rillig 106 1.1 tls /* left and right edges */ 107 1.52 rillig for (int row = BSZ; row >= 1; row--) { 108 1.52 rillig mvprintw(scr_y(row), 0, "%2d", row); 109 1.52 rillig mvprintw(scr_y(row), scr_x(BSZ) + 2, "%d", row); 110 1.1 tls } 111 1.36 rillig 112 1.37 rillig bdwho(); 113 1.42 rillig mvaddstr(0, TRANSCRIPT_COL, " # black white"); 114 1.1 tls lastline = 0; 115 1.1 tls bdisp(); 116 1.1 tls } 117 1.1 tls 118 1.1 tls /* 119 1.1 tls * Update who is playing whom. 120 1.1 tls */ 121 1.5 lukem void 122 1.37 rillig bdwho(void) 123 1.1 tls { 124 1.33 rillig int bw = (int)strlen(plyr[BLACK]); 125 1.33 rillig int ww = (int)strlen(plyr[WHITE]); 126 1.33 rillig int available = 3 + (1 + scr_x(BSZ) - scr_x(1)) + 3; 127 1.33 rillig int fixed = (int)sizeof("BLACK/ (*) vs. WHITE/ (O)") - 1; 128 1.33 rillig int total = fixed + bw + ww; 129 1.37 rillig int x; 130 1.1 tls 131 1.37 rillig if (total <= available) 132 1.37 rillig x = (available - total) / 2; 133 1.37 rillig else { 134 1.33 rillig int remaining = available - fixed; 135 1.33 rillig int half = remaining / 2; 136 1.33 rillig 137 1.33 rillig if (bw <= half) 138 1.33 rillig ww = remaining - bw; 139 1.33 rillig else if (ww <= half) 140 1.33 rillig bw = remaining - ww; 141 1.33 rillig else 142 1.33 rillig bw = half, ww = remaining - half; 143 1.37 rillig x = 0; 144 1.37 rillig } 145 1.33 rillig 146 1.37 rillig mvhline(BSZ + 2, 0, ' ', available); 147 1.37 rillig mvprintw(BSZ + 2, x, "BLACK/%.*s (*) vs. WHITE/%.*s (O)", 148 1.37 rillig bw, plyr[BLACK], ww, plyr[WHITE]); 149 1.1 tls } 150 1.1 tls 151 1.49 rillig static bool 152 1.51 rillig should_highlight(spot_index s) 153 1.49 rillig { 154 1.49 rillig 155 1.49 rillig if (game.nmoves > 0 && game.moves[game.nmoves - 1] == s) 156 1.49 rillig return true; 157 1.52 rillig if (game.win_spot != 0) 158 1.52 rillig for (int off = 0; off < 5; off++) 159 1.52 rillig if (s == game.win_spot + off * dd[game.win_dir]) 160 1.49 rillig return true; 161 1.49 rillig return false; 162 1.49 rillig } 163 1.49 rillig 164 1.1 tls /* 165 1.1 tls * Update the board display after a move. 166 1.1 tls */ 167 1.5 lukem void 168 1.10 dholland bdisp(void) 169 1.1 tls { 170 1.5 lukem struct spotstr *sp; 171 1.1 tls 172 1.52 rillig for (int row = BSZ + 1; --row > 0; ) { 173 1.52 rillig for (int col = 1; col <= BSZ; col++) { 174 1.52 rillig sp = &board[PT(col, row)]; 175 1.55 rillig char c; 176 1.1 tls if (debug > 1 && sp->s_occ == EMPTY) { 177 1.24 rillig if ((sp->s_flags & IFLAGALL) != 0) 178 1.1 tls c = '+'; 179 1.24 rillig else if ((sp->s_flags & CFLAGALL) != 0) 180 1.1 tls c = '-'; 181 1.1 tls else 182 1.1 tls c = '.'; 183 1.1 tls } else 184 1.1 tls c = pcolor[sp->s_occ]; 185 1.36 rillig 186 1.52 rillig move(scr_y(row), scr_x(col)); 187 1.52 rillig if (should_highlight(PT(col, row))) { 188 1.27 rillig attron(A_BOLD); 189 1.27 rillig addch(c); 190 1.27 rillig attroff(A_BOLD); 191 1.27 rillig } else 192 1.27 rillig addch(c); 193 1.1 tls } 194 1.1 tls } 195 1.1 tls refresh(); 196 1.1 tls } 197 1.1 tls 198 1.1 tls #ifdef DEBUG 199 1.1 tls /* 200 1.1 tls * Dump board display to a file. 201 1.1 tls */ 202 1.5 lukem void 203 1.10 dholland bdump(FILE *fp) 204 1.1 tls { 205 1.28 rillig int c; 206 1.5 lukem struct spotstr *sp; 207 1.1 tls 208 1.1 tls /* top border */ 209 1.1 tls fprintf(fp, " A B C D E F G H J K L M N O P Q R S T\n"); 210 1.1 tls 211 1.52 rillig for (int row = BSZ + 1; --row > 0; ) { 212 1.52 rillig fprintf(fp, "%2d ", row); /* left edge */ 213 1.52 rillig 214 1.52 rillig for (int col = 1; col <= BSZ; col++) { 215 1.52 rillig sp = &board[PT(col, row)]; 216 1.1 tls if (debug > 1 && sp->s_occ == EMPTY) { 217 1.25 rillig if ((sp->s_flags & IFLAGALL) != 0) 218 1.1 tls c = '+'; 219 1.25 rillig else if ((sp->s_flags & CFLAGALL) != 0) 220 1.1 tls c = '-'; 221 1.1 tls else 222 1.1 tls c = '.'; 223 1.1 tls } else 224 1.1 tls c = pcolor[sp->s_occ]; 225 1.1 tls putc(c, fp); 226 1.1 tls putc(' ', fp); 227 1.1 tls } 228 1.52 rillig 229 1.52 rillig fprintf(fp, "%d\n", row); /* right edge */ 230 1.1 tls } 231 1.1 tls 232 1.1 tls /* bottom border */ 233 1.1 tls fprintf(fp, " A B C D E F G H J K L M N O P Q R S T\n"); 234 1.1 tls } 235 1.1 tls #endif /* DEBUG */ 236 1.1 tls 237 1.1 tls /* 238 1.1 tls * Display a transcript entry 239 1.1 tls */ 240 1.5 lukem void 241 1.10 dholland dislog(const char *str) 242 1.1 tls { 243 1.1 tls 244 1.1 tls if (++lastline >= SCRNH - 1) { 245 1.1 tls /* move 'em up */ 246 1.1 tls lastline = 1; 247 1.1 tls } 248 1.36 rillig mvaddnstr(lastline, TRANSCRIPT_COL, str, SCRNW - TRANSCRIPT_COL - 1); 249 1.1 tls clrtoeol(); 250 1.14 dholland move(lastline + 1, TRANSCRIPT_COL); 251 1.1 tls clrtoeol(); 252 1.1 tls } 253 1.1 tls 254 1.1 tls /* 255 1.1 tls * Display a question. 256 1.1 tls */ 257 1.5 lukem void 258 1.10 dholland ask(const char *str) 259 1.1 tls { 260 1.23 rillig int len = (int)strlen(str); 261 1.1 tls 262 1.36 rillig mvaddstr(BSZ + 4, 0, str); 263 1.1 tls clrtoeol(); 264 1.22 rillig move(BSZ + 4, len); 265 1.1 tls refresh(); 266 1.1 tls } 267 1.1 tls 268 1.5 lukem int 269 1.15 dholland get_key(const char *allowed) 270 1.15 dholland { 271 1.15 dholland 272 1.19 rillig for (;;) { 273 1.50 rillig int ch = getch(); 274 1.50 rillig if (allowed == NULL || ch == '\0' || 275 1.50 rillig strchr(allowed, ch) != NULL) 276 1.50 rillig return ch; 277 1.50 rillig beep(); 278 1.50 rillig refresh(); 279 1.15 dholland } 280 1.15 dholland } 281 1.15 dholland 282 1.26 rillig bool 283 1.40 rillig get_line(char *buf, int size, void (*on_change)(const char *)) 284 1.1 tls { 285 1.5 lukem char *cp, *end; 286 1.5 lukem int c; 287 1.1 tls 288 1.1 tls cp = buf; 289 1.1 tls end = buf + size - 1; /* save room for the '\0' */ 290 1.39 rillig while ((c = getchar()) != EOF && c != '\n' && c != '\r') { 291 1.39 rillig if (!interactive && cp < end) { 292 1.39 rillig *cp++ = c; 293 1.39 rillig continue; 294 1.39 rillig } 295 1.39 rillig if (!interactive) 296 1.39 rillig errx(EXIT_FAILURE, "line too long"); 297 1.39 rillig 298 1.39 rillig switch (c) { 299 1.39 rillig case 0x0c: /* ^L */ 300 1.39 rillig wrefresh(curscr); 301 1.39 rillig continue; 302 1.39 rillig case 0x15: /* ^U */ 303 1.39 rillig case 0x18: /* ^X */ 304 1.39 rillig for (; cp > buf; cp--) 305 1.39 rillig addstr("\b \b"); 306 1.39 rillig break; 307 1.39 rillig case '\b': 308 1.39 rillig case 0x7f: /* DEL */ 309 1.39 rillig if (cp == buf) 310 1.1 tls continue; 311 1.39 rillig cp--; 312 1.39 rillig addstr("\b \b"); 313 1.39 rillig break; 314 1.39 rillig default: 315 1.39 rillig if (cp < end) { 316 1.39 rillig *cp++ = c; 317 1.1 tls addch(c); 318 1.39 rillig } else 319 1.39 rillig beep(); 320 1.1 tls } 321 1.40 rillig if (on_change != NULL) { 322 1.40 rillig *cp = '\0'; 323 1.40 rillig on_change(buf); 324 1.40 rillig } 325 1.39 rillig refresh(); 326 1.1 tls } 327 1.1 tls *cp = '\0'; 328 1.21 rillig return c != EOF; 329 1.1 tls } 330 1.14 dholland 331 1.46 rillig static bool 332 1.46 rillig get_coord_mouse(int *x, int *y) 333 1.46 rillig { 334 1.46 rillig MEVENT ev; 335 1.46 rillig 336 1.46 rillig if (getmouse(&ev) == OK && 337 1.46 rillig (ev.bstate & (BUTTON1_RELEASED | BUTTON1_CLICKED)) != 0 && 338 1.46 rillig ev.y >= scr_y(BSZ) && ev.y <= scr_y(1) && 339 1.46 rillig ev.x >= scr_x(1) && ev.x <= scr_x(BSZ) && 340 1.46 rillig (ev.x - scr_x(1)) % (scr_x(2) - scr_x(1)) == 0) { 341 1.46 rillig *x = 1 + (ev.x - scr_x(1)) / (scr_x(2) - scr_x(1)); 342 1.46 rillig *y = 1 + (scr_y(1) - ev.y) / (scr_y(1) - scr_y(2)); 343 1.46 rillig return true; 344 1.46 rillig } 345 1.46 rillig return false; 346 1.46 rillig } 347 1.46 rillig 348 1.14 dholland /* 349 1.43 rillig * Ask the user for the coordinate of a move, or return RESIGN or SAVE. 350 1.43 rillig * 351 1.43 rillig * Based on Eric S. Raymond's modifications to the battleship (bs) user 352 1.43 rillig * interface. 353 1.14 dholland */ 354 1.55 rillig spot_index 355 1.14 dholland get_coord(void) 356 1.14 dholland { 357 1.54 rillig int x = game.user_x, y = game.user_y; 358 1.14 dholland 359 1.45 rillig move(scr_y(y), scr_x(x)); 360 1.14 dholland refresh(); 361 1.14 dholland for (;;) { 362 1.45 rillig mvprintw(BSZ + 3, 6, "(%c %d) ", letters[x], y); 363 1.45 rillig move(scr_y(y), scr_x(x)); 364 1.14 dholland 365 1.45 rillig int ch = getch(); 366 1.14 dholland switch (ch) { 367 1.14 dholland case 'k': 368 1.14 dholland case '8': 369 1.14 dholland case KEY_UP: 370 1.45 rillig y++; 371 1.14 dholland break; 372 1.14 dholland case 'j': 373 1.14 dholland case '2': 374 1.14 dholland case KEY_DOWN: 375 1.45 rillig y--; 376 1.14 dholland break; 377 1.14 dholland case 'h': 378 1.14 dholland case '4': 379 1.14 dholland case KEY_LEFT: 380 1.45 rillig x--; 381 1.14 dholland break; 382 1.14 dholland case 'l': 383 1.14 dholland case '6': 384 1.14 dholland case KEY_RIGHT: 385 1.45 rillig x++; 386 1.14 dholland break; 387 1.14 dholland case 'y': 388 1.14 dholland case '7': 389 1.14 dholland case KEY_A1: 390 1.45 rillig x--; 391 1.45 rillig y++; 392 1.14 dholland break; 393 1.14 dholland case 'b': 394 1.14 dholland case '1': 395 1.14 dholland case KEY_C1: 396 1.45 rillig x--; 397 1.45 rillig y--; 398 1.14 dholland break; 399 1.14 dholland case 'u': 400 1.14 dholland case '9': 401 1.14 dholland case KEY_A3: 402 1.45 rillig x++; 403 1.45 rillig y++; 404 1.14 dholland break; 405 1.14 dholland case 'n': 406 1.14 dholland case '3': 407 1.14 dholland case KEY_C3: 408 1.45 rillig x++; 409 1.45 rillig y--; 410 1.14 dholland break; 411 1.14 dholland case 'K': 412 1.45 rillig y += 5; 413 1.14 dholland break; 414 1.14 dholland case 'J': 415 1.45 rillig y -= 5; 416 1.14 dholland break; 417 1.14 dholland case 'H': 418 1.45 rillig x -= 5; 419 1.14 dholland break; 420 1.14 dholland case 'L': 421 1.45 rillig x += 5; 422 1.14 dholland break; 423 1.14 dholland case 'Y': 424 1.45 rillig x -= 5; 425 1.45 rillig y += 5; 426 1.14 dholland break; 427 1.14 dholland case 'B': 428 1.45 rillig x -= 5; 429 1.45 rillig y -= 5; 430 1.14 dholland break; 431 1.14 dholland case 'U': 432 1.45 rillig x += 5; 433 1.45 rillig y += 5; 434 1.14 dholland break; 435 1.14 dholland case 'N': 436 1.45 rillig x += 5; 437 1.45 rillig y -= 5; 438 1.14 dholland break; 439 1.44 rillig case 0x0c: /* ^L */ 440 1.24 rillig (void)clearok(stdscr, true); 441 1.14 dholland (void)refresh(); 442 1.14 dholland break; 443 1.14 dholland case KEY_MOUSE: 444 1.46 rillig if (get_coord_mouse(&x, &y)) 445 1.53 rillig goto selected; 446 1.46 rillig beep(); 447 1.46 rillig break; 448 1.14 dholland case 'Q': 449 1.15 dholland case 'q': 450 1.14 dholland return RESIGN; 451 1.14 dholland case 'S': 452 1.15 dholland case 's': 453 1.14 dholland return SAVE; 454 1.14 dholland case ' ': 455 1.14 dholland case '\r': 456 1.53 rillig selected: 457 1.44 rillig (void)mvhline(BSZ + 3, 6, ' ', 6); 458 1.54 rillig game.user_x = x; 459 1.54 rillig game.user_y = y; 460 1.45 rillig return PT(x, y); 461 1.20 rillig } 462 1.20 rillig 463 1.45 rillig x = 1 + (x + BSZ - 1) % BSZ; 464 1.45 rillig y = 1 + (y + BSZ - 1) % BSZ; 465 1.14 dholland } 466 1.14 dholland } 467