keith@motel6.UUCP (Keith Packard) (07/09/85)
This is the source to an othello program I wrote completely from scratch. Do what you will to the source but, if you mangle it don't expect me to fix it... As usual, bug fixes will be most gratefully accepted. If you care to figure out how the edgescore array is generated you can probably improve the play considerably by mucking about with the generating yacc program makeedge.y. This was developed on my pdp 11/73 running 2.9BSD unix. I do nothing weird to either the screen or to signals; it *should* run without major modifications on sys5, sys3 and, gasp, even version 7. It ran at one time on 4.2BSD and I haven't made substantial changes since then so, who knows, it may run there with no modifications! Keith Packard ...!tektronix!reed!motel6!keith ...!tektronix!azure!keithp *** Writing silly programs so you don't have to. *** [ With cat like tread upon our prey we steal... ] : shell archive - extract with /bin/sh : corners.c : count.c : display.c : edges.c : fini.c : gencor.c : genedge.c : hasmove.c : legal.c : makeedge.y : makefile : minmax.c : move.c : reversi.h : score.c : ulex.l : user.y sed 's/^X//' << \EOF_OF_corners.c >corners.c X/* X * cornerscores.c X */ X Xshort cornerscores[81] = { X -20, /* O O O O */ X 0, /* O O O - */ X 10, /* O O O * */ X -20, /* O O - O */ X 0, /* O O - - */ X -10, /* O O - * */ X -20, /* O O * O */ X 0, /* O O * - */ X 20, /* O O * * */ X -20, /* O - O O */ X 0, /* O - O - */ X -10, /* O - O * */ X -20, /* O - - O */ X 0, /* O - - - */ X -10, /* O - - * */ X -20, /* O - * O */ X 0, /* O - * - */ X 20, /* O - * * */ X -20, /* O * O O */ X 0, /* O * O - */ X 20, /* O * O * */ X -20, /* O * - O */ X 0, /* O * - - */ X 10, /* O * - * */ X -20, /* O * * O */ X 0, /* O * * - */ X 10, /* O * * * */ X 40, /* - O O O */ X 0, /* - O O - */ X -40, /* - O O * */ X 40, /* - O - O */ X 0, /* - O - - */ X -40, /* - O - * */ X 40, /* - O * O */ X 0, /* - O * - */ X -40, /* - O * * */ X 40, /* - - O O */ X 0, /* - - O - */ X -40, /* - - O * */ X 40, /* - - - O */ X 0, /* - - - - */ X -40, /* - - - * */ X 40, /* - - * O */ X 0, /* - - * - */ X -40, /* - - * * */ X 40, /* - * O O */ X 0, /* - * O - */ X -40, /* - * O * */ X 40, /* - * - O */ X 0, /* - * - - */ X -40, /* - * - * */ X 40, /* - * * O */ X 0, /* - * * - */ X -40, /* - * * * */ X -20, /* * O O O */ X 0, /* * O O - */ X 20, /* * O O * */ X -10, /* * O - O */ X 0, /* * O - - */ X 20, /* * O - * */ X -10, /* * O * O */ X 0, /* * O * - */ X 20, /* * O * * */ X -10, /* * - O O */ X 0, /* * - O - */ X 20, /* * - O * */ X -10, /* * - - O */ X 0, /* * - - - */ X 20, /* * - - * */ X -10, /* * - * O */ X 0, /* * - * - */ X 20, /* * - * * */ X -10, /* * * O O */ X 0, /* * * O - */ X 20, /* * * O * */ X -10, /* * * - O */ X 0, /* * * - - */ X 20, /* * * - * */ X -10, /* * * * O */ X 0, /* * * * - */ X 20, /* * * * * */ X }; EOF_OF_corners.c echo extracting 'count.c' sed 's/^X//' << \EOF_OF_count.c >count.c X/* X * count.c X * X * count up the board X */ X X# include "reversi.h" X Xcount (player, board) XboardT board; X{ X register int x, y, count; X X count = 0; X for (x = 1; x <= SIZE; x++) X for (y = 1; y <= SIZE; y++) X count += board[x][y]; X return count * player; X} EOF_OF_count.c echo extracting 'display.c' sed 's/^X//' << \EOF_OF_display.c >display.c X/* X * display.c X */ X X# include "reversi.h" X# include <curses.h> X# include <ctype.h> X X# define toscrx(x) ((x) * 5 - 1) X# define toscry(y) ((y) * 3 - 2) X X# define LINEX (toscrx(10)-2) X# define LINEY (toscry(5)+1) X Xstatic helpShown; X XdispInit () X{ X register int i, j; X int dispEnd(); X X initscr (); X savetty(); X noecho (); X crmode (); X helpShown = 0; X for (i = 1; i <= SIZE; i++) { X move (toscry(i), 0); X printw ("%1d", i); X move (0, toscrx(i)); X printw ("%1d", i); X } X refresh (); X} X XdispGrid () X{ X register int i, j; X X for (i = 1; i <= SIZE; i++) { X for (j = 1; j <= SIZE + 1; j++) { X if (i <= SIZE) { X move (toscry(i)+1, toscrx(j)-2); X addch ('|'); X move (toscry(i), toscrx(j)-2); X addch ('|'); X move (toscry(i)-1, toscrx(j)-2); X } X if (j <= SIZE) { X if (i == 1) X printw ("+-%1d--", j); X else X addstr ("+----"); X } else X addstr ("+"); X } X } X refresh (); X} X XdispNoGrid () X{ X register int i, j; X X for (i = 1; i <= SIZE; i++) { X for (j = 1; j <= SIZE + 1; j++) { X move (toscry(i)+1, toscrx(j)-2); X addch (' '); X move (toscry(i), toscrx(j)-2); X addch (' '); X move (toscry(i)-1, toscrx(j)-2); X if (j <= SIZE) { X if (i == 1) X printw (" %1d ", j); X else X addstr (" "); X } else X addstr (" "); X } X } X refresh (); X} X XdispEnd () X{ X clearok(stdscr, 1); X erase (); X refresh (); X resetty(); X endwin (); X exit (0); X} X XboardT old; X Xdisplay (board) XboardT board; X{ X register int i,j; X extern int showScore; X X for (i = 1; i <= SIZE; i++) X for (j = 1; j <= SIZE; j++) X if (board[i][j] != old[i][j]) { X dispOne (i, j, board[i][j]); X old[i][j] = board[i][j]; X } X refresh (); X if (showScore) X dispScore (board); X} X XdispOne (y, x, who) X{ X move (toscry (y), toscrx (x)); X switch (who) { X case BLACK: X addstr ("/\\"); X break; X case WHITE: X addstr ("**"); X break; X case EMPTY: X addstr (" "); X break; X } X move (toscry(y) + 1, toscrx (x)); X switch (who) { X case BLACK: X addstr ("\\/"); X break; X case WHITE: X addstr ("**"); X break; X case EMPTY: X addstr (" "); X break; X } X} X XdispScore (board) Xregister boardT board; X{ X register int i,j; X register int ws, bs; X X ws = bs = 0; X for (i = 1; i <= SIZE; i++) X for (j = 1; j <= SIZE; j++) X switch (board[i][j]) { X case WHITE: X ws++; break; X case BLACK: X bs++; break; X } X move (LINEY - 3, LINEX); X printw ("white: %-2d black: %-2d", ws, bs); X refresh (); X} X XdispNoScore () X{ X move (LINEY - 3, LINEX); X clrtoeol (); X refresh (); X} X Xstatic char *helpText[] = { X "y, x [no] grid", X "[no] help hint", X "play quit", X "restart record", X "replay save", X "[no] score undo", X "level", X "white|black first", X "white|black second", X 0, X}; X XdispTurn (player) X{ X static displayed = EMPTY; X X if (displayed == player) X return; X move (LINEY-1, LINEX); X switch (player) { X case WHITE: X addstr ("white's turn"); X break; X case BLACK: X addstr ("black's turn"); X break; X case EMPTY: X clrtoeol (); X } X displayed = player; X refresh (); X} X XdispHelp () X{ X register int i; X register char **h; X X if (helpShown) X return; X i = 0; X for (h = helpText; *h; ++h) { X move (i, LINEX); X addstr (*h); X ++i; X } X move (LINEY+4, LINEX); X printw ("white pieces are **"); X move (LINEY+5, LINEX+18); X printw ("**"); X move (LINEY+7, LINEX); X printw ("black pieces are /\\"); X move (LINEY+8, LINEX+18); X printw ("\\/"); X refresh (); X ++helpShown; X} X XdispNoHelp () X{ X register int i; X register char **h; X X if (!helpShown) X return; X i = 0; X for (h = helpText; *h; ++h) { X move (i, LINEX); X clrtoeol (); X ++i; X } X move (LINEY+4, LINEX); X clrtoeol (); X move (LINEY+5, LINEX+18); X clrtoeol (); X move (LINEY+7, LINEX); X clrtoeol (); X move (LINEY+8, LINEX+18); X clrtoeol (); X refresh (); X helpShown = 0; X} X Xstatic char lexbuf[256]; Xstatic char *lexpnt; X XreadLine () X{ X int ch, x, y; X X move (LINEY, LINEX); X addstr ("-> "); Xloop: X x = LINEX+3; X y = LINEY; X move (y, x); X clrtoeol (); X refresh (); X lexpnt = lexbuf; X for (;;) { X ch = getch (); X if (ch == -1) X ch = '\004'; X *lexpnt++ = ch; X if (isprint (ch)) { X addch (ch); X ++x; X refresh (); X } else X switch (ch) { X case '\f': X clearok (stdscr, 1); X case '\030': X case '\025': X goto loop; X case '\004': X *lexpnt++ = -1; X case '\r': X case '\n': X move (LINEY+1, LINEX); X refresh (); X *lexpnt++ = '\0'; X goto done; X case '\b': X if (lexpnt >= lexbuf + 2) { X lexpnt -= 2; X --x; X move (y,x); X delch (); X refresh (); X } else X --lexpnt; X break; X default: X --lexpnt; X write (1, "\007", 1); X break; X } X } Xdone: lexpnt = lexbuf; X dispError (""); X} X Xlexgetc () X{ X int c; X extern int yylineno; X X c = *lexpnt++; X if (c == -1) X c = 4; X c &= 0177; X if (c == '\r') X c = '\n'; X if (c == '\n') X ++yylineno; X return c; X} X Xlexungetc (c) X{ X --lexpnt; X} X XdispError (s) Xchar *s; X{ X move (LINEY+1, LINEX); X clrtoeol (); X addstr (s); X refresh (); X} EOF_OF_display.c echo extracting 'edges.c' sed 's/^X//' << \EOF_OF_edges.c >edges.c X/* X * edgescores.c X */ X Xshort edgescores [6561] = { X# include "edges.out" X}; EOF_OF_edges.c echo extracting 'fini.c' sed 's/^X//' << \EOF_OF_fini.c >fini.c X/* X * fini.c X * X * count up score and display winner X */ X X# include "reversi.h" X Xfini (board) XboardT board; X{ X register int x,y; X register int wscore, bscore; X char sbuf[80]; X X wscore = bscore = 0; X X for (x = 1; x <= SIZE; x++) X for (y = 1; y <= SIZE; y++) X if (board[x][y] == WHITE) X ++wscore; X else if (board[x][y] == BLACK) X ++bscore; X if (wscore > bscore) X sprintf (sbuf, "white wins %d to %d.", wscore, bscore); X else if (bscore > wscore) X sprintf (sbuf, "black wins %d to %d.", bscore, wscore); X else X sprintf (sbuf, "tie game %d to %d.", wscore, bscore); X dispError (sbuf); X} EOF_OF_fini.c echo extracting 'gencor.c' sed 's/^X//' << \EOF_OF_gencor.c >gencor.c X/* X * generate preliminary corner score array X */ X Xchar board[9]; X Xmain () X{ X register int i; X for (board[1] = -1; board[1] <= 1; board[1]++) X for (board[2] = -1; board[2] <= 1; board[2]++) X for (board[3] = -1; board[3] <= 1; board[3]++) X for (board[4] = -1; board[4] <= 1; board[4]++) { X for (i = 1; i <= 4; i++) X switch (board[i]) { X case 0: X printf (" -"); X break; X case -1: X printf (" O"); X break; X case 1: X printf (" *"); X break; X } X printf ("\n"); X } X} EOF_OF_gencor.c echo extracting 'genedge.c' sed 's/^X//' << \EOF_OF_genedge.c >genedge.c X/* X * generate preliminary edge score array X */ X Xchar board[9]; X Xmain () X{ X register int i; X for (board[1] = -1; board[1] <= 1; board[1]++) X for (board[2] = -1; board[2] <= 1; board[2]++) X for (board[3] = -1; board[3] <= 1; board[3]++) X for (board[4] = -1; board[4] <= 1; board[4]++) X for (board[5] = -1; board[5] <= 1; board[5]++) X for (board[6] = -1; board[6] <= 1; board[6]++) X for (board[7] = -1; board[7] <= 1; board[7]++) X for (board[8] = -1; board[8] <= 1; board[8]++) { X for (i = 1; i <= 8; i++) X switch (board[i]) { X case 0: X printf (" -"); X break; X case -1: X printf (" O"); X break; X case 1: X printf (" *"); X break; X } X printf ("\n"); X } X} EOF_OF_genedge.c echo extracting 'hasmove.c' sed 's/^X//' << \EOF_OF_hasmove.c >hasmove.c X/* X * hasmove.c X * X * figure out if player has move in board X */ X X# include "reversi.h" X Xhasmove (player, board) XboardT board; X{ X register int x,y; X X for (x = 1; x <= SIZE; x++) X for (y = 1; y <= SIZE; y++) X if (legal (player, x, y, board)) X return 1; X return 0; X} EOF_OF_hasmove.c echo extracting 'legal.c' sed 's/^X//' << \EOF_OF_legal.c >legal.c X# include "reversi.h" Xextern int offsets[]; X Xlegal (player, x, y, board) Xregister int player; Xint x, y; XboardT board; X{ X register char *b, *m; X register int *o, i; X X b = & board[x][y]; X player = -player; X if (*b == EMPTY) { X for (o = offsets; i = *o++;) { X if (b[i] == player) { X m = b+i; X while (*m == player) X m += i; X if (*m == -player) X return 1; X } X } X } X return 0; X} EOF_OF_legal.c echo extracting 'makeedge.y' sed 's/^X//' << \EOF_OF_makeedge.y >makeedge.y X%{ X/* X * ex:set ts=8 sw=8: X */ Xint score; Xextern int position; X%} X%union { X struct { X int width; X int position; X int base; X } field; X int ival; X} X%type <field> line whites blacks empties oempties X%type <field> type1 type2 otype3e type3e type3 otype4 type4 type4.w type4.b X%token <field> WHITE BLACK EMPTY X%token <ival> NL X%% Xlines : lines line X { printf ("\t%5d,\t/*%s */\n", $2.base, line); } X | X ; Xline : whites type1 NL X { $$.base = 20 * $1.width + $2.base; } X | blacks type2 NL X { $$.base = -20 * $1.width + $2.base; } X | EMPTY type3 NL X { $$.base = $2.base; } X | EMPTY empties otype4 NL X { $$.base = $3.base; } X ; Xtype1 : blacks whites empties otype4 X { X $$.base = $4.base; X switch ($2.position) { X case 7: X $$.base -= ($2.width + $1.width+1) * 15; X break; X default: X if ($3.width == 1) X $$.base -= X ($1.width + $2.width+1) * 15; X else X $$.base += X ($2.width - $1.width) * 20; X break; X } X $$.position = $4.position; X $$.width = $1.width + $2.width + $3.width; X } X | blacks whites type1 X { X $$.base = $3.base; X $$.base -= ($1.width - $2.width) * 20; X $$.position = $3.position; X $$.width = $1.width + $2.width + $3.width; X } X | blacks empties otype4 X { X $$.base = ($1.width + 1) * 15 + $3.base; X $$.width = $1.width + $2.width + $3.width; X $$.position = $3.position; X } X | blacks X { X $$ = $1; X $$.base = - $1.width * 20; X } X | empties otype4 X { X $$.position = $2.position; X $$.width = $1.width+$2.width; X $$.base = $2.base; X } X | X { $$.position = position; $$.width = 0; $$.base = 0; } X ; Xtype2 : whites blacks empties otype4 X { X $$.base = $4.base; X switch ($2.position) { X case 7: X $$.base += ($2.width + $1.width+1) * 15; X break; X default: X if ($3.width == 1) X $$.base += X ($1.width + $2.width+1) * 15; X else X $$.base -= X ($2.width - $1.width) * 20; X break; X } X $$.position = $4.position; X $$.width = $1.width + $2.width + $3.width X + $4.width; X } X | whites blacks type2 X { X $$.base = $3.base; X $$.base += ($1.width - $2.width) * 20; X $$.position = $3.position; X $$.width = $1.width + $2.width + $3.width; X } X | whites empties otype4 X { X $$.base = - ($1.width + 1) * 15 + $3.base; X $$.width = $1.width + $2.width + $3.width; X $$.position = $3.position; X } X | whites X { X $$ = $1; X $$.base = $1.width * 20; X } X | empties otype4 X { X $$.position = $2.position; X $$.width = $1.width+$2.width; X $$.base = $2.base; X } X | X { $$.position = 0; $$.width = 0; $$.base = 0; } X ; Xotype4 : type4 X { $$ = $1; } X | X { $$.position = position; $$.width = 0; $$.base = 0; } X ; Xwhites : whites WHITE X { X $$.position = $2.position; X $$.width = $1.width + $2.width; X $$.base = $1.base + $2.base; X } X | WHITE X { $$ = $1; } X ; Xblacks : blacks BLACK X { X $$.position = $2.position; X $$.width = $1.width + $2.width; X $$.base = $1.base + $2.base; X } X | BLACK X { $$ = $1; } X ; Xempties : empties EMPTY X { X $$.position = $2.position; X $$.width = $1.width + $2.width; X $$.base = $1.base + $2.base; X } X | EMPTY X { $$ = $1; } X ; Xotype3e : type3e X { $$ = $1; } X | X { $$.position = position; $$.width = 0; $$.base = 0; } X ; Xtype3 : whites EMPTY whites oempties otype3e X { X $$.base = -($1.width + $3.width + 2) * 15 + X $5.base; X $$.width = $1.width + $2.width + $3.width X + $4.width + $5.width; X $$.position = $5.position; X } X | blacks EMPTY blacks oempties otype3e X { X $$.base = ($1.width + $3.width + 2) * 15 + X $5.base; X $$.width = $1.width + $2.width + $3.width X + $4.width + $5.width; X $$.position = $5.position; X } X | type3e X ; Xtype3e : whites blacks type2 X { X $$.base = -15 * ($1.width + $2.width + 1); X $$.width = $1.width + $2.width + $3.width; X $$.position = $3.position; X } X | blacks whites type1 X { X $$.base = 15 * ($1.width + $2.width + 1); X $$.width = $1.width + $2.width + $3.width; X $$.position = $3.position; X } X | whites empties otype3e X { X if ($1.position - $1.width == 1) { X switch ($1.width) { X case 1: X $$.base = -30; X break; X case 6: X $$.base = -20; X break; X case 2: X $$.base = -15; X break; X case 3: X $$.base = -10; X break; X case 4: X $$.base = -5; X break; X case 5: X $$.base = 10; X break; X default: X yyerror ("weirdo"); X break; X } X } else { X $$.base = $1.base; X } X $$.base += $3.base; X $$.position = $3.position; X $$.width = $1.width + $2.width + $3.width; X } X | blacks empties otype3e X { X if ($1.position - $1.width == 1) { X switch ($1.width) { X case 1: X $$.base = 30; X break; X case 6: X $$.base = 20; X break; X case 2: X $$.base = 15; X break; X case 3: X $$.base = 10; X break; X case 4: X $$.base = 5; X break; X case 5: X $$.base = -10; X break; X default: X yyerror ("weirdo"); X break; X } X } else { X $$.base = $1.base; X } X $$.base += $3.base; X $$.position = $3.position; X $$.width = $1.width + $2.width + $3.width; X } X | whites X { X $$.base = 20 * $1.width; X $$.position = $1.position; X $$.width = $1.width; X } X | blacks X { X $$.base = -20 * $1.width; X $$.position = $1.position; X $$.width = $1.width; X } X ; Xtype4 : whites EMPTY whites oempties otype4 X { X if ($4.position == 8) { X $$.base = -($1.width + $3.width + 2) * 15; X } else { X $$.base = 0; X if ($1.position - $1.width + 1 == 3) X $$.base = $1.width * 15; X else X $$.base = $1.base; X if ($3.position == 6) X $$.base += $3.width * 15; X else X $$.base += $3.base; X $$.base += $5.base; X } X $$.width = $1.width + $2.width + $3.width X + $4.width + $5.width; X $$.position = $5.position; X } X | whites empties otype4 X { X if ($1.position - $1.width + 1 == 3) X $$.base = $1.width * 15 + $3.base; X else if ($1.position == 6) X $$.base = $1.width * 15 + $3.base; X else X $$.base = $1.base + $3.base; X $$.position = $3.position; X $$.width = $1.width + $2.width + $3.width; X } X | blacks EMPTY blacks oempties otype4 X { X if ($4.position == 8) { X $$.base = ($1.width + $3.width + 2) * 15; X } else { X $$.base = 0; X if ($1.position - $1.width + 1 == 3) X $$.base = -$1.width * 15; X else X $$.base = $1.base; X if ($3.position == 6) X $$.base += -$3.width * 15; X else X $$.base += $3.base; X $$.base += $5.base; X } X $$.width = $1.width + $2.width + $3.width X + $4.width + $5.width; X $$.position = $5.position; X } X | blacks empties otype4 X { X if ($1.position - $1.width + 1 == 3) X $$.base = -$1.width * 15 + $3.base; X else if ($1.position == 6) X $$.base = -$1.width * 15 + $3.base; X else X $$.base = $1.base + $3.base; X $$.position = $3.position; X $$.width = $1.width + $2.width + $3.width; X } X | whites X { X $$.base = 20 * $1.width; X $$.position = $1.position; X $$.width = $1.width; X } X | blacks X { X $$.base = -20 * $1.width; X $$.position = $1.position; X $$.width = $1.width; X } X | type4.w X { $$ = $1; } X | type4.b X { $$ = $1; } X ; Xtype4.w : whites blacks oempties otype4 X { X if ($2.position == 8) X $$.base = - ($1.width + $2.width + 1) * 15; X else if ($3.position == 8 && $3.width == 1) X $$.base = ($1.width + $2.width + 1) * 10; X else X $$.base = $1.base + $2.base + $4.base; X $$.position = $4.position; X $$.width = $1.width + $2.width + $3.width + $4.width; X } X ; Xtype4.b : blacks whites oempties otype4 X { X if ($2.position == 8) X $$.base = ($1.width + $2.width + 1) * 15; X else if ($3.position == 8 && $3.width == 1) X $$.base = - ($1.width + $2.width + 1) * 10; X else X $$.base = $1.base + $2.base + $4.base; X $$.position = $4.position; X $$.width = $1.width + $2.width + $3.width + $4.width; X } X ; Xoempties: empties X { $$ = $1; } X | X { $$.position = position; $$.width = 0; $$.base = 0; } X ; X%% X X# include <stdio.h> X Xmain () X{ X return yyparse (); X} X Xchar line[80]; Xchar *lp = line; X Xyyerror (s) Xchar *s; X{ X fprintf (stderr, "%s in %s\n", s, line); X} X Xyywrap () X{ X return 1; X} X Xint position = 1; X Xint base[] = { 0, 20, -30, 15, -5, -5, 15, -30, 20, 0 }; X Xyylex () X{ X char *gets(); X X if (*lp == '\0') X if (fgets (line, 80, stdin) == 0) X return -1; X else X lp = line; X for (;;) { X switch (*lp++) { X case ' ': X case '\t': X break; X case '\n': X lp[-1] = '\0'; X position = 1; X return NL; X case 'O': X yylval.field.base = - X base[yylval.field.position = position++]; X yylval.field.width = 1; X return BLACK; X case '*': X yylval.field.base = X base[yylval.field.position = position++]; X yylval.field.width = 1; X return WHITE; X case '-': X yylval.field.base = 0; X yylval.field.position = position++; X yylval.field.width = 1; X return EMPTY; X } X } X} EOF_OF_makeedge.y echo extracting 'makefile' sed 's/^X//' << \EOF_OF_makefile >makefile XCFLAGS=-O -i XOFILES=user.o ulex.o move.o display.o hasmove.o fini.o \ X minmax.o score.o edges.o corners.o count.o XSOURCE= makefile corners.c count.c display.c edges.c fini.c genedge.c \ X hasmove.c makeedge.y minmax.c move.c reversi.h score.c ulex.l user.y X Xreversi: $(OFILES) X cc $(CFLAGS) -o reversi $(OFILES) -lcurses -ltermlib X Xreversi.shar: $(SOURCE) X shar -c $(SOURCE) > reversi.shar X X$(OFILES): reversi.h Xuser.o: user.c Xuser.c: user.y X yacc -dv user.y X mv y.tab.c user.c Xulex.o: ulex.c Xulex.c: ulex.l X lex ulex.l X mv lex.yy.c ulex.c Xcorners.o: corners.c X $(CC) $(CFLAGS) -R -c corners.c X Xedges.o: edges.c edges.out X $(CC) $(CFLAGS) -R -c edges.c Xedges.out: makeedge genedge X genedge | makeedge > edges.out Xmakeedge: makeedge.o X $(CC) $(CFLAGS) -o makeedge makeedge.o Xmakeedge.o: makeedge.c Xmakeedge.c: makeedge.y X yacc makeedge.y X mv y.tab.c makeedge.c Xgenedge: genedge.o X $(CC) $(CFLAGS) -o genedge genedge.o Xgenedge.o: genedge.c EOF_OF_makefile echo extracting 'minmax.c' sed 's/^X//' << \EOF_OF_minmax.c >minmax.c X/* X * minmax.c X */ X X# include "reversi.h" X Xint maxlev, movex, movey; X X/* X * this defines the order in which the board X * is searched for the best move. It is X * here to shorten the time to best move, X * this increasing the chance of hitting X * a good trimming point as well as X * increasing the possibility of making X * a reasonable move when an interrupt is X * caught. X */ Xshort morder[64][2] = { X 1,1, 1,8, 8,1, 8,8, X 1,3, 1,6, 3,1, 3,8, 6,1, 6,8, 8,3, 8,6, X 3,3, 3,6, 6,3, 6,6, X 1,4, 1,5, 4,1, 4,8, 5,1, 5,8, 8,4, 8,5, X 3,4, 3,5, 4,3, 4,6, 5,3, 5,6, 6,4, 6,5, X 2,3, 2,6, 3,2, 3,7, 6,2, 6,7, 7,3, 7,6, X 2,4, 2,5, 4,2, 4,7, 5,2, 5,7, 7,4, 7,5, X 1,2, 1,7, 2,1, 2,8, 7,1, 7,8, 8,2, 8,7, X 2,2, 2,7, 7,2, 7,7, 4,4, 4,5, 5,4, 5,5, X}; X X# define NOMOVE (-32760) X X X# define USECOPY X# ifdef USECOPY Xstruct copyB { X boardT data; X}; X# define copyb(next,board) (*((struct copyB *)next) = *((struct copyB *) board)) X# else X# define copyb(next,board) copy(next,board) X# endif X Xcopy(next, board) Xregister int *next, *board; X{ X register int count; X X count = sizeof (boardT) / sizeof (int); X do { X *next++ = *board++; X } while (--count); X} X Xcomputer (player, board, level) XboardT board; X{ X int i; X extern int com, defcom; X X maxlev = level; X movex = movey = -1; X i = seek (player, board, 0, 1, -NOMOVE); X if (movex == -1 || movey == -1) X return 0; X move (player, movex, movey, board); X return 1; X} X Xhint (player, board, level) XboardT board; X{ X int i; X X maxlev = level; X i = seek (player, board, 0, 1, -NOMOVE); X if (movex == -1 || movey == -1) X return 0; X return 1; X} X Xseek (player, board, level, moved, best) Xregister player; Xregister boardT board; X{ X boardT next; X register int x, y; X register int s; X int max, i; X int bestx, besty; X int m, j; X extern int gotsignal; X X max = NOMOVE; X m = 0; X for (j = 0; j < 60; j++) { X x = morder[j][0]; X y = morder[j][1]; X if (gotsignal) X return 0; X if (legal (player, x, y, board)) { X copyb (next, board); X if (level == 0 && movex == -1) { X movex = x; X movey = y; X } X move (player, x, y, next); X ++m; X if (level >= maxlev) X s = score (next, player); X else X s = seek (-player, next, level+1, 1, -max); X if (s >= max) { X /* X * try to make the game appear random X * by choosing among equal moves X * randomly X */ X if (s == max && rand()&01) X goto skip; X if (s > best) X return -s; X bestx = x; X besty = y; X if (level == 0) { X movex = bestx; X movey = besty; X } X max = s; X } Xskip: ; X } X } X if (m == 0) X if (moved && level) X return seek (-player, board, level + 1, 0, -best); X else X return - count (player, board) * 500; X return -max; X} EOF_OF_minmax.c echo extracting 'move.c' sed 's/^X//' << \EOF_OF_move.c >move.c X/* X * move.c X * X * move player to x,y in board X */ X X# include "reversi.h" X Xint offsets[] = { -11, -10, -9, -1, 1, 9, 10, 11, 0 }; X Xmove (player, x, y, board) Xregister int player; Xint x, y; XboardT board; X{ X register char *b, *m; X register int *o, i; X X b = & board[x][y]; X *b = player; X player = -player; X for (o = offsets; i = *o++;) { X if (b[i] == player) { X m = b+i; X while (*m == player) X m += i; X if (*m == -player) { X while (m != b) { X *m = -player; X m -= i; X } X } X } X } X} X Xlegal (player, x, y, board) Xregister int player; Xint x, y; XboardT board; X{ X register char *b, *m; X register int *o, i; X X b = & board[x][y]; X player = -player; X if (*b == EMPTY) { X for (o = offsets; i = *o++;) { X if (b[i] == player) { X m = b+i; X while (*m == player) X m += i; X if (*m == -player) X return 1; X } X } X } X return 0; X} EOF_OF_move.c echo extracting 'reversi.h' sed 's/^X//' << \EOF_OF_reversi.h >reversi.h X/* X * reversi.h X * X * include file for game program X */ X X# define SIZE 8 X Xtypedef char boardT[SIZE+2][SIZE+2]; X Xtypedef boardT *boardP; X X# define EMPTY 0 X# define WHITE 1 X# define BLACK -1 EOF_OF_reversi.h echo extracting 'score.c' sed 's/^X//' << \EOF_OF_score.c >score.c X/* X * score.c X * X * score a board position X */ X X# include "reversi.h" X#ifdef SDEBUG Xextern int sdebug; X#endif X XboardT base = { X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, -40, -10, -5, -5, -10, -40, 0, 0, X 0, 0, -10, 3, 1, 1, 3, -10, 0, 0, X 0, 0, -5, 1, 0, 0, 1, -5, 0, 0, X 0, 0, -5, 1, 0, 0, 1, -5, 0, 0, X 0, 0, -10, 3, 1, 1, 3, -10, 0, 0, X 0, 0, -40, -10, -5, -5, -10, -40, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X}; X Xshort edgemod[10][3] = { X 0, 0, 0, X 0, 0, 0, X 0, 0, 0, X 5, -10, 5, X 5, -5, 5, X 5, -5, 5, X 5, -10, 5, X 0, 0, 0, X 0, 0, 0, X 0, 0, 0, X}; X Xextern short cornerscores[3][3][3][3]; X Xextern short edgescores[6561]; X X# define edgesc(a,b,c,d,e,f,g,h) edgescores[a*2187 + b*729 + c*243 + \ X d*81 + e*27 + f*9 + g*3 + h + 3280] X Xscore (board, player) Xregister boardT board; Xint player; X{ X register char *j, *b; X char *l; X register int score; X int i; X int n, m; X X#ifdef SDEBUG X if (sdebug) { X display (board); X } X#endif X score = 0; X for (i = 3; i < SIZE - 1; i++) { X j = & board[i][3]; X b = & base [i][3]; X l = & board[i][SIZE-1]; X while (j != l) { X n = *j++; X score += n * *b++; X } X score += board[2][i] * edgemod[i][board[1][i]+1]; X score += board[SIZE-1][i] * edgemod[i][board[SIZE][i]+1]; X score += board[i][2] * edgemod[i][board[i][1]+1]; X score += board[i][SIZE-1] * edgemod[i][board[i][SIZE]+1]; X } X score += X cornerscores[board[1][1] + 1] X [board[1][2] + 1] X [board[2][1] + 1] X [board[2][2] + 1] + X cornerscores[board[1][8] + 1] X [board[1][7] + 1] X [board[2][8] + 1] X [board[2][7] + 1] + X cornerscores[board[8][1] + 1] X [board[8][2] + 1] X [board[7][1] + 1] X [board[7][2] + 1] + X cornerscores[board[8][8] + 1] X [board[8][7] + 1] X [board[7][8] + 1] X [board[7][7] + 1]; X score += edgesc (board[1][1], board[1][2], board[1][3], board[1][4], X board[1][5], board[1][6], board[1][7], board[1][8]) + X edgesc (board[8][1], board[8][2], board[8][3], board[8][4], X board[8][5], board[8][6], board[8][7], board[8][8]); X score += edgesc (board[1][1], board[2][1], board[3][1], board[4][1], X board[5][1], board[6][1], board[7][1], board[8][1]) + X edgesc (board[1][8], board[2][8], board[3][8], board[4][8], X board[5][8], board[6][8], board[7][8], board[8][8]); X#ifdef SDEBUG X if (sdebug) X printf ("score: %d\n", score); X#endif X return score * player; X} EOF_OF_score.c echo extracting 'ulex.l' sed 's/^X//' << \EOF_OF_ulex.l >ulex.l X%{ X/* X * ex:set ts=8 sw=8: X */ X# include "y.tab.h" Xextern int yylval; Xextern char sbuf[]; X#undef input X#define input() lexgetc() X#undef unput X#define unput(c) lexungetc(c) X%} X%% X[ \t] ; X\004 return EOG; Xblack { yylval = -1; return BL; } Xboth return BOTH; Xcomputer return COMPUTER; Xdebug return DEBUG; Xeval return EVAL; Xfile return FILEe; Xfirst return FIRST; Xfrom return FROM; Xgame return GAME; Xgrid return GRID; Xhelp return HELP; Xhint return HINT; Xhuman return HUMAN; Xinto return INTO; Xlevel return LEVEL; Xme return HUMAN; Xmove return MOVE; Xnew return NEW; Xneither return NEITHER; Xno return NO; Xnogrid return NOGRID; Xnohelp return NOHELP; Xnoscore return NOSCORE; Xnone return NONE; Xplay return PLAY; Xquit return QUIT; Xrecord return RECORD; Xreplay return REPLAY; Xrestart return RESTART; Xsave return SAVE; Xscore return SCORE; Xsecond return SECOND; Xto return TO; Xundo return UNDO; Xwhite { yylval = 1; return WH; } Xyou return COMPUTER; X\n return NL; X[0-9]+ { yylval = atoi (yytext); return NUMBER; } X"," return COMMA; X";" return SEMI; X\"[^"]*\" { strcpy (sbuf, yytext+1); sbuf[yyleng-2]='\0'; return STRING; } X. return ERR; EOF_OF_ulex.l echo extracting 'user.y' sed 's/^X//' << \EOF_OF_user.y >user.y X%{ X/* X * ex:set ts=8 sw=8: X * user interface X */ X X# include "reversi.h" X# include <stdio.h> X# include <signal.h> X XboardT board, saveBoard; Xint saved; Xint savePlayer; Xint atend; Xint atbegin; Xint level; Xint player; Xextern int maxlev, movex, movey; Xint com; Xint gotsignal; Xchar sbuf[80]; Xchar ebuf[80]; Xint sdebug = 0, mdebug = 0; Xint record = 0; XFILE *rfile; Xint first = WHITE; Xint defcom = BLACK; Xint showScore = 1; X Xstruct move { X int p, x, y; X}; X Xstruct move saveGame[64]; Xstruct move *saveP; X X%} X%token MOVE LEVEL COMPUTER UNDO HINT PLAY X%token RECORD REPLAY SAVE X%token RESTART NEW GAME QUIT X%token GRID NOGRID HELP NOHELP SCORE NOSCORE X%token DEBUG EVAL X%token FROM INTO TO FILEe NO X%token NUMBER COMMA NL STRING SEMI EOG ERR X%token WH BL HUMAN BOTH NEITHER NONE FIRST SECOND X%% Xgame : game commands NL prompt X | prompt X ; Xprompt : X { X if (!atend) { X loop: ; X dispTurn (player); X if (!hasmove (player, board)) { X if (!hasmove (-player, board)) { X fini (board); X if (com == 0) X com = BLACK; X ++atend; X dispTurn (EMPTY); X goto nomove; X } else { X if (player == WHITE) X dispError ("white has no move"); X else X dispError ("black has no move"); X player = -player; X } X } X if (com == 0 || com == player) { X dispError ("thinking..."); X if (computer (player, board, level)) { X atbegin = 0; X sprintf (ebuf, "I move to %d, %d\n", X movex, movey); X dispError (ebuf); X saveP->x = movex; X saveP->y = movey; X saveP->p = player; X ++saveP; X if (record) X fprintf (rfile, "%d: %d,%d\n", X player, movex, movey); X player = -player; X display (board); X if (gotsignal && com != 0) X gotsignal = 0; X } X if (gotsignal && com == 0) { X com = -player; X gotsignal = 0; X } X goto loop; X } X } X nomove: ; X readLine (); X } X ; Xcommands: commands SEMI command X | command X | error oerror X { X dispHelp (); X } X ; Xcommand : X | EOG X { X YYACCEPT; X } X | omove NUMBER ocomma NUMBER X { X if (1 <= $2 && $2 <= SIZE && X 1 <= $4 && $4 <= SIZE && X legal (player, $2, $4, board)) { X copy (saveBoard, board); X savePlayer = player; X ++saved; X move (player, $2, $4, board); X atbegin = 0; X if (record) X fprintf (rfile, "%d: %d,%d\n", X player, $2, $4); X saveP->x = $2; X saveP->y = $4; X saveP->p = player; X ++saveP; X player = -player; X display (board); X } else { X sprintf (ebuf, "illegal move: %d, %d", $2, $4); X dispError (ebuf); X } X } X | DEBUG STRING X { X register char *s; X register int v; X X v = 1; X for (s = sbuf; *s; ++s) X switch (*s) { X case 'm': X mdebug = v; X break; X case 's': X sdebug = v; X break; X case '!': X v = !v; X break; X } X } X | GRID X { X dispGrid (); X } X | NO GRID X { X dispNoGrid (); X } X | NOGRID X { X dispNoGrid (); X } X | SCORE X { X showScore = 1; X dispScore (board); X } X | NOSCORE X { X showScore = 0; X dispNoScore (); X } X | NO SCORE X { X showScore = 0; X dispNoScore (); X } X | LEVEL NUMBER X { X level = $2; X } X | LEVEL oerror X { X sprintf (ebuf, "current level is %d", level); X dispError (ebuf); X } X | PLAY whichp X { X if ($2 == WHITE || $2 == BLACK) X defcom = $2; X com = $2; X } X | PLAY oerror X { X dispError ("play (white black both none)"); X } X | whichp FIRST X { X if ($1 == WHITE || $1 == BLACK) X first = $1; X if (atbegin) X player = first; X } X | FIRST oerror X { X dispError ("(white black you me) first"); X } X | whichp SECOND X { X if ($1 == WHITE || $1 == BLACK) X first = - $1; X if (atbegin) X player = first; X } X | SECOND oerror X { X dispError ("(white black you me) second"); X } X | HELP X { X dispHelp (); X } X | NOHELP X { X dispNoHelp (); X } X | NO HELP X { X dispNoHelp (); X } X | QUIT X { X YYACCEPT; X } X | UNDO X { X if (saved) { X copy (board, saveBoard); X player = savePlayer; X saved = 0; X display (board); X } X } X | NEW ogame eoc X { X YYABORT; X } X | RESTART eoc X { X YYABORT; X } X | EVAL X { X sprintf (ebuf, "score: %d\n", score (board, WHITE)); X dispError (ebuf); X } X | RECORD ointo ofile STRING X { X if ((rfile = fopen (sbuf, "w")) == NULL) { X sprintf (ebuf, "could not open %s", sbuf); X dispError (ebuf); X record = 0; X } else X ++record; X } X | RECORD oerror X { X dispError ("record \"file\""); X } X | REPLAY whichp ofrom ofile STRING X { X replay ($2, sbuf); X } X | REPLAY oerror X { X dispError ("replay (both white black) \"file\""); X } X | SAVE ointo ofile STRING X { X struct move *m; X X if ((rfile = fopen (sbuf, "w")) == NULL) { X sprintf (ebuf, "could not open %s", sbuf); X dispError (ebuf); X } else { X m = saveGame; X fprintf (rfile, "%d: -1,-1\n", m->p); X for (; m != saveP; m++) X fprintf (rfile, "%d: %d,%d\n", X m->p, m->x, m->y); X fclose (rfile); X rfile = 0; X } X } X | SAVE oerror X { X dispError ("save \"file\""); X } X | HINT X { X if (hasmove (player, board)) { X char buf[80]; X hint (player, board, level); X sprintf (buf, "I suggest %d, %d", movex, movey); X dispError (buf); X } X } X ; Xeoc : SEMI X | NL X ; Xomove : MOVE X | X ; Xogame : GAME X | X ; Xocomma : COMMA X | X ; Xoerror : oerror error X { X yyerrok; X } X | oerror ERR X | X ; Xointo : TO X | INTO X | X ; Xofrom : FROM X | X ; Xofile : FILEe X | X ; Xwhichp : WH X { $$ = WHITE; } X | BL X { $$ = BLACK; } X | COMPUTER X { $$ = com==WHITE?WHITE:BLACK; } X | HUMAN X { $$ = com==WHITE?BLACK:WHITE; } X | BOTH X { $$ = 0; } X | none X { $$ = 2; } X ; Xnone : NONE X | NEITHER X ; X%% Xyyerror (s) Xchar *s; X{ X dispError (s); X} X Xcaught () X{ X gotsignal++; X signal (SIGINT, caught); X} X Xmain (argc, argv) Xchar **argv; X{ X signal (SIGINT, caught); X level = 2; X dispInit (); X srand (getpid()); X while (**++argv == '-') { X while (*++*argv) { X switch (**argv) { X case 'b': X defcom = BLACK; X break; X case 'w': X defcom = WHITE; X break; X case '1': X if (!*++*argv) X continue; X if (**argv == WHITE) X first = WHITE; X else X first = BLACK; X break; X case 'g': X dispGrid (); X break; X case 's': X showScore = 1; X } X } X } X do { X if (rfile) X fclose (rfile); X rfile = 0; X player = first; X com = defcom; X atend = 0; X atbegin = 1; X setup (); X saved = 0; X saveP = saveGame; X display (board); X if (*argv) { X replay (0, *argv); X ++argv; X } X } while (yyparse ()); X dispEnd (); X} X Xyywrap () X{ X return 1; X} X Xsetup () X{ X register int i,j; X X for (i = 1; i <= SIZE; i++) X for (j = 1; j <= SIZE; j++) X board[i][j] = 0; X board[4][4] = WHITE; X board[4][5] = BLACK; X board[5][4] = BLACK; X board[5][5] = WHITE; X} X Xreplay (who, file) Xchar *file; X{ X int x, y, p; X if (rfile) X fclose (rfile); X if ((rfile = fopen (file, "r")) == NULL) { X sprintf (ebuf, "could not open %s", file); X dispError (ebuf); X return; X } X while (fscanf (rfile, "%d: %d, %d\n", &p, &x, &y) == 3) { X if (x == -1 && y == -1) { X player = p; X continue; X } X if (!hasmove (player, board)) { X player = -player; X if (!hasmove (player, board)) X return; X } X if (p != player) { X sprintf (ebuf, "not %s's turn\n", X player == WHITE? "white":"black"); X dispError (ebuf); X return; X } X if (who == 0 || p == who) { X if (!legal (p, x, y, board)) { X sprintf(ebuf, "illegal move: %d, %d\n", x, y); X dispError (ebuf); X return; X } X move (p, x, y, board); X atbegin = 0; X player = -player; X display (board); X } X else if (player == com) { X if (hasmove (player, board)) { X dispError ("thinking..."); X dispTurn (EMPTY); X if (computer (player, board, level)) { X dispError (""); X atbegin = 0; X player = -player; X display (board); X } X } X } X } X fclose (rfile); X rfile = 0; X} EOF_OF_user.y
deg@mtgzz.UUCP (d.e.gillespie) (07/24/85)
There are some assumptions your code makes about the target machine, in particular in the use of 'char' variables. On many targets, a char is never negative! In your program, the board is stored as a char array, and so far this is the only problem i noticed. The easiest solution was to add this line to reversi.h: typdef short int boardE; The diff listings of the affected files follows: ***** diff between gencor.c.BAK and gencor.c 5c5 < char board[9]; --- > boardE board[9]; ***** diff between genedge.c.BAK and genedge.c 5c5 < char board[9]; --- > boardE board[9]; ***** diff between legal.c.BAK and legal.c 9c9 < register char *b, *m; --- > register boardE *b, *m; ***** diff between move.c.BAK and move.c 16c16 < register char *b, *m; --- > register boardE *b, *m; 42c42 < register char *b, *m; --- > register boardE *b, *m; ***** diff between reversi.h.BAK and reversi.h 8,9c8,9 < < typedef short int boardT[SIZE+2][SIZE+2]; --- > typedef short int boardE; > typedef boardE boardT[SIZE+2][SIZE+2]; ***** diff between score.c.BAK and score.c 49,50c49,50 < register char *j, *b; < char *l; --- > register boardE *j, *b; > boardE *l;