bdisp.c revision 1.28
1/* $NetBSD: bdisp.c,v 1.28 2022/05/18 22:30:19 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.28 2022/05/18 22:30:19 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/* 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 %d%xd)", 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 border */ 103 for (int i = 1; i < BSZ + 1; i++) { 104 move(0, 2 * i + 1); 105 addch(letters[i]); 106 } 107 /* left and right edges */ 108 for (int j = BSZ + 1; --j > 0; ) { 109 move(20 - j, 0); 110 printw("%2d ", j); 111 move(20 - j, 2 * (BSZ + 1) + 1); 112 printw("%d ", j); 113 } 114 /* bottom border */ 115 for (int i = 1; i < BSZ + 1; i++) { 116 move(20, 2 * i + 1); 117 addch(letters[i]); 118 } 119 bdwho(false); 120 move(0, 47); 121 addstr("# black white"); 122 lastline = 0; 123 bdisp(); 124} 125 126/* 127 * Update who is playing whom. 128 */ 129void 130bdwho(bool update) 131{ 132 int i, j; 133 134 move(21, 0); 135 printw(" "); 136 i = (int)strlen(plyr[BLACK]); 137 j = (int)strlen(plyr[WHITE]); 138 if (i + j <= 20) { 139 move(21, 10 - (i + j) / 2); 140 printw("BLACK/%s (*) vs. WHITE/%s (O)", 141 plyr[BLACK], plyr[WHITE]); 142 } else { 143 move(21, 0); 144 if (i <= 10) { 145 j = 20 - i; 146 } else if (j <= 10) { 147 i = 20 - j; 148 } else { 149 i = j = 10; 150 } 151 printw("BLACK/%.*s (*) vs. WHITE/%.*s (O)", 152 i, plyr[BLACK], j, plyr[WHITE]); 153 } 154 if (update) 155 refresh(); 156} 157 158/* 159 * Update the board display after a move. 160 */ 161void 162bdisp(void) 163{ 164 int c; 165 struct spotstr *sp; 166 167 for (int j = BSZ + 1; --j > 0; ) { 168 for (int i = 1; i < BSZ + 1; i++) { 169 move(BSZ + 1 - j, 2 * i + 1); 170 sp = &board[i + j * (BSZ + 1)]; 171 if (debug > 1 && sp->s_occ == EMPTY) { 172 if ((sp->s_flags & IFLAGALL) != 0) 173 c = '+'; 174 else if ((sp->s_flags & CFLAGALL) != 0) 175 c = '-'; 176 else 177 c = '.'; 178 } else 179 c = pcolor[sp->s_occ]; 180 if (movenum > 1 && movelog[movenum - 2] == PT(i, j)) { 181 attron(A_BOLD); 182 addch(c); 183 attroff(A_BOLD); 184 } else 185 addch(c); 186 } 187 } 188 refresh(); 189} 190 191#ifdef DEBUG 192/* 193 * Dump board display to a file. 194 */ 195void 196bdump(FILE *fp) 197{ 198 int c; 199 struct spotstr *sp; 200 201 /* top border */ 202 fprintf(fp, " A B C D E F G H J K L M N O P Q R S T\n"); 203 204 for (int j = BSZ + 1; --j > 0; ) { 205 /* left edge */ 206 fprintf(fp, "%2d ", j); 207 for (int i = 1; i < BSZ + 1; i++) { 208 sp = &board[i + j * (BSZ + 1)]; 209 if (debug > 1 && sp->s_occ == EMPTY) { 210 if ((sp->s_flags & IFLAGALL) != 0) 211 c = '+'; 212 else if ((sp->s_flags & CFLAGALL) != 0) 213 c = '-'; 214 else 215 c = '.'; 216 } else 217 c = pcolor[sp->s_occ]; 218 putc(c, fp); 219 putc(' ', fp); 220 } 221 /* right edge */ 222 fprintf(fp, "%d\n", j); 223 } 224 225 /* bottom border */ 226 fprintf(fp, " A B C D E F G H J K L M N O P Q R S T\n"); 227} 228#endif /* DEBUG */ 229 230/* 231 * Display a transcript entry 232 */ 233void 234dislog(const char *str) 235{ 236 237 if (++lastline >= SCRNH - 1) { 238 /* move 'em up */ 239 lastline = 1; 240 } 241 move(lastline, TRANSCRIPT_COL); 242 addnstr(str, SCRNW - TRANSCRIPT_COL - 1); 243 clrtoeol(); 244 move(lastline + 1, TRANSCRIPT_COL); 245 clrtoeol(); 246} 247 248/* 249 * Display a question. 250 */ 251 252void 253ask(const char *str) 254{ 255 int len = (int)strlen(str); 256 257 move(BSZ + 4, 0); 258 addstr(str); 259 clrtoeol(); 260 move(BSZ + 4, len); 261 refresh(); 262} 263 264int 265get_key(const char *allowed) 266{ 267 int ch; 268 269 for (;;) { 270 ch = getch(); 271 if (allowed != NULL && 272 ch != '\0' && strchr(allowed, ch) == NULL) { 273 beep(); 274 refresh(); 275 continue; 276 } 277 break; 278 } 279 return ch; 280} 281 282bool 283get_line(char *buf, int size) 284{ 285 char *cp, *end; 286 int c; 287 288 c = 0; 289 cp = buf; 290 end = buf + size - 1; /* save room for the '\0' */ 291 while (cp < end && (c = getchar()) != EOF && c != '\n' && c != '\r') { 292 *cp++ = c; 293 if (interactive) { 294 switch (c) { 295 case 0x0c: /* ^L */ 296 wrefresh(curscr); 297 cp--; 298 continue; 299 case 0x15: /* ^U */ 300 case 0x18: /* ^X */ 301 while (cp > buf) { 302 cp--; 303 addch('\b'); 304 } 305 clrtoeol(); 306 break; 307 case '\b': 308 case 0x7f: /* DEL */ 309 if (cp == buf + 1) { 310 cp--; 311 continue; 312 } 313 cp -= 2; 314 addch('\b'); 315 c = ' '; 316 /* FALLTHROUGH */ 317 default: 318 addch(c); 319 } 320 refresh(); 321 } 322 } 323 *cp = '\0'; 324 return c != EOF; 325} 326 327/* 328 * Decent (n)curses interface for the game, based on Eric S. Raymond's 329 * modifications to the battleship (bs) user interface. 330 */ 331int 332get_coord(void) 333{ 334 static int curx = BSZ / 2; 335 static int cury = BSZ / 2; 336 int ny, nx, ch; 337 338 BGOTO(cury, curx); 339 refresh(); 340 nx = curx; 341 ny = cury; 342 for (;;) { 343 mvprintw(BSZ + 3, (BSZ - 6) / 2, "(%c %d) ", 344 'A' + ((curx > 7) ? (curx + 1) : curx), cury + 1); 345 BGOTO(cury, curx); 346 347 ch = getch(); 348 switch (ch) { 349 case 'k': 350 case '8': 351 case KEY_UP: 352 nx = curx; 353 ny = cury + 1; 354 break; 355 case 'j': 356 case '2': 357 case KEY_DOWN: 358 nx = curx; 359 ny = BSZ + cury - 1; 360 break; 361 case 'h': 362 case '4': 363 case KEY_LEFT: 364 nx = BSZ + curx - 1; 365 ny = cury; 366 break; 367 case 'l': 368 case '6': 369 case KEY_RIGHT: 370 nx = curx + 1; 371 ny = cury; 372 break; 373 case 'y': 374 case '7': 375 case KEY_A1: 376 nx = BSZ + curx - 1; 377 ny = cury + 1; 378 break; 379 case 'b': 380 case '1': 381 case KEY_C1: 382 nx = BSZ + curx - 1; 383 ny = BSZ + cury - 1; 384 break; 385 case 'u': 386 case '9': 387 case KEY_A3: 388 nx = curx + 1; 389 ny = cury + 1; 390 break; 391 case 'n': 392 case '3': 393 case KEY_C3: 394 nx = curx + 1; 395 ny = BSZ + cury - 1; 396 break; 397 case 'K': 398 nx = curx; 399 ny = cury + 5; 400 break; 401 case 'J': 402 nx = curx; 403 ny = BSZ + cury - 5; 404 break; 405 case 'H': 406 nx = BSZ + curx - 5; 407 ny = cury; 408 break; 409 case 'L': 410 nx = curx + 5; 411 ny = cury; 412 break; 413 case 'Y': 414 nx = BSZ + curx - 5; 415 ny = cury + 5; 416 break; 417 case 'B': 418 nx = BSZ + curx - 5; 419 ny = BSZ + cury - 5; 420 break; 421 case 'U': 422 nx = curx + 5; 423 ny = cury + 5; 424 break; 425 case 'N': 426 nx = curx + 5; 427 ny = BSZ + cury - 5; 428 break; 429 case '\f': 430 nx = curx; 431 ny = cury; 432 (void)clearok(stdscr, true); 433 (void)refresh(); 434 break; 435#if 0 /* notyet */ 436 case KEY_MOUSE: 437 { 438 MEVENT myevent; 439 440 getmouse(&myevent); 441 if (myevent.y >= 1 && myevent.y <= BSZ + 1 && 442 myevent.x >= 3 && myevent.x <= 2 * BSZ + 1) { 443 curx = (myevent.x - 3) / 2; 444 cury = BSZ - myevent.y; 445 return PT(curx,cury); 446 } else { 447 beep(); 448 } 449 } 450 break; 451#endif /* 0 */ 452 case 'Q': 453 case 'q': 454 return RESIGN; 455 case 'S': 456 case 's': 457 return SAVE; 458 case ' ': 459 case '\r': 460 (void)mvaddstr(BSZ + 3, (BSZ - 6) / 2, " "); 461 return PT(curx + 1, cury + 1); 462 } 463 464 curx = nx % BSZ; 465 cury = ny % BSZ; 466 } 467} 468