home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
dirs
/
curses_391.lzh
/
Curses
/
examples
/
tttt
/
tttt.c
< prev
Wrap
C/C++ Source or Header
|
1990-10-27
|
7KB
|
354 lines
/*
Eric Lechner Feb. 27, 1990
revised for curses output: march 6, 1990
CE 126 Final Project Development
a high level simulation of tic-tac-toc-toe, a 4x4
version of tic-tac-toe with "wraparound edges"
this takes user input for one player, and has a
computer player for the other.
*/
#include <stdio.h>
#include <curses.h>
#define EMPTY 0
#define X 1
#define O 2
#define TIE -1 /* for ending when the board is full */
#define QUIT -2
#define WIN 100 /* for position rank scoring */
#ifndef TRUE
#define TRUE 1 /* cause they aren't included elsewhere */
#define FALSE 0
#endif
char board [4][4]; /* this is the playing board */
int pieces;
void initboard(),
printboard();
int check_win(),
getrank(),
x_move(), /* "our" move */
o_move(); /* the computer player's move */
main()
{
int done = FALSE;
int xmove = TRUE;
pieces = 0;
initscr();
savetty();
cbreak();
noecho();
initboard();
clear();
printboard();
while (!done) {
if (xmove)
done = x_move();
else {
done = o_move();
}
if ((++pieces == 16) && !done) done = TIE;
xmove = !xmove;
}
switch (done) {
case TIE :
move(17,23);
printw("The board is full, and nobody won.\n");
break;
case QUIT :
move(17,23);
printw("Hope to beat you again someday!\n");
break;
default :
move(17,33);
printw("Player `%c' Wins!\n",(done == X) ? 'X' : 'O');
}
move(21,0);
refresh();
#ifdef AMIGA
Delay(200);
#else
sleep(2);
#endif
resetty();
endwin();
}
/*
initialize the board to all empty
*/
void initboard()
{
int i,j;
for (i=0; i<4; i++)
for (j=0; j<4; j++)
board [i][j] = EMPTY;
}
/*
print the current board
*/
void printboard()
{
int i;
move(2,24);
printw("Tic-Tac-Toc-Toe - by Eric Lechner");
move(5,30);
printw(" A B C D \n");
move(6,30);
printw(" --- --- --- ---\n");
for (i=0; i<4; i++) {
move(7 + (i * 2), 30);
printw("%d | %c | %c | %c | %c |\n", i,
(!board[i][0]) ? ' ' : (board[i][0] == X) ? 'X' : 'O',
(!board[i][1]) ? ' ' : (board[i][1] == X) ? 'X' : 'O',
(!board[i][2]) ? ' ' : (board[i][2] == X) ? 'X' : 'O',
(!board[i][3]) ? ' ' : (board[i][3] == X) ? 'X' : 'O');
move(8 + (i * 2), 30);
printw(" --- --- --- ---\n");
}
refresh();
}
/*
player "x", the human player
*/
int x_move()
{
int row, col, tmp, mess = 0;
GetX: row = col = -1;
move(15,33);
printw("Your move : ");
clrtoeol();
refresh();
while ((row == -1) || (col == -1)) {
tmp = getch();
switch (tmp) {
case 'A' :
case 'a' :
case 'B' :
case 'b' :
case 'C' :
case 'c' :
case 'D' :
case 'd' :
move(15,45);
printw("%c ",tmp);
if ((tmp >= 'a') && (tmp <= 'd'))
col = tmp - 'a';
else
col = tmp - 'A';
break;
case '0' :
case '1' :
case '2' :
case '3' :
move(15,47);
printw("%c",tmp);
row = tmp - '0';
break;
case 'q' :
case 'Q' :
return(QUIT);
break;
case 0x12 :
case 0x0c :
clear();
printboard();
goto GetX;
default:
break;
}
refresh();
}
if (board[row][col] == EMPTY) board[row][col] = X;
else {
move(17,34);
printw("Illegal move!\n");
mess = 1; /* whether an error message has been printed */
refresh();
goto GetX;
}
if (mess) { /* if there was an error message, clear it */
move(17,1);
clrtoeol();
}
move(7 + (row * 2), 34 + (col * 4)); /* print the move */
printw("X");
refresh();
return (check_win (X,row,col));
}
/*
player "o", the computer player
*/
int o_move()
{
int bestrank = 0, bestrow = 0, bestcol = 0, i, j, rank;
for (i=0; i<4; i++) {
for (j=0; j<4; j++) {
rank = getrank(O,i,j);
if (rank > bestrank) {
bestrow = i;
bestcol = j;
bestrank = rank;
}
}
}
board [bestrow][bestcol] = O;
move(7 + (bestrow * 2), 34 + (bestcol * 4));
printw("O");
refresh();
return (check_win (O,bestrow,bestcol));
}
/*
this ranks a move location in order of "preference".
the strategy is to not let the opponent get lots in a row.
ever.
rows, columns, and diagonals get treated independently, and
the "best" rank of them all is considered.
*/
int getrank(type,row,col)
int type,row,col;
{
int i, rank = 0, countx = 0, counto = 0;
/* if already taken, this isn't a good spot */
if (board[row][col]) return (rank);
/* check across */
countx = counto = 0;
for (i=0; i<4; i++) {
if (board[row][i] == X) countx++;
else if (board[row][i] == O) counto++;
}
if (type == X) {
if (countx >= 3) return (WIN);
if (!countx && (counto > rank)) rank = counto;
} else {
if (counto >= 3) return (WIN);
if (!counto && (countx > rank)) rank = countx;
}
/* check vertically */
countx = counto = 0;
for (i=0; i<4; i++) {
if (board[i][col] == X) countx++;
else if (board[i][col] == O) counto++;
}
if (type == X) {
if (countx >= 3) return (WIN);
if (!countx && (counto > rank)) rank = counto;
} else {
if (counto >= 3) return (WIN);
if (!counto && (countx > rank)) rank = countx;
}
/* check \ diagonal */
countx = counto = 0;
for (i=0; i<4; i++) {
if (board[(row + i) % 4][(col + i) % 4] == X) countx++;
else if (board[(row + i) % 4][(col + i) % 4] == O) counto++;
}
if (type == X) {
if (countx >= 3) return (WIN);
if (!countx && (counto > rank)) rank = counto;
} else {
if (counto >= 3) return (WIN);
if (!counto && (countx > rank)) rank = countx;
}
/* check / diagonal */
countx = counto = 0;
for (i=0; i<4; i++) {
if (board[(row + 4 - i) % 4][(col + i) % 4] == X) countx++;
else if (board[(row + 4 - i) % 4][(col + i) % 4] == O) counto++;
}
if (type == X) {
if (countx >= 3) return (WIN);
if (!countx && (counto > rank)) rank = counto;
} else {
if (counto >= 3) return (WIN);
if (!counto && (countx > rank)) rank = countx;
}
/* add one, so that even no blocks still shows as a valid move */
/* and return the rank for this move */
return (++rank);
}
/*
checks for a win at a specific location, and returns the
type of win, or 0, if there wasn't a win.
*/
int check_win(type,row,col)
int type, row, col;
{
int r[4],c[4], i; /* temp row, col, and counter vars */
/* check across */
if ((board [row][0] == type) && (board [row][1] == type) &&
(board [row][2] == type) && (board [row][3] == type))
return (type);
/* check vertically */
if ((board [0][col] == type) && (board [1][col] == type) &&
(board [2][col] == type) && (board [3][col] == type))
return (type);
/* check \ diagonal */
for (i=0; i<4; i++) {
r[i] = (row + i) % 4;
c[i] = (col + i) % 4;
}
if ((board [r[0]][c[0]] == type) && (board [r[1]][c[1]] == type) &&
(board [r[2]][c[2]] == type) && (board [r[3]][c[3]] == type))
return (type);
/* check / diagonal */
for (i=0; i<4; i++) {
r[i] = (row + i) % 4;
c[i] = (col + (4 - i)) % 4;
}
if ((board [r[0]][c[0]] == type) && (board [r[1]][c[1]] == type) &&
(board [r[2]][c[2]] == type) && (board [r[3]][c[3]] == type))
return (type);
/* if it got here, there aren't any wins at that spot */
return (0);
}