第2题之测试程序:
/*
Name: Tic-Tac-Toe
Copyright: original
Author: goal00001111
Date: 12-04-06 10:25
Description:
tic-tac-toe 是在3*3的棋盘上进行对弈的游戏。两个玩家在方格上轮流放置自己的棋子。
谁先获得行,列或对角线上的连续3个方格,谁就获胜。
请编写一个程序与其他程序进行tic-tac-toe比赛。
我创建了一个棋盘,供两位选手对弈。选手根据我提供的当前棋盘布局情况,选择合适的棋子落点。
注意:棋子要下在适当的空白处,若落子在已有棋子的地方或超出棋盘界限,判负。
函数接口:void ChooseMove(const int board[][3], int & row, int & column);
输入:当前棋盘布局board[][3],棋盘上某点的行号row和列号column,行号和列号均从0开始.
输出:棋子落点的坐标 row, column
当前棋盘布局board[][3],空为0, 我方为1, 敌方为2.
我会在测试程序中对棋盘布局board[][3]进行实时变更,使得面对每一个选手程序均为:空为0, 我方为1, 敌方为2.
评分方法:
每一轮比赛由2个程序进行3局对弈,前两局分先,第3局猜先。每局对弈打平各得1分,胜利者得2分,失败者不得分。
比赛按提交楼层顺序,每3个程序为一组(每人最多提交2个程序,如果超过2个则只取最后修改的2个程序)。
每组进行循环赛,即组内任意2个程序进行一轮比赛。
分组剩余的程序如果为1个则自动晋级。如果为2个则2个程序作为一组进行比赛。
第一次循环赛结束后,每组得分最高的程序晋级,其他程序被淘汰。如果组内最高分相同,则一起晋级。
对所有晋级程序按顺序进行第二次分组,淘汰的程序不继续参与比赛。
重复直到最终剩余一个程序或者不再有人被淘汰为止。
*/#include<cassert>
#include<iostream>
using namespace std;
enum Side { EMPTY, PLAYER1, PLAYER2 };
enum PositionVal { PLAYER1_WIN, DRAW, UNCLEAR, PLAYER2_WIN };
int PlayGame( int player1, int player2 );
void GetBoard(int board[][3]);
void ClearBoard( int board[][3] );
bool BoardIsFull( const int board[][3] );
bool PlayMove( int board[][3], int player, int row, int column );
bool IsAWin( const int board[][3], int player );
void PrintBoard(const int board[][3]);
void ChooseMove_1(const int board[][3], int & row, int & column);
void ChooseMove_2(const int board[][3], int & row, int & column);
void ChooseMove_3(const int board[][3], int & row, int & column);
int ChooseMove(int board[][3], Side s, int & bestRow, int & bestColumn);
void Place( int board[][3], int row, int column, int piece );
bool SquareIsEmpty( const int board[][3], int row, int column );
int PositionValue( const int board[][3]);
////////////////////////////作者:eastcowboy///////////////////////////////////////////////
// 测试环境Visual Stuidio 2005
// 语言:C++
// 考虑下子的顺序
// 1、如果我方下一步能胜利,则胜利
// 2、如果对手下一步能胜利,则试图阻止
// 3、占据当前条件下最重要的位置
// 最重要的位置定义为:已经被占据的位置都不是当前重要位置。
// 在此前提下按以下标准评分,分最高的就是最重要的
// a、如果我方可通过此位置获得胜利,得一分。(有多种途径可得多分)
// b、如果对手可通过此位置获得胜利,也得一分。(有多种途径可得多分)
static inline bool WillWin(
const int board[][3],
const int WinLine[3][2],
int &row, int &column
)
{
int i;
int n0 = 0;
int n1 = 0;
for(i=0; i<3; ++i)
{
int x = WinLine[i][0];
int y = WinLine[i][1];
if( board[x][y] == 0 )
++n0, row=x, column=y;
else if( board[x][y] == 1 )
++n1;
}
return ((n0==1) && (n1==2));
}
static inline bool WillLose(
const int board[][3],
const int WinLine[3][2],
int &row, int &column
)
{
int i;
int n0 = 0;
int n1 = 0;
for(i=0; i<3; ++i)
{
int x = WinLine[i][0];
int y = WinLine[i][1];
if( board[x][y] == 0 )
++n0, row=x, column=y;
else if( board[x][y] == 2 )
++n1;
}
return ((n0==1) && (n1==2));
}
static inline bool PointInLine(const int WinLine[3][2], const int row, const int column)
{
register int i;
for(i=0; i<3; ++i)
if(WinLine[i][0]==row && WinLine[i][1]==column)
return true;
return false;
}
static inline bool CanWin(
const int board[][3],
const int WinLine[3][2]
)
{
int i;
for(i=0; i<3; ++i)
{
int x = WinLine[i][0];
int y = WinLine[i][1];
if( board[x][y] == 2 )
return false;
}
return true;
}
static inline bool CanLose(
const int board[][3],
const int WinLine[3][2]
)
{
int i;
for(i=0; i<3; ++i)
{
int x = WinLine[i][0];
int y = WinLine[i][1];
if( board[x][y] == 1 )
return false;
}
return true;
}
void ChooseMove_2(const int board[][3], int &row, int &column)
{
static int WinLine[8][3][2] = {
0,0,0,1,0,2, // 第一行
1,0,1,1,1,2, // 第二行
2,0,2,1,2,2, // 第三行
0,0,1,0,2,0, // 第一列
0,1,1,1,2,1, // 第二列
0,2,1,2,2,2, // 第三列
0,0,1,1,2,2, // 左上到右下方向
0,2,1,1,2,0 // 右下到左上方向
};
int i;
// 1、如果我方下一步能胜利,则胜利
for(i=0; i<8; ++i)
if( WillWin(board, WinLine[i], row, column) )
{
assert( board[row][column] == 0 );
return;
}
// 2、如果对手下一步能胜利,则试图阻止
for(i=0; i<8; ++i)
if( WillLose(board, WinLine[i], row, column) )
{
assert( board[row][column] == 0 );
return;
}
// 3、占据当前条件下最重要的位置
int Importance[3][3] = {0};
int r,c;
int maxImportance = -1;
for(r=0; r<3; ++r)
for(c=0; c<3; ++c)
{
if( board[r][c] != 0 )
{
Importance[r][c] = -2;
continue;
}
for(i=0; i<8; ++i)
if( PointInLine(WinLine[i], r, c) )
{
if( CanWin(board, WinLine[i]) )
++(Importance[r][c]);
if( CanLose(board, WinLine[i]) )
++(Importance[r][c]);
}
if( Importance[r][c] > maxImportance )
maxImportance = Importance[r][c];
}
for(r=0; r<3; ++r)
for(c=0; c<3; ++c)
if( Importance[r][c] == maxImportance )
{
row = r;
column = c;
return;
}
}
///////////////////////////////////////////////////////////////////////////////////////
////////////////////////作者:yxs0001////////////////////////////////////////////////////
struct Point{
int row;
int column;
};
struct LINE{
int points;//点数
bool pass;//是否可能在该线获胜
//构造函数
LINE(){
points = 0;
pass = true;
}
};
struct PLAYER{
LINE H_Line[3];//横线
LINE C_Line[3];//竖线
LINE D_Line[2];//斜线
// int ps;//本方点数
};
class CChess{
private :
int bps;//空点数
Point BlackPoint[9];//空点
PLAYER I,you;
public :
//构造函数
CChess(const int board[][3]);
//点的分值
int ScorePoint(Point p);
int ScoreCheck(Point p,LINE line,int player);
//下的位置
void FallPoint(int & row, int & column);
//初始化(row,column)
void InitPoint(const int row,const int column,const int player);
};
void CChess::InitPoint(const int row,const int column,const int player)
{
PLAYER *p1,*p2;
if(player == 2){
p1 = &you;
p2 = &I;
}
else{
p1 = &I;
p2 = &you;
}
// p1->ps ++;
//横线
p1->H_Line[row].points++;
p2->H_Line[row].pass = false;
//竖线
p1->C_Line[column].points++;
p2->C_Line[column].pass = false;
//斜线
if(row == column){
p1->D_Line[0].points++;
p2->D_Line[0].pass = false;
}
if(row + column == 2){
p1->D_Line[1].points++;
p2->D_Line[1].pass = false;
}
}
CChess::CChess(const int board[][3])
{
int i,j;
bps = 0;
// I.ps =0;
// you.ps = 0;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
{
if(board[i][j])
InitPoint(i,j,board[i][j]);
else{//空点
BlackPoint[bps].row = i;
BlackPoint[bps].column = j;
bps++;
}
}
}
int CChess::ScoreCheck(Point p,LINE line,int player)
{
int score = 0;
int score1,score2;
if(player == 1){
score1 = 125;
score2 = 1000;
}
else{
score1 = 100;
score2 = 500;
}
if(line.pass){
switch (line.points){
case 0:
break;
case 1:
score += score1;
break;
case 2:
score += score2;//胜点
}
}
return score;
}
int CChess::ScorePoint(Point p)
{
int score = 0;
LINE line;
if(p.column == p.row ){//斜线1
score ++;
//己方
line = I.D_Line[0];
score += ScoreCheck(p,line,1);
//对方
line = you.D_Line[0];
score += ScoreCheck(p,line,2);
}
if(p.row + p.column == 2){//斜线2
score ++;
//己方
line = I.D_Line[1];
score += ScoreCheck(p,line,1);
//对方
line = you.D_Line[1];
score += ScoreCheck(p,line,2);
}
//横线 //己方
line = I.H_Line[p.row];
score += ScoreCheck(p,line,1);
//对方
line = you.H_Line[p.row];
score += ScoreCheck(p,line,2);
//竖线 //己方
line = I.C_Line[p.column];
score += ScoreCheck(p,line,1);
//对方
line = you.C_Line[p.column];
score += ScoreCheck(p,line,2);
return score;
}
void CChess::FallPoint(int & row,int & column)
{
int max = -1;
int score;
// Point p;
for(int i=0;i<bps;i++){
score = ScorePoint(BlackPoint[i]);
if(score>max){
max = score;
row = BlackPoint[i].row;
column = BlackPoint[i].column;
}
if (max>=1000)
return;
}
}
void ChooseMove_1(const int board[][3], int & row, int & column)
{
CChess cchess(board);
cchess.FallPoint(row,column);
}
//////////////////////////////////////////////////////////////////////////////////
int main( )
{
cout << "Welcome to TIC-TAC-TOE" << endl;
const int N = 4;
int score[N] = {0};
int winer;
for (int i=1; i<N-1; i++)
for (int j=i+1; j<N; j++)
{
winer = PlayGame( i, j );
if (winer == 0)
{
cout << "DRAW!\n";
score[i]++;
score[j]++;
}
else
{
cout << winer << "WIN!\n";
score[winer] += 2;
}
}
for (int i=1; i<N; i++)
cout << i << ":" << score[i] << endl;
getchar();
return 0;
}
int PlayGame( int player1, int player2 )
{
int board[3][3];
int bestRow, bestColumn;
int player = 1;//每一个选手程序的棋子值均为1
ClearBoard(board);
while( !BoardIsFull(board) )
{
//对棋盘布局board[][3]进行实时变更,使得面对每一个选手程序均为:空为0, 我方为1, 敌方为2
GetBoard(board); //创建空棋盘
if (player1 == 1)
ChooseMove_1( board, bestRow, bestColumn);
else if (player1 == 2)
ChooseMove_2( board, bestRow, bestColumn);
if (!PlayMove(board, player, bestRow, bestColumn))
return player2;
if (IsAWin(board, player1))
return player1;
if ( !BoardIsFull(board) )//如果棋盘未满
{
GetBoard(board);
if (player2 == 2)
ChooseMove_2( board, bestRow, bestColumn);
else if (player2 == 3)
ChooseMove_3( board, bestRow, bestColumn);
if (!PlayMove(board, player, bestRow, bestColumn))
return player1;
if (IsAWin(board, player2))
return player2;
}
}
return 0;
}
/*
函数介绍:对棋盘布局board[][3]进行实时变更,使得面对每一个选手程序均为:空为0, 我方为1, 敌方为2
即若把原来为1的子变成2,原来为2的子变成1
输入:当前棋局落子分布board[][3]
输出:更新后的棋局落子分布board[][3]
*/
void GetBoard(int board[][3])
{
for( int i = 0; i < 3; i++ )
for( int j = 0; j < 3; j++ )
{
if (board[i][j] == 1)
board[i][j] = 2;
else if (board[i][j] == 2)
board[i][j] = 1;
}
}
/////////////////作者:goal00001111////////////////////////////////////
// Routine to compute optimal tic-tac-toe move.
/*
函数介绍:根据当前棋局落子分布,采用回溯算法,确定最佳着点
输入:当前棋局落子分布board[][3],最佳着点的坐标 bestRow, bestColumn
输出:最佳着点的坐标 bestRow, bestColumn
*/
void ChooseMove_3(const int board[][3], int & row, int & column)
{
int c_board[3][3];
for( int i = 0; i < 3; i++ )
for( int j = 0; j < 3; j++ )
c_board[i][j] = board[i][j];
PrintBoard(board);
ChooseMove( c_board, PLAYER1, row, column);
}
/*
函数介绍:根据当前棋局落子分布,采用回溯算法,确定最佳着点
输入:当前棋局落子分布board[][3],当前选手s,最佳着点的坐标 bestRow, bestColumn
输出:当前棋局落子分布board[][3],最佳着点的坐标 bestRow, bestColumn
返回该落子点的分值value
*/
int ChooseMove(int board[][3], Side s, int & bestRow, int & bestColumn)
{
Side opp; // The other side
int reply; // Value of opponent's reply
int dc; // Placeholder
int simpleEval; // Result of an immediate evaluation
int value; //该落子点的分值,可以是枚举变量PositionVal中的任何一个
if( ( simpleEval = PositionValue(board) ) != UNCLEAR )//若胜负已分,则不再落子,直接返回分值
return simpleEval;
if( s == PLAYER1 )
{
opp = PLAYER2;
value = PLAYER2_WIN;
}
else
{
opp = PLAYER1;
value = PLAYER1_WIN;
}
// Search for a move.
for( int row = 0; row < 3; row++ )
for( int column = 0; column < 3; column++ )
if( SquareIsEmpty( board, row, column ) )
{
Place( board, row, column, s ); // Try s move; then
reply = ChooseMove( board, opp, dc, dc );// Evaluate;
Place( board, row, column, EMPTY ); // then undo
// If s gets a better position; update
//如果返回信息为自己可以赢,不再继续搜寻最佳落子点,直接在此处下子
if( s == PLAYER2 && reply == PLAYER2_WIN ||
s == PLAYER1 && reply == PLAYER1_WIN )
{
bestRow = row;
bestColumn = column;
return reply;
}
//否则继续搜寻最佳落子点
if( s == PLAYER2 && reply > value ||
s == PLAYER1 && reply < value )
{
value = reply;
bestRow = row;
bestColumn = column;
}
}
return value;
}
void Place( int board[][3], int row, int column, int piece )
{
board[ row ][ column ] = piece;
}
bool SquareIsEmpty( const int board[][3], int row, int column )
{
return board[ row ][ column ] == EMPTY;
}
int PositionValue( const int board[][3])
{
return IsAWin( board, PLAYER1 ) ? PLAYER1_WIN :
IsAWin( board, PLAYER2 ) ? PLAYER2_WIN :
BoardIsFull(board) ? DRAW : UNCLEAR;
}
/////////////////////////////////////////////////////////////////////////////////
// Clear the board.
void ClearBoard(int board[][3])
{
for( int row = 0; row < 3; row++ )
for( int column = 0; column < 3; column++ )
board[ row ][ column ] = EMPTY;
}
/*
函数介绍:根据当前棋局落子分布,判断棋盘是否已满
输入:当前棋局落子分布board[][3]
输出:若棋盘已满返回真,否则返回假
*/
bool BoardIsFull( const int board[][3])
{
for( int row = 0; row < 3; row++ )
for( int column = 0; column < 3; column++ )
if( board[ row ][ column ] == EMPTY )
return false;
return true;
}
/*
函数介绍:根据当前落子选手选择的坐标落子,并判断其是否违规
输入:落子前棋局分布board[][3] ,当前落子选手player,当前选手选择的坐标row, column
输出:更新棋局分布board[][3] ;
若当前落子选手没有违规返回真,否则返回假
*/
bool PlayMove( int board[][3], int player, int row, int column )
{
if( row < 0 || row >= 3 || column < 0 || column >= 3
|| board[ row ][ column ] != EMPTY )
{cout << row << column <<endl; return false; }
board[ row ][ column ] = player;
return true;
}
/*
函数介绍:根据当前棋局落子分布,判断当前落子选手是否胜利
输入:当前棋局落子分布board[][3] ,当前落子选手player
输出:若当前落子选手胜利返回真,否则返回假
*/
bool IsAWin( const int board[][3], int player )
{
int row, column;
// Look for all in a row
for( row = 0; row < 3; row++ )
{
for( column = 0; column < 3; column++ )
if( board[ row ][ column ] != player )
break;
if( column >= 3 )
return true;
}
// Look for all in a column
for( column = 0; column < 3; column++ )
{
for( row = 0; row < 3; row++ )
if( board[ row ][ column ] != player )
break;
if( row >= 3 )
return true;
}
// Look on diagonals
if( board[ 1 ][ 1 ] == player && board[ 2 ][ 2 ] == player
&& board[ 0 ][ 0 ] == player )
return true;
if( board[ 0 ][ 2 ] == player && board[ 1 ][ 1 ] == player
&& board[ 2 ][ 0 ] == player )
return true;
return false;
}
/*
函数介绍:输出当前棋局落子分布
输入:当前棋局落子分布board[][3]
*/
void PrintBoard(const int board[][3])
{
cout << "-------\n";
for( int row = 0; row < 3; row++ )
{
for( int col = 0; col < 3; col++ )
{
cout << "|";
cout << board[row][col];
}
cout << "|\n";
}
cout << "-------" << endl;
}
正文
第24次比赛第2题之测试程序:2006-04-17 20:51:00
【评论】 【打印】 【字体:大 中 小】 本文链接:http://blog.pfan.cn/goal00001111/12615.html
阅读(2368) | 评论(0)
版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!
评论