From 3c3f8c0880fed372a83ed917c866247edb974156 Mon Sep 17 00:00:00 2001 From: dholland Date: Mon, 29 Mar 2010 03:51:55 +0000 Subject: Better user interface. From OpenBSD, written by Paul Janzen quite a long time ago. A few minor adjustments by yours truly. --- gomoku/bdisp.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++------ gomoku/gomoku.6 | 43 +++++++----- gomoku/gomoku.h | 12 +++- gomoku/main.c | 61 ++++++++++------- 4 files changed, 258 insertions(+), 61 deletions(-) (limited to 'gomoku') diff --git a/gomoku/bdisp.c b/gomoku/bdisp.c index fe227618..075ea172 100644 --- a/gomoku/bdisp.c +++ b/gomoku/bdisp.c @@ -1,4 +1,4 @@ -/* $NetBSD: bdisp.c,v 1.13 2010/03/29 02:21:04 dholland Exp $ */ +/* $NetBSD: bdisp.c,v 1.14 2010/03/29 03:51:55 dholland Exp $ */ /* * Copyright (c) 1994 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)bdisp.c 8.2 (Berkeley) 5/3/95"; #else -__RCSID("$NetBSD: bdisp.c,v 1.13 2010/03/29 02:21:04 dholland Exp $"); +__RCSID("$NetBSD: bdisp.c,v 1.14 2010/03/29 03:51:55 dholland Exp $"); #endif #endif /* not lint */ @@ -66,9 +66,19 @@ cursinit(void) if (!initscr()) { errx(EXIT_FAILURE, "Couldn't initialize screen"); } + if ((LINES < SCRNH) || (COLS < SCRNW)) { + errx(EXIT_FAILURE, "Screen too small (need %d%xd)", + SCRNW, SCRNH); + } + keypad(stdscr, TRUE); + nonl(); noecho(); cbreak(); - leaveok(stdscr, TRUE); + leaveok(stdscr, FALSE); + +#if 0 /* no mouse support in netbsd curses yet */ + mousemask(BUTTON1_CLICKED, NULL); +#endif } /* @@ -78,10 +88,10 @@ void cursfini(void) { - leaveok(stdscr, FALSE); - move(23, 0); + move(BSZ4, 0); clrtoeol(); refresh(); + echo(); endwin(); } @@ -123,18 +133,28 @@ bdisp_init(void) void bdwho(int update) { - int i; + int i, j; move(21, 0); - clrtoeol(); - i = 6 - strlen(plyr[BLACK]) / 2; - move(21, i > 0 ? i : 0); - printw("BLACK/%s", plyr[BLACK]); - i = 30 - strlen(plyr[WHITE]) / 2; - move(21, i); - printw("WHITE/%s", plyr[WHITE]); - move(21, 19); - addstr(" vs. "); + printw(" "); + i = strlen(plyr[BLACK]); + j = strlen(plyr[WHITE]); + if (i + j <= 20) { + move(21, 10 - (i+j)/2); + printw("BLACK/%s (*) vs. WHITE/%s (O)", + plyr[BLACK], plyr[WHITE]); + } else { + move(21, 0); + if (i <= 10) { + j = 20 - i; + } else if (j <= 10) { + i = 20 - j; + } else { + i = j = 10; + } + printw("BLACK/%.*s (*) vs. WHITE/%.*s (O)", + i, plyr[BLACK], j, plyr[WHITE]); + } if (update) refresh(); } @@ -217,10 +237,10 @@ dislog(const char *str) /* move 'em up */ lastline = 1; } - move(lastline, 46); - addnstr(str, SCRNW - 46 - 1); + move(lastline, TRANSCRIPT_COL); + addnstr(str, SCRNW - TRANSCRIPT_COL - 1); clrtoeol(); - move(lastline + 1, 46); + move(lastline + 1, TRANSCRIPT_COL); clrtoeol(); } @@ -233,10 +253,10 @@ ask(const char *str) { int len = strlen(str); - move(23, 0); + move(BSZ4, 0); addstr(str); clrtoeol(); - move(23, len); + move(BSZ4, len); refresh(); } @@ -284,3 +304,146 @@ get_line(char *buf, int size) *cp = '\0'; return(c != EOF); } + +/* + * Decent (n)curses interface for the game, based on Eric S. Raymond's + * modifications to the battleship (bs) user interface. + */ +int +get_coord(void) +{ + static int curx = BSZ / 2; + static int cury = BSZ / 2; + int ny, nx, ch; + + BGOTO(cury, curx); + refresh(); + nx = curx; + ny = cury; + for (;;) { + mvprintw(BSZ3, (BSZ -6)/2, "(%c %d)", + 'A'+ ((curx > 7) ? (curx+1) : curx), cury + 1); + BGOTO(cury, curx); + + ch = getch(); + switch (ch) { + case 'k': + case '8': + case KEY_UP: + nx = curx; + ny = cury + 1; + break; + case 'j': + case '2': + case KEY_DOWN: + nx = curx; + ny = BSZ + cury - 1; + break; + case 'h': + case '4': + case KEY_LEFT: + nx = BSZ + curx - 1; + ny = cury; + break; + case 'l': + case '6': + case KEY_RIGHT: + nx = curx + 1; + ny = cury; + break; + case 'y': + case '7': + case KEY_A1: + nx = BSZ + curx - 1; + ny = cury + 1; + break; + case 'b': + case '1': + case KEY_C1: + nx = BSZ + curx - 1; + ny = BSZ + cury - 1; + break; + case 'u': + case '9': + case KEY_A3: + nx = curx + 1; + ny = cury + 1; + break; + case 'n': + case '3': + case KEY_C3: + nx = curx + 1; + ny = BSZ + cury - 1; + break; + case 'K': + nx = curx; + ny = cury + 5; + break; + case 'J': + nx = curx; + ny = BSZ + cury - 5; + break; + case 'H': + nx = BSZ + curx - 5; + ny = cury; + break; + case 'L': + nx = curx + 5; + ny = cury; + break; + case 'Y': + nx = BSZ + curx - 5; + ny = cury + 5; + break; + case 'B': + nx = BSZ + curx - 5; + ny = BSZ + cury - 5; + break; + case 'U': + nx = curx + 5; + ny = cury + 5; + break; + case 'N': + nx = curx + 5; + ny = BSZ + cury - 5; + break; + case '\f': + nx = curx; + ny = cury; + (void)clearok(stdscr, TRUE); + (void)refresh(); + break; +#if 0 /* notyet */ + case KEY_MOUSE: + { + MEVENT myevent; + + getmouse(&myevent); + if (myevent.y >= 1 && myevent.y <= BSZ1 && + myevent.x >= 3 && myevent.x <= (2 * BSZ + 1)) { + curx = (myevent.x - 3) / 2; + cury = BSZ - myevent.y; + return PT(curx,cury); + } else { + beep(); + } + } + break; +#endif /* 0 */ + case 'Q': + return RESIGN; + break; + case 'S': + return SAVE; + break; + case ' ': + case '\r': + (void) mvaddstr(BSZ3, (BSZ -6)/2, " "); + return PT(curx+1,cury+1); + break; + } + + curx = nx % BSZ; + cury = ny % BSZ; + } +} diff --git a/gomoku/gomoku.6 b/gomoku/gomoku.6 index 6abec4b0..0a36d6d3 100644 --- a/gomoku/gomoku.6 +++ b/gomoku/gomoku.6 @@ -1,4 +1,4 @@ -.\" $NetBSD: gomoku.6,v 1.13 2010/03/29 02:34:50 dholland Exp $ +.\" $NetBSD: gomoku.6,v 1.14 2010/03/29 03:51:55 dholland Exp $ .\" .\" Copyright (c) 1994 .\" The Regents of the University of California. All rights reserved. @@ -32,7 +32,7 @@ .\" .\" @(#)gomoku.6 8.2 (Berkeley) 8/4/94 .\" -.Dd August 4, 1994 +.Dd March 28, 2010 .Dt GOMOKU 6 .Os .Sh NAME @@ -42,7 +42,7 @@ .Nm .Op Fl bcdu .Op Fl D Ar debugfile -.Op Ar inputfile +.Op Ar savefile .Sh DESCRIPTION .Nm is a two player game where the object is to get 5 in a row horizontally, @@ -51,19 +51,26 @@ By convention, black always moves first. With no arguments, .Nm will display a playing board and prompt for moves from the user. -Valid moves are a letter for the column and a number for the row of an empty -board location. -Entering -.Dq quit -or -.Dq resign -will end the game. -You can save the current state of the game by entering -.Dq save -and supplying a file name when prompted. -The optional file -.Ar inputfile -can be used to restore a saved game. +Moves may be entered by selecting the desired board location and +pressing the space or enter key. +The cursor may be moved using the arrow keys or +.Xr vi 1 +motion keys +.Em hjklyubn . +These also may be familiar from +.Xr rogue 6 +and +.Xr hack 6 . +.\" Valid moves are a letter for the column and a number for the row +.\" of an empty board location. +To quit, type +.Sq Q , +and to save the game, type +.Sq S +and supply a file name when prompted. +To restore a saved game, pass the file name on the +.Nm +command line. .Pp The options are: .Bl -tag -width Ds @@ -102,3 +109,7 @@ This is mostly used for testing. The board display routines were based on the .Nm goref program written by Peter Langston. +The user interface was based on Eric S. Raymond's interface for +.\" change this when/if we import openbsd's bs(6) +.\" .Xr bs 6 . +.Nm bs . diff --git a/gomoku/gomoku.h b/gomoku/gomoku.h index bf83379a..bf97b1cf 100644 --- a/gomoku/gomoku.h +++ b/gomoku/gomoku.h @@ -1,4 +1,4 @@ -/* $NetBSD: gomoku.h,v 1.17 2009/08/12 06:19:17 dholland Exp $ */ +/* $NetBSD: gomoku.h,v 1.18 2010/03/29 03:51:55 dholland Exp $ */ /* * Copyright (c) 1994 @@ -42,9 +42,16 @@ #define BSZ 19 #define BSZ1 (BSZ+1) #define BSZ2 (BSZ+2) +#define BSZ3 (BSZ+3) +#define BSZ4 (BSZ+4) #define BAREA (BSZ2*BSZ1+1) -/* frame dimentions (based on 5 in a row) */ +#define TRANSCRIPT_COL 46 /* necessarily == 2*BSZ4 */ + +/* interactive curses stuff */ +#define BGOTO(y,x) move(BSZ - (y), 2 * (x) + 3) + +/* frame dimensions (based on 5 in a row) */ #define FSZ1 BSZ #define FSZ2 (BSZ-4) #define FAREA (FSZ1*FSZ2 + FSZ2*FSZ2 + FSZ1*FSZ2 + FSZ2*FSZ2) @@ -261,6 +268,7 @@ extern int debug; #define ASSERT(x) void bdinit(struct spotstr *); +int get_coord(void); int get_line(char *, int); void ask(const char *); void dislog(const char *); diff --git a/gomoku/main.c b/gomoku/main.c index f557c64b..769bfef7 100644 --- a/gomoku/main.c +++ b/gomoku/main.c @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.22 2010/03/29 02:48:17 dholland Exp $ */ +/* $NetBSD: main.c,v 1.23 2010/03/29 03:51:55 dholland Exp $ */ /* * Copyright (c) 1994 @@ -42,7 +42,7 @@ __COPYRIGHT("@(#) Copyright (c) 1994\ #if 0 static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 5/4/95"; #else -__RCSID("$NetBSD: main.c,v 1.22 2010/03/29 02:48:17 dholland Exp $"); +__RCSID("$NetBSD: main.c,v 1.23 2010/03/29 03:51:55 dholland Exp $"); #endif #endif /* not lint */ @@ -66,6 +66,7 @@ int interactive = 1; /* true if interactive */ int debug; /* true if debugging */ static int test; /* both moves come from 1: input, 2: computer */ static char *prog; /* name of program */ +static char user[LOGIN_NAME_MAX]; /* name of player */ static FILE *debugfp; /* file for debug output */ static FILE *inputfp; /* file for debug input */ @@ -90,6 +91,7 @@ main(int argc, char **argv) { char buf[128]; char fname[PATH_MAX]; + char *tmp; int color, curmove, i, ch; int input[2]; static const char *const fmt[2] = { @@ -100,6 +102,13 @@ main(int argc, char **argv) /* Revoke setgid privileges */ setgid(getgid()); + tmp = getlogin(); + if (tmp) { + strlcpy(user, tmp, sizeof(user)); + } else { + strcpy(user, "you"); + } + color = curmove = 0; prog = strrchr(argv[0], '/'); @@ -156,21 +165,21 @@ again: #endif if (inputfp == NULL && test == 0) { + ask("black or white? "); for (;;) { - ask("black or white? "); - get_line(buf, sizeof(buf)); - if (buf[0] == 'b' || buf[0] == 'B') { + ch = getchar(); + if (ch == 'b' || ch == 'B') { color = BLACK; break; } - if (buf[0] == 'w' || buf[0] == 'W') { + if (ch == 'w' || ch == 'W') { color = WHITE; break; } - move(22, 0); + move(BSZ3, 0); printw("Black moves first. Please enter `black' or `white'\n"); } - move(22, 0); + move(BSZ3, 0); clrtoeol(); } } else { @@ -208,8 +217,8 @@ again: } } if (interactive) { - plyr[BLACK] = input[BLACK] == USER ? "you" : prog; - plyr[WHITE] = input[WHITE] == USER ? "you" : prog; + plyr[BLACK] = input[BLACK] == USER ? user : prog; + plyr[WHITE] = input[WHITE] == USER ? user : prog; bdwho(1); } @@ -236,23 +245,16 @@ again: input[WHITE] = PROGRAM; break; } - plyr[BLACK] = input[BLACK] == USER ? "you" : prog; - plyr[WHITE] = input[WHITE] == USER ? "you" : prog; + plyr[BLACK] = input[BLACK] == USER ? user : prog; + plyr[WHITE] = input[WHITE] == USER ? user : prog; bdwho(1); goto top; case USER: /* input comes from standard input */ getinput: - if (interactive) - ask("move? "); - if (!get_line(buf, sizeof(buf))) { - curmove = RESIGN; - break; - } - if (buf[0] == '\0') - goto getinput; - curmove = ctos(buf); if (interactive) { + ask("move? "); + curmove = get_coord(); if (curmove == SAVE) { FILE *fp; @@ -270,13 +272,24 @@ again: } if (curmove != RESIGN && board[curmove].s_occ != EMPTY) { - misclog("Illegal move"); + /*misclog("Illegal move");*/ + beep(); goto getinput; } + } else { + if (!get_line(buf, sizeof(buf))) { + curmove = RESIGN; + break; + } + if (buf[0] == '\0') + goto getinput; + curmove = ctos(buf); } break; case PROGRAM: /* input comes from the program */ + if (interactive) + ask("Thinking..."); curmove = pickmove(color); break; } @@ -289,11 +302,13 @@ again: bdisp(); } if (interactive) { - move(22, 0); + move(BSZ3, 0); switch (i) { case WIN: if (input[color] == PROGRAM) addstr("Ha ha, I won"); + else if (input[0] == USER && input[1] == USER) + addstr("Well, you won (and lost)"); else addstr("Rats! you won"); break; -- cgit v1.2.3-56-ge451