300 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/* tic tac toe (noughts and crosses)		Author: Warren Toomey */
 | 
						|
 | 
						|
/* Copyright 1988 by Warren Toomey	wkt@cs.adfa.oz.au[@uunet.uu.net]
 | 
						|
 *
 | 
						|
 * You may freely copy or distribute this code as long as this notice
 | 
						|
 * remains intact.
 | 
						|
 *
 | 
						|
 * You may modify this code, as long as this notice remains intact, and
 | 
						|
 * you add another notice indicating that the code has been modified.
 | 
						|
 *
 | 
						|
 * You may NOT sell this code or in any way profit from this code without
 | 
						|
 * prior agreement from the author.
 | 
						|
 */
 | 
						|
 | 
						|
/* Compile with cc -o tic tic.c -lcurses -ltermcap */
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
#include <time.h>
 | 
						|
 | 
						|
#ifdef CURSES
 | 
						|
#include <curses.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
#ifndef CURSES
 | 
						|
#define printw printf
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  int value;			/* The move returned by the    */
 | 
						|
  int path;			/* alphabeta consists of a value */
 | 
						|
} MOVE;				/* and an actual move (path)   */
 | 
						|
 | 
						|
_PROTOTYPE(int main, (void));
 | 
						|
_PROTOTYPE(int stateval, (int board [], int whosemove));
 | 
						|
_PROTOTYPE(MOVE alphabeta, (int board [], int whosemove, int alpha, int beta));
 | 
						|
_PROTOTYPE(void draw, (int board []));
 | 
						|
_PROTOTYPE(void getmove, (int board []));
 | 
						|
_PROTOTYPE(int endofgame, (int board []));
 | 
						|
_PROTOTYPE(int randommove, (void));
 | 
						|
 | 
						|
 /* Static evaluator. Returns 100 if we have 3 in a row -100 if they have 3
 | 
						|
  * in a row
 | 
						|
  * 
 | 
						|
  * Board is array of 9 ints, where 0=empty square 1=our move 4= their move
 | 
						|
  * 
 | 
						|
  * and board is indices	0 1 2 3 4 5 6 7 8 */
 | 
						|
 | 
						|
 | 
						|
int stateval(board, whosemove)
 | 
						|
int board[];
 | 
						|
int whosemove;
 | 
						|
{
 | 
						|
  static int row[8][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8},	/* Indices of 3in-a-rows */
 | 
						|
			{0, 3, 6}, {1, 4, 7}, {2, 5, 8},
 | 
						|
			{0, 4, 8}, {2, 4, 6}};
 | 
						|
 | 
						|
  int temp;			/* Temp row results */
 | 
						|
  int i, j;			/* Loop counters */
 | 
						|
  int side;			/* Depth multiplier */
 | 
						|
  int win, lose;
 | 
						|
 | 
						|
  if (whosemove == 1) {
 | 
						|
	win = 100;
 | 
						|
	lose = -100;
 | 
						|
	side = 1;
 | 
						|
  } else {
 | 
						|
	/* Multiply by -1 if */
 | 
						|
	win = -100;
 | 
						|
	lose = 100;
 | 
						|
	side = -1;
 | 
						|
  }				/* not out move */
 | 
						|
  for (i = 0; i < 8; i++) {	/* For every 3-in-a-row */
 | 
						|
	temp = 0;
 | 
						|
	for (j = 0; j < 3; j++)	/* Add up the board values */
 | 
						|
		temp += board[row[i][j]];
 | 
						|
 | 
						|
	if (temp == 3) return(win);	/* We've got 3 in a row */
 | 
						|
	if (temp == 12) return (lose);	/* They've got 3 in a row */
 | 
						|
  }
 | 
						|
  return(0);			/* Finally return sum */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
MOVE alphabeta(board, whosemove, alpha, beta)	/* Alphabeta: takes a board, */
 | 
						|
int board[];			/* whose move, alpha & beta cutoffs, */
 | 
						|
int whosemove;			/* and returns a move to make and */
 | 
						|
int alpha;			/* the value that the move has */
 | 
						|
