740 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			740 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* gomoku - 5 in a row game		Author: ? */
 | 
						|
 | 
						|
/* This program plays a very old Japanese game called GO-MOKU,
 | 
						|
   perhaps better known as  5-in-line.   The game is played on
 | 
						|
   a board with 19 x 19 squares, and the object of the game is
 | 
						|
   to get 5 stones in a row.
 | 
						|
*/
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <curses.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <unistd.h>
 | 
						|
 | 
						|
/* Size of the board */
 | 
						|
#define SIZE 19
 | 
						|
 | 
						|
/* Importance of attack (1..16) */
 | 
						|
#define AttackFactor 4
 | 
						|
 | 
						|
/* Value of having 0, 1,2,3,4 or 5 pieces in line */
 | 
						|
int Weight[7] = {0, 0, 4, 20, 100, 500, 0};
 | 
						|
 | 
						|
#define Null 0
 | 
						|
#define Horiz 1
 | 
						|
#define DownLeft 2
 | 
						|
#define DownRight 3
 | 
						|
#define Vert 4
 | 
						|
 | 
						|
/* The two players */
 | 
						|
#define Empty 0
 | 
						|
#define Cross 1
 | 
						|
#define Nought 2
 | 
						|
 | 
						|
char PieceChar[Nought + 1] = {' ', 'X', '0'};
 | 
						|
 | 
						|
int Board[SIZE + 1][SIZE + 1];/* The board */
 | 
						|
int Player;			/* The player whose move is next */
 | 
						|
int TotalLines;			/* The number of Empty lines left */
 | 
						|
int GameWon;			/* Set if one of the players has won */
 | 
						|
 | 
						|
int Line[4][SIZE + 1][SIZE + 1][Nought + 1];
 | 
						|
 | 
						|
/* Value of each square for each player */
 | 
						|
int Value[SIZE + 1][SIZE + 1][Nought + 1];
 | 
						|
 | 
						|
int X, Y;			/* Move coordinates */
 | 
						|
char Command;			/* Command from keyboard */
 | 
						|
int AutoPlay = FALSE;		/* The program plays against itself */
 | 
						|
 | 
						|
_PROTOTYPE(void Initialize, (void));
 | 
						|
_PROTOTYPE(int Abort, (char *s));
 | 
						|
_PROTOTYPE(void WriteLetters, (void));
 | 
						|
_PROTOTYPE(void WriteLine, (int j, int *s));
 | 
						|
_PROTOTYPE(void WriteBoard, (int N, int *Top, int *Middle, int *Bottom));
 | 
						|
_PROTOTYPE(void SetUpScreen, (void));
 | 
						|
_PROTOTYPE(void GotoSquare, (int x, int y));
 | 
						|
_PROTOTYPE(void PrintMove, (int Piece, int X, int Y));
 | 
						|
_PROTOTYPE(void ClearMove, (void));
 | 
						|
_PROTOTYPE(void PrintMsg, (char *Str));
 | 
						|
_PROTOTYPE(void ClearMsg, (void));
 | 
						|
_PROTOTYPE(void WriteCommand, (char *S));
 | 
						|
_PROTOTYPE(void ResetGame, (int FirstGame));
 | 
						|
_PROTOTYPE(int OpponentColor, (int Player));
 | 
						|
_PROTOTYPE(void BlinkRow, (int X, int Y, int Dx, int Dy, int Piece));
 | 
						|
_PROTOTYPE(void BlinkWinner, (int Piece, int X, int Y, int WinningLine));
 | 
						|
_PROTOTYPE(int Random, (int x));
 | 
						|
_PROTOTYPE(void Add, (int *Num));
 | 
						|
_PROTOTYPE(void Update, (int Lin[], int Valu[], int Opponent));
 | 
						|
_PROTOTYPE(void MakeMove, (int X, int Y));
 | 
						|
_PROTOTYPE(int GameOver, (void));
 | 
						|
_PROTOTYPE(void FindMove, (int *X, int *Y));
 | 
						|
_PROTOTYPE(char GetChar, (void));
 | 
						|
_PROTOTYPE(void ReadCommand, (int X, int Y, char *Command));
 | 
						|
