Better user interface. From OpenBSD, written by Paul Janzen quite a

long time ago. A few minor adjustments by yours truly.
This commit is contained in:
dholland 2010-03-29 03:51:55 +00:00
parent 6c6b8bd86e
commit 4a11aa7558
4 changed files with 258 additions and 61 deletions

View File

@ -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;
}
}

View File

@ -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 .

View File

@ -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 *);

View File

@ -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;