int beta;
 | 
						|
{
 | 
						|
  MOVE result, successor;
 | 
						|
  int best_score, i, best_path, mademove;
 | 
						|
 | 
						|
  result.value = stateval(board, whosemove);	/* Work out the board's */
 | 
						|
  /* Static value */
 | 
						|
  if ((result.value == 100) ||	/* If a win or loss already */
 | 
						|
      (result.value == -100))
 | 
						|
	return(result);	/* return the result */
 | 
						|
 | 
						|
  best_score = beta;		/* Ok, set worst score */
 | 
						|
  mademove = 0;			/* to the beta cutoff */
 | 
						|
  for (i = 0; i < 9; i++) {
 | 
						|
	if (board[i] == 0) {	/* For all valid moves */
 | 
						|
		mademove = 1;
 | 
						|
		board[i] = whosemove;	/* make the move on board */
 | 
						|
		successor = alphabeta(board, 5 - whosemove, -best_score - 1, -alpha - 1);
 | 
						|
		/* Get value of the move */
 | 
						|
		board[i] = 0;	/* Take move back */
 | 
						|
		if (-successor.value > best_score) {	/* If a better score */
 | 
						|
			best_score = -successor.value;	/* update our score */
 | 
						|
			best_path = i;	/* and move */
 | 
						|
			if (best_score > alpha)
 | 
						|
				break;	/* If we've beaten alpha */
 | 
						|
		}		/* return immediately */
 | 
						|
	}
 | 
						|
  }
 | 
						|
  if (mademove) {
 | 
						|
	result.value = best_score;	/* Finally return best score */
 | 
						|
	result.path = best_path;/* and best move */
 | 
						|
  }
 | 
						|
  return(result);		/* If no move, return static result */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void draw(board)			/* Draw the board */
 | 
						|
int board[];
 | 
						|
{
 | 
						|
  int i, j, row;
 | 
						|
  static char out[] = " X  O";	/* Lookup table for character */
 | 
						|
 | 
						|
  row = 6;
 | 
						|
#ifdef CURSES
 | 
						|
  move(row, 0);
 | 
						|
#endif
 | 
						|
  for (j = 0; j < 9; j += 3) {
 | 
						|
	printw(" %d | %d | %d     ", j, j + 1, j + 2);
 | 
						|
	for (i = 0; i < 3; i++) {
 | 
						|
		printw("%c ", out[board[j + i]]);
 | 
						|
		if (i < 2) printw("| ");
 | 
						|
	}
 | 
						|
	if (j < 4) {
 | 
						|
#ifdef CURSES
 | 
						|
		move(++row, 0);
 | 
						|
#else
 | 
						|
		printw("\n");
 | 
						|
#endif
 | 
						|
		printw("---+---+---   ---+---+---");
 | 
						|
	}
 | 
						|
#ifdef CURSES
 | 
						|
	move(++row, 0);
 | 
						|
#else
 | 
						|
	printw("\n");
 | 
						|
#endif
 | 
						|
  }
 | 
						|
#ifdef CURSES
 | 
						|
  refresh();
 | 
						|
#else
 | 
						|
  printw("\n");
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void getmove(board)			/* Get a player's move */
 | 
						|
int board[];
 | 
						|
{
 | 
						|
  int Move;
 | 
						|
  int ItemsRead;
 | 
						|
  char dumc;
 | 
						|
 | 
						|
  do {
 | 
						|
	do {
 | 
						|
#ifdef CURSES
 | 
						|
		move(9, 40);
 | 
						|
		printw("Your move: ");	/* Prompt for move */
 | 
						|
		refresh();
 | 
						|
#else
 | 
						|
		printw("Your move: ");	/* Prompt for move */
 | 
						|
#endif
 | 
						|
		ItemsRead = scanf("%d", &Move);	/* Input the move */
 | 
						|
		if (ItemsRead == 0) scanf("%c", &dumc);	/* Remove the offending character */
 | 
						|
	}
 | 
						|
	while (ItemsRead != 1);
 | 
						|
  }
 | 
						|
  while (board[Move]);
 | 
						|
  board[Move] = 4;		/* If legal, add to board */
 | 
						|
  draw(board);			/* Draw the board */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int endofgame(board)		/* Determine end of the game */
 | 
						|
int board[];
 | 
						|
{
 | 
						|
  int eval;
 | 
						|
  int count;
 | 
						|
 | 
						|
  eval = stateval(board, 1);
 | 
						|
#ifdef CURSES
 | 
						|
  move(20, 25);
 | 
						|
#endif
 | 
						|
  if (eval == 100) {
 | 
						|
	printw("I have beaten you.\n");
 | 
						|
	return(1);
 | 
						|
  }
 | 
						|
  if (eval == -100) {
 | 
						|
	printw("Bus error (core dumped)\n");
 | 
						|
	return(1);
 | 
						|
  }
 | 
						|
  count = 0;
 | 
						|
  for (eval = 0; eval < 9; eval++)
 | 
						|
	if (board[eval] != 0) count++;
 | 
						|
  if (count == 9) {
 | 
						|
	printw("A draw!\n");
 | 
						|
	return(1);
 | 
						|
  }
 | 
						|
#ifdef CURSES
 | 
						|
  refresh();
 | 
						|
#endif
 | 
						|
  return(0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int randommove()
 | 
						|
{				/* Make an initial random move */
 | 
						|
  int i;
 | 
						|
 | 
						|
  i = abs((int) time((long *) 0));
 | 
						|
  return(i % 9);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int main()
 | 
						|
{				/* The actual game */
 | 
						|
  int i, board[9];
 | 
						|
  char ch;
 | 
						|
  MOVE ourmove;
 | 
						|
 | 
						|
  for (i = 0; i < 9; i++) board[i] = 0;	/* Initialise the board */
 | 
						|
#ifdef CURSES
 | 
						|
  initscr();
 | 
						|
  clear();
 | 
						|
  refresh();
 | 
						|
#endif
 | 
						|
  printw("                           TIC TAC TOE   \n\n");
 | 
						|
  printw("                        Your moves are 'O'\n");
 | 
						|
  printw("                         My moves are 'X'\n\n");
 | 
						|
#ifdef CURSES
 | 
						|
  move(5, 0);
 | 
						|
  printw("Do you wish to move first: ");
 | 
						|
  refresh();
 | 
						|
  while (scanf("%c", &ch) != 1);
 | 
						|
  move(5, 0);
 | 
						|
  printw("                         .......");	/* Kludge to get rid */
 | 
						|
  refresh();
 | 
						|
  move(5, 0);
 | 
						|
  printw("                                ");	/* of input letter */
 | 
						|
  refresh();
 | 
						|
#else
 | 
						|
  do
 | 
						|
	printw("Do you wish to move first: ");
 | 
						|
  while (scanf("%c", &ch) != 1);
 | 
						|
#endif
 | 
						|
  if ((ch != 'y') && (ch != 'Y')) {
 | 
						|
	i = randommove();	/* If we move first */
 | 
						|
	board[i] = 1;		/* make it random */
 | 
						|
#ifdef CURSES
 | 
						|
	move(7, 42);
 | 
						|
	printw("My move: %d\n", i);
 | 
						|
	refresh();
 | 
						|
#else
 | 
						|
	printw("My move: %d\n", i);
 | 
						|
#endif
 | 
						|
  }
 | 
						|
  draw(board);
 | 
						|
  getmove(board);
 | 
						|
 | 
						|
  while (1) {
 | 
						|
	ourmove = alphabeta(board, 1, 99, -99);	/* Get a move for us;
 | 
						|
						 * return wins */
 | 
						|
	/* Immediately & ignore losses */
 | 
						|
	board[ourmove.path] = 1;/* and make it */
 | 
						|
#ifdef CURSES
 | 
						|
	move(7, 42);
 | 
						|
	printw("My move: %d\n", ourmove.path);
 | 
						|
	refresh();
 | 
						|
#else
 | 
						|
	printw("My move: %d\n", ourmove.path);
 | 
						|
#endif
 | 
						|
	draw(board);
 | 
						|
	if (endofgame(board)) break;	/* If end of game, exit */
 | 
						|
	getmove(board);		/* Get opponent's move */
 | 
						|
	if (endofgame(board)) break;	/* If end of game, exit */
 | 
						|
  }
 | 
						|
#ifdef CURSES
 | 
						|
  endwin();
 | 
						|
#endif
 | 
						|
  return(0);
 | 
						|
}
 |