_PROTOTYPE(void InterpretCommand, (int Command));
 | 
						|
_PROTOTYPE(void PlayerMove, (void));
 | 
						|
_PROTOTYPE(void ProgramMove, (void));
 | 
						|
_PROTOTYPE(int main, (void));
 | 
						|
 | 
						|
/* Set terminal to raw mode. */
 | 
						|
void Initialize()
 | 
						|
{
 | 
						|
  srand(getpid() + 13);		/* Initialize the random seed with our pid */
 | 
						|
  initscr();
 | 
						|
  raw();
 | 
						|
  noecho();
 | 
						|
  clear();
 | 
						|
}
 | 
						|
 | 
						|
/* Reset terminal and exit from the program. */
 | 
						|
int Abort(s)
 | 
						|
char *s;
 | 
						|
{
 | 
						|
  move(LINES - 1, 0);
 | 
						|
  refresh();
 | 
						|
  endwin();
 | 
						|
  exit(0);
 | 
						|
}
 | 
						|
 | 
						|
/* Set up the screen ----------------------------------------------- */
 | 
						|
 | 
						|
/* Write the letters */
 | 
						|
void WriteLetters()
 | 
						|
{
 | 
						|
  int i;
 | 
						|
 | 
						|
  addch(' ');
 | 
						|
  addch(' ');
 | 
						|
  for (i = 1; i <= SIZE; i++) printw(" %c", 'A' + i - 1);
 | 
						|
  addch('\n');
 | 
						|
}
 | 
						|
 | 
						|
/* Write one line of the board */
 | 
						|
void WriteLine(j, s)
 | 
						|
int j;
 | 
						|
int *s;
 | 
						|
{
 | 
						|
  int i;
 | 
						|
 | 
						|
  printw("%2d ", j);
 | 
						|
  addch(s[0]);
 | 
						|
  for (i = 2; i <= SIZE - 1; i++) {
 | 
						|
	addch(s[1]);
 | 
						|
	addch(s[2]);
 | 
						|
  }
 | 
						|
  addch(s[1]);
 | 
						|
  addch(s[3]);
 | 
						|
  printw(" %-2d\n", j);
 | 
						|
}
 | 
						|
 | 
						|
/* Print the Empty board and the border */
 | 
						|
void WriteBoard(N, Top, Middle, Bottom)
 | 
						|
int N;
 | 
						|
int *Top, *Middle, *Bottom;
 | 
						|
{
 | 
						|
  int j;
 | 
						|
 | 
						|
  move(1, 0);
 | 
						|
  WriteLetters();
 | 
						|
  WriteLine(N, Top);
 | 
						|
  for (j = N - 1; j >= 2; j--) WriteLine(j, Middle);
 | 
						|
  WriteLine(1, Bottom);
 | 
						|
  WriteLetters();
 | 
						|
}
 | 
						|
 | 
						|
/* Sets up the screen with an Empty board */
 | 
						|
void SetUpScreen()
 | 
						|
{
 | 
						|
  int top[4], middle[4], bottom[4];
 | 
						|
 | 
						|
  top[0] = ACS_ULCORNER;
 | 
						|
  top[1] = ACS_HLINE;
 | 
						|
  top[2] = ACS_TTEE;
 | 
						|
  top[3] = ACS_URCORNER;
 | 
						|
 | 
						|
  middle[0] = ACS_LTEE;
 | 
						|
  middle[1] = ACS_HLINE;
 | 
						|
  middle[2] = ACS_PLUS;
 | 
						|
  middle[3] = ACS_RTEE;
 | 
						|
 | 
						|
  bottom[0] = ACS_LLCORNER;
 | 
						|
  bottom[1] = ACS_HLINE;
 | 
						|
  bottom[2] = ACS_BTEE;
 | 
						|
  bottom[3] = ACS_LRCORNER;
 | 
						|
 | 
						|
  WriteBoard(SIZE, top, middle, bottom);
 | 
						|
}
 | 
						|
 | 
						|
/* Show moves ----------------------------------------------- */
 | 
						|
 | 
						|
void GotoSquare(x, y)
 | 
						|
int x, y;
 | 
						|
{
 | 
						|
  move(SIZE + 2 - y, 1 + x * 2);
 | 
						|
}
 | 
						|
 | 
						|
/* Prints a move */
 | 
						|
void PrintMove(Piece, X, Y)
 | 
						|
int Piece;
 | 
						|
int X, Y;
 | 
						|
{
 | 
						|
  move(22, 49);
 | 
						|
  printw("%c %c %d", PieceChar[Piece], 'A' + X - 1, Y);
 | 
						|
  clrtoeol();
 | 
						|
  GotoSquare(X, Y);
 | 
						|
  addch(PieceChar[Piece]);
 | 
						|
  GotoSquare(X, Y);
 | 
						|
  refresh();
 | 
						|
}
 | 
						|
 | 
						|
/* Clears the line where a move is displayed */
 | 
						|
void ClearMove()
 | 
						|
{
 | 
						|
  move(22, 49);
 | 
						|
  clrtoeol();
 | 
						|
}
 | 
						|
 | 
						|
/* Message handling ---------------------------------------------- */
 | 
						|
 | 
						|
/* Prints a message */
 | 
						|
void PrintMsg(Str)
 | 
						|
char *Str;
 | 
						|
{
 | 
						|
  mvprintw(23, 1, "%s", Str);
 | 
						|
}
 | 
						|
 | 
						|
/* Clears the message about the winner */
 | 
						|
void ClearMsg()
 | 
						|
{
 | 
						|
  move(23, 1);
 | 
						|
  clrtoeol();
 | 
						|
}
 | 
						|
 | 
						|
/* Highlights the first letter of S */
 | 
						|
void WriteCommand(S)
 | 
						|
char *S;
 | 
						|
{
 | 
						|
  standout();
 | 
						|
  addch(*S);
 | 
						|
  standend();
 | 
						|
  printw("%s", S + 1);
 | 
						|
}
 | 
						|
 | 
						|
/* Display the board ----------------------------------------------- */
 | 
						|
 | 
						|
/* Resets global variables to start a new game */
 | 
						|
void ResetGame(FirstGame)
 | 
						|
int FirstGame;
 | 
						|
{
 | 
						|
  int I, J;
 | 
						|
  int C, D;
 | 
						|
 | 
						|
  SetUpScreen();
 | 
						|
  if (FirstGame) {
 | 
						|
	move(1, 49);
 | 
						|
	addstr("G O M O K U");
 | 
						|
	move(3, 49);
 | 
						|
	WriteCommand("Newgame    ");
 | 
						|
	WriteCommand("Quit ");
 | 
						|
	move(5, 49);
 | 
						|
	WriteCommand("Auto");
 | 
						|
	move(7, 49);
 | 
						|
	WriteCommand("Play");
 | 
						|
	move(9, 49);
 | 
						|
	WriteCommand("Hint");
 | 
						|
	move(14, 60);
 | 
						|
	WriteCommand("Left, ");
 | 
						|
	WriteCommand("Right, ");
 | 
						|
	move(16, 60);
 | 
						|
	WriteCommand("Up, ");
 | 
						|
	WriteCommand("Down");
 | 
						|
	move(18, 60);
 | 
						|
	standout();
 | 
						|
	addstr("SPACE");
 | 
						|
	move(20, 49);
 | 
						|
	WriteCommand(" NOTE: Use Num Lock & arrows");
 | 
						|
	standend();
 | 
						|
	mvaddstr(14, 49, "7  8  9");
 | 
						|
	mvaddch(15, 52, ACS_UARROW);
 | 
						|
	mvaddch(16, 49, '4');
 | 
						|
	addch(ACS_LARROW);
 | 
						|
	mvaddch(16, 54, ACS_RARROW);
 | 
						|
	addch('6');
 | 
						|
	mvaddch(17, 52, ACS_DARROW);
 | 
						|
	mvaddstr(18, 49, "1  2  3");
 | 
						|
	FirstGame = FALSE;
 | 
						|
  } else {
 | 
						|
	ClearMsg();
 | 
						|
	ClearMove();
 | 
						|
  }
 | 
						|
 | 
						|
  /* Clear tables */
 | 
						|
  for (I = 1; I <= SIZE; I++) for (J = 1; J <= SIZE; J++) {
 | 
						|
		Board[I][J] = Empty;
 | 
						|
		for (C = Cross; C <= Nought; C++) {
 | 
						|
			Value[I][J][C] = 0;
 | 
						|
			for (D = 0; D <= 3; D++) Line[D][I][J][C] = 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
  /* Cross starts */
 | 
						|
  Player = Cross;
 | 
						|
  /* Total number of lines */
 | 
						|
  TotalLines = 2 * 2 * (SIZE * (SIZE - 4) + (SIZE - 4) * (SIZE - 4));
 | 
						|
  GameWon = FALSE;
 | 
						|
}
 | 
						|
 | 
						|
int OpponentColor(Player)
 | 
						|
int Player;
 | 
						|
{
 | 
						|
  if (Player == Cross)
 | 
						|
	return Nought;
 | 
						|
  else
 | 
						|
	return Cross;
 | 
						|
}
 | 
						|
 | 
						|
/* Blink the row of 5 stones */
 | 
						|
void BlinkRow(X, Y, Dx, Dy, Piece)
 | 
						|
int X, Y, Dx, Dy, Piece;
 | 
						|
{
 | 
						|
  int I;
 | 
						|
 | 
						|
  attron(A_BLINK);
 | 
						|
  for (I = 1; I <= 5; I++) {
 | 
						|
	GotoSquare(X, Y);
 | 
						|
	addch(PieceChar[Piece]);
 | 
						|
	X = X - Dx;
 | 
						|
	Y = Y - Dy;
 | 
						|
  }
 | 
						|
  attroff(A_BLINK);
 | 
						|
}
 | 
						|
 | 
						|
/* Prints the 5 winning stones in blinking color */
 | 
						|
void BlinkWinner(Piece, X, Y, WinningLine)
 | 
						|
int Piece, X, Y, WinningLine;
 | 
						|
{
 | 
						|
  /* Used to store the position of the winning move */
 | 
						|
  int XHold, YHold;
 | 
						|
  /* Change in X and Y */
 | 
						|
  int Dx, Dy;
 | 
						|
 | 
						|
  /* Display winning move */
 | 
						|
  PrintMove(Piece, X, Y);
 | 
						|
  /* Preserve winning position */
 | 
						|
  XHold = X;
 | 
						|
  YHold = Y;
 | 
						|
  switch (WinningLine) {
 | 
						|
      case Horiz:
 | 
						|
	{
 | 
						|
		Dx = 1;
 | 
						|
		Dy = 0;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
      case DownLeft:
 | 
						|
	{
 | 
						|
		Dx = 1;
 | 
						|
		Dy = 1;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
      case Vert:
 | 
						|
	{
 | 
						|
		Dx = 0;
 | 
						|
		Dy = 1;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
      case DownRight:
 | 
						|
	{
 | 
						|
		Dx = -1;
 | 
						|
		Dy = 1;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
  }
 | 
						|
 | 
						|
  /* Go to topmost, leftmost */
 | 
						|
  while (Board[X + Dx][Y + Dy] != Empty && Board[X + Dx][Y + Dy] == Piece) {
 | 
						|
	X = X + Dx;
 | 
						|
	Y = Y + Dy;
 | 
						|
  }
 | 
						|
  BlinkRow(X, Y, Dx, Dy, Piece);
 | 
						|
  /* Restore winning position */
 | 
						|
  X = XHold;
 | 
						|
  Y = YHold;
 | 
						|
  /* Go back to winning square */
 | 
						|
  GotoSquare(X, Y);
 | 
						|
}
 | 
						|
 | 
						|
/* Functions for playing a game -------------------------------- */
 | 
						|
 | 
						|
int Random(x)
 | 
						|
int x;
 | 
						|
{
 | 
						|
  return((rand() / 19) % x);
 | 
						|
}
 | 
						|
 | 
						|
/* Adds one to the number of pieces in a line */
 | 
						|
void Add(Num)
 | 
						|
int *Num;
 | 
						|
{
 | 
						|
  /* Adds one to the number.     */
 | 
						|
  *Num = *Num + 1;
 | 
						|
  /* If it is the first piece in the line, then the opponent cannot use
 | 
						|
   * it any more.  */
 | 
						|
  if (*Num == 1) TotalLines = TotalLines - 1;
 | 
						|
  /* The game is won if there are 5 in line. */
 | 
						|
  if (*Num == 5) GameWon = TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/* Updates the value of a square for each player, taking into
 | 
						|
   account that player has placed an extra piece in the square.
 | 
						|
   The value of a square in a usable line is Weight[Lin[Player]+1]
 | 
						|
   where Lin[Player] is the number of pieces already placed
 | 
						|
in the line */
 | 
						|
void Update(Lin, Valu, Opponent)
 | 
						|
int Lin[];
 | 
						|
int Valu[];
 | 
						|
int Opponent;
 | 
						|
{
 | 
						|
  /* If the opponent has no pieces in the line, then simply update the
 | 
						|
   * value for player */
 | 
						|
  if (Lin[Opponent] == 0)
 | 
						|
	Valu[Player] += Weight[Lin[Player] + 1] - Weight[Lin[Player]];
 | 
						|
  else
 | 
						|
	/* If it is the first piece in the line, then the line is
 | 
						|
	 * spoiled for the opponent */
 | 
						|
  if (Lin[Player] == 1) Valu[Opponent] -= Weight[Lin[Opponent] + 1];
 | 
						|
}
 | 
						|
 | 
						|
/* Performs the move X,Y for player, and updates the global variables
 | 
						|
(Board, Line, Value, Player, GameWon, TotalLines and the screen) */
 | 
						|
void MakeMove(X, Y)
 | 
						|
int X, Y;
 | 
						|
{
 | 
						|
  int Opponent;
 | 
						|
  int X1, Y1;
 | 
						|
  int K, L, WinningLine;
 | 
						|
 | 
						|
  WinningLine = Null;
 | 
						|
  Opponent = OpponentColor(Player);
 | 
						|
  GameWon = FALSE;
 | 
						|
 | 
						|
  /* Each square of the board is part of 20 different lines. The adds
 | 
						|
   * one to the number of pieces in each of these lines. Then it
 | 
						|
   * updates the value for each of the 5 squares in each of the 20
 | 
						|
   * lines. Finally Board is updated, and the move is printed on the
 | 
						|
   * screen. */
 | 
						|
 | 
						|
  /* Horizontal lines, from left to right */
 | 
						|
  for (K = 0; K <= 4; K++) {
 | 
						|
	X1 = X - K;		/* Calculate starting point */
 | 
						|
	Y1 = Y;
 | 
						|
	if ((1 <= X1) && (X1 <= SIZE - 4)) {	/* Check starting point */
 | 
						|
		Add(&Line[0][X1][Y1][Player]);	/* Add one to line */
 | 
						|
		if (GameWon && (WinningLine == Null))	/* Save winning line */
 | 
						|
			WinningLine = Horiz;
 | 
						|
		for (L = 0; L <= 4; L++)	/* Update value for the
 | 
						|
						 * 5 squares in the line */
 | 
						|
			Update(Line[0][X1][Y1], Value[X1 + L][Y1], Opponent);
 | 
						|
	}
 | 
						|
  }
 | 
						|
 | 
						|
  for (K = 0; K <= 4; K++) {	/* Diagonal lines, from lower left to
 | 
						|
				 * upper right */
 | 
						|
	X1 = X - K;
 | 
						|
	Y1 = Y - K;
 | 
						|
	if ((1 <= X1) && (X1 <= SIZE - 4) &&
 | 
						|
	    (1 <= Y1) && (Y1 <= SIZE - 4)) {
 | 
						|
		Add(&Line[1][X1][Y1][Player]);
 | 
						|
		if (GameWon && (WinningLine == Null))	/* Save winning line */
 | 
						|
			WinningLine = DownLeft;
 | 
						|
		for (L = 0; L <= 4; L++)
 | 
						|
			Update(Line[1][X1][Y1], Value[X1 + L][Y1 + L], Opponent);
 | 
						|
	}
 | 
						|
  }				/* for */
 | 
						|
 | 
						|
  for (K = 0; K <= 4; K++) {	/* Diagonal lines, down right to upper left */
 | 
						|
	X1 = X + K;
 | 
						|
	Y1 = Y - K;
 | 
						|
	if ((5 <= X1) && (X1 <= SIZE) &&
 | 
						|
	    (1 <= Y1) && (Y1 <= SIZE - 4)) {
 | 
						|
		Add(&Line[3][X1][Y1][Player]);
 | 
						|
		if (GameWon && (WinningLine == Null))	/* Save winning line */
 | 
						|
			WinningLine = DownRight;
 | 
						|
		for (L = 0; L <= 4; L++)
 | 
						|
			Update(Line[3][X1][Y1], Value[X1 - L][Y1 + L], Opponent);
 | 
						|
	}
 | 
						|
  }				/* for */
 | 
						|
 | 
						|
  for (K = 0; K <= 4; K++) {	/* Vertical lines, from down to up */
 | 
						|
	X1 = X;
 | 
						|
	Y1 = Y - K;
 | 
						|
	if ((1 <= Y1) && (Y1 <= SIZE - 4)) {
 | 
						|
		Add(&Line[2][X1][Y1][Player]);
 | 
						|
		if (GameWon && (WinningLine == Null))	/* Save winning line */
 | 
						|
			WinningLine = Vert;
 | 
						|
		for (L = 0; L <= 4; L++)
 | 
						|
			Update(Line[2][X1][Y1], Value[X1][Y1 + L], Opponent);
 | 
						|
	}
 | 
						|
  }
 | 
						|
 | 
						|
  Board[X][Y] = Player;		/* Place piece in board */
 | 
						|
  if (GameWon)
 | 
						|
	BlinkWinner(Player, X, Y, WinningLine);
 | 
						|
  else
 | 
						|
	PrintMove(Player, X, Y);/* Print move on screen */
 | 
						|
  Player = Opponent;		/* The opponent is next to move */
 | 
						|
}
 | 
						|
 | 
						|
int GameOver()
 | 
						|
/* A game is over if one of the players have
 | 
						|
won, or if there are no more Empty lines */
 | 
						|
{
 | 
						|
  return(GameWon || (TotalLines <= 0));
 | 
						|
}
 | 
						|
 | 
						|
/* Finds a move X,Y for player, simply by picking the one with the
 | 
						|
highest value */
 | 
						|
void FindMove(X, Y)
 | 
						|
int *X, *Y;
 | 
						|
{
 | 
						|
  int Opponent;
 | 
						|
  int I, J;
 | 
						|
  int Max, Valu;
 | 
						|
 | 
						|
  Opponent = OpponentColor(Player);
 | 
						|
  Max = -10000;
 | 
						|
  /* If no square has a high value then pick the one in the middle */
 | 
						|
  *X = (SIZE + 1) / 2;
 | 
						|
  *Y = (SIZE + 1) / 2;
 | 
						|
  if (Board[*X][*Y] == Empty) Max = 4;
 | 
						|
  /* The evaluation for a square is simply the value of the square for
 | 
						|
   * the player (attack points) plus the value for the opponent
 | 
						|
   * (defense points). Attack is more important than defense, since it
 | 
						|
   * is better to get 5 in line yourself than to prevent the op- ponent
 | 
						|
   * from getting it. */
 | 
						|
 | 
						|
  /* For all Empty squares */
 | 
						|
  for (I = 1; I <= SIZE; I++) for (J = 1; J <= SIZE; J++)
 | 
						|
		if (Board[I][J] == Empty) {
 | 
						|
			/* Calculate evaluation */
 | 
						|
			Valu = Value[I][J][Player] * (16 + AttackFactor) / 16 + Value[I][J][Opponent] + Random(4);
 | 
						|
			/* Pick move with highest value */
 | 
						|
			if (Valu > Max) {
 | 
						|
				*X = I;
 | 
						|
				*Y = J;
 | 
						|
				Max = Valu;
 | 
						|
			}
 | 
						|
		}
 | 
						|
}
 | 
						|
 | 
						|
char GetChar()
 | 
						|
/* Get a character from the keyboard */
 | 
						|
{
 | 
						|
  int c;
 | 
						|
 | 
						|
  c = getch();
 | 
						|
  if (c < 0) abort();
 | 
						|
  if (c == '\033') {	/* arrow key */
 | 
						|
	if ((c = getch()) == '[') {
 | 
						|
		c = getch();
 | 
						|
		switch (c) {
 | 
						|
		case 'A': c = 'U'; break;
 | 
						|
		case 'B': c = 'D'; break;
 | 
						|
		case 'C': c = 'R'; break;
 | 
						|
		case 'D': c = 'L'; break;
 | 
						|
		default:
 | 
						|
			c = '?';
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
		c = '?';
 | 
						|
  }
 | 
						|
  if (islower(c))
 | 
						|
	return toupper(c);
 | 
						|
  else
 | 
						|
	return c;
 | 
						|
}
 | 
						|
 | 
						|
/* Reads in a valid command character */
 | 
						|
void ReadCommand(X, Y, Command)
 | 
						|
int X, Y;
 | 
						|
char *Command;
 | 
						|
{
 | 
						|
  int ValidCommand;
 | 
						|
 | 
						|
  do {
 | 
						|
	ValidCommand = TRUE;
 | 
						|
	GotoSquare(X, Y);	/* Goto square */
 | 
						|
	refresh();
 | 
						|
	*Command = GetChar();	/* Read from keyboard */
 | 
						|
	switch (*Command) {
 | 
						|
	    case '\n':		/* '\n', '\r' or space means place a */
 | 
						|
	    case '\r':
 | 
						|
	    case ' ':
 | 
						|
		*Command = 'E';
 | 
						|
		break;		/* stone at the cursor position  */
 | 
						|
 | 
						|
	    case 'L':
 | 
						|
	    case 'R':
 | 
						|
	    case 'U':
 | 
						|
	    case 'D':
 | 
						|
	    case '7':
 | 
						|
	    case '9':
 | 
						|
	    case '1':
 | 
						|
	    case '3':
 | 
						|
	    case 'N':
 | 
						|
	    case 'Q':
 | 
						|
	    case 'A':
 | 
						|
	    case 'P':
 | 
						|
	    case 'H':
 | 
						|
		break;
 | 
						|
 | 
						|
	    case '8':	*Command = 'U';	break;
 | 
						|
	    case '2':	*Command = 'D';	break;
 | 
						|
	    case '4':	*Command = 'L';	break;
 | 
						|
	    case '6':	*Command = 'R';	break;
 | 
						|
	    default:
 | 
						|
		{
 | 
						|
			if (GameOver())
 | 
						|
				*Command = 'P';
 | 
						|
			else
 | 
						|
				ValidCommand = FALSE;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
  } while (!ValidCommand);
 | 
						|
}
 | 
						|
 | 
						|
void InterpretCommand(Command)
 | 
						|
char Command;
 | 
						|
{
 | 
						|
  int Temp;
 | 
						|
 | 
						|
  switch (Command) {
 | 
						|
      case 'N':{		/* Start new game */
 | 
						|
		ResetGame(FALSE);	/* ResetGame but only redraw
 | 
						|
					 * the board */
 | 
						|
		X = (SIZE + 1) / 2;
 | 
						|
		Y = X;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
      case 'H':
 | 
						|
	FindMove(&X, &Y);
 | 
						|
	break;			/* Give the user a hint */
 | 
						|
      case 'L':
 | 
						|
	X = (X + SIZE - 2) % SIZE + 1;
 | 
						|
	break;			/* Left  */
 | 
						|
      case 'R':
 | 
						|
	X = X % SIZE + 1;
 | 
						|
	break;			/* Right */
 | 
						|
      case 'D':
 | 
						|
	Y = (Y + SIZE - 2) % SIZE + 1;
 | 
						|
	break;			/* Down  */
 | 
						|
      case 'U':
 | 
						|
	Y = Y % SIZE + 1;
 | 
						|
	break;			/* Up    */
 | 
						|
      case '7':{
 | 
						|
		if ((X == 1) || (Y == SIZE)) {	/* Move diagonally    *//* t
 | 
						|
						 * owards upper left */
 | 
						|
			Temp = X;
 | 
						|
			X = Y;
 | 
						|
			Y = Temp;
 | 
						|
		} else {
 | 
						|
			X = X - 1;
 | 
						|
			Y = Y + 1;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	}
 | 
						|
      case '9':{		/* Move diagonally    */
 | 
						|
		if (X == SIZE) {/* toward upper right */
 | 
						|
			X = (SIZE - Y) + 1;
 | 
						|
			Y = 1;
 | 
						|
		} else if (Y == SIZE) {
 | 
						|
			Y = (SIZE - X) + 1;
 | 
						|
			X = 1;
 | 
						|
		} else {
 | 
						|
			X = X + 1;
 | 
						|
			Y = Y + 1;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	}
 | 
						|
      case '1':{		/* Move diagonally   */
 | 
						|
		if (Y == 1) {	/* toward lower left */
 | 
						|
			Y = (SIZE - X) + 1;
 | 
						|
			X = SIZE;
 | 
						|
		} else if (X == 1) {
 | 
						|
			X = (SIZE - Y) + 1;
 | 
						|
			Y = SIZE;
 | 
						|
		} else {
 | 
						|
			X = X - 1;
 | 
						|
			Y = Y - 1;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	}
 | 
						|
      case '3':{		/* Move diagonally    */
 | 
						|
		if ((X == SIZE) || (Y == 1)) {	/* toward lower right */
 | 
						|
			Temp = X;
 | 
						|
			X = Y;
 | 
						|
			Y = Temp;
 | 
						|
		} else {
 | 
						|
			X = X + 1;
 | 
						|
			Y = Y - 1;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	}
 | 
						|
      case 'A':
 | 
						|
	AutoPlay = TRUE;
 | 
						|
	break;			/* Auto play mode */
 | 
						|
  }				/* case */
 | 
						|
}				/* InterpretCommand */
 | 
						|
 | 
						|
void PlayerMove()
 | 
						|
/* Enter and make a move */
 | 
						|
{
 | 
						|
  if (Board[X][Y] == Empty) {
 | 
						|
	MakeMove(X, Y);
 | 
						|
	if (GameWon) PrintMsg("Congratulations, You won!");
 | 
						|
	Command = 'P';
 | 
						|
  }
 | 
						|
  refresh();
 | 
						|
}				/* PlayerMove */
 | 
						|
 | 
						|
void ProgramMove()
 | 
						|
/* Find and perform programs move */
 | 
						|
{
 | 
						|
  do {
 | 
						|
	if (GameOver()) {
 | 
						|
		AutoPlay = FALSE;
 | 
						|
		if ((Command != 'Q') && (!GameWon)) PrintMsg("Tie game!");
 | 
						|
	} else {
 | 
						|
		FindMove(&X, &Y);
 | 
						|
		MakeMove(X, Y);
 | 
						|
		if (GameWon) PrintMsg("I won!");
 | 
						|
	}
 | 
						|
	refresh();
 | 
						|
  } while (AutoPlay);
 | 
						|
}
 | 
						|
 | 
						|
int main()
 | 
						|
{
 | 
						|
  Initialize();
 | 
						|
  ResetGame(TRUE);		/* ResetGame and draw the entire screen */
 | 
						|
  refresh();
 | 
						|
  X = (SIZE + 1) / 2;		/* Set starting position to */
 | 
						|
  Y = X;			/* the middle of the board  */
 | 
						|
  do {
 | 
						|
	ReadCommand(X, Y, &Command);
 | 
						|
	if (GameOver())
 | 
						|
		if (Command != 'Q') Command = 'N';
 | 
						|
	InterpretCommand(Command);
 | 
						|
	if (Command == 'E') PlayerMove();
 | 
						|
	if (Command == 'P' || Command == 'A') ProgramMove();
 | 
						|
  } while (Command != 'Q');
 | 
						|
  Abort("Good bye!");
 | 
						|
  return(0);
 | 
						|
}
 |