#include
#include
//棋子 x,y是棋子的坐标位置,value是判断该坐标是否落有棋子 0表示没有落棋 1表示X自己下的棋 2表示〇AI下的棋
//一字棋棋盘 一共9个格子
typedef struct{
int chessman[9];
}ChessBoard;
//搜索树节点的定义
typedef struct BiTNode{
ChessBoard chessboard; //chessboard 一个棋盘以及所有棋子落子的情况
int CoordinateAI; //这一步棋子的位置 ChessMan[]0~8
int CoordinatePlayer; //这一步是选手可能落下棋子的位置
int Value; //节点的估价值
}BiTNode;
BiTNode Head; //头结点
//BiTNode *TreeBoard;
#define MAX 100
#define MIN -100
#define DOGFALL 50 //平局
void initialBoard(ChessBoard *chessboard); //初始化一个棋盘,对一字棋棋盘的每个格子规定坐标
int EvaluationFunction(ChessBoard *chessboard); //计算节点的静态估价值
int checkValue(int x,int y, ChessBoard *chessboard); //判断某一方可能获胜结果的个数
void PlayChess(int x, int play, ChessBoard *chessboard); //下棋
int PlayAI(ChessBoard *chessboard); //AI考虑下棋
void DrawBoard(ChessBoard *chessboard); //绘画棋盘,给用户显示
int PlayAI(ChessBoard *chessboard); //电脑考虑下棋
int judgeBoard(ChessBoard *chessboard); //当某一方下棋后,判断结果
int main(){
int first = 0;
int play;
int playNum = 0; //记录运行步数 如果大于9,说明平局
printf("欢迎来到一字棋游戏;x代表你下的棋,〇代表电脑下的棋 该棋盘9个棋子的位置对应坐标如下:\n");
printf("-------------------\n") ;
printf("| 0 | 1 | 2 |\n\n");
printf("| 3 | 4 | 5 |\n\n");
printf("| 6 | 7 | 8 |\n");
printf("-------------------\n\n");
printf("当你和机器对弈时,请输入你下的棋子位置对应的坐标,比如想下在最中间的位置就输入4\n");
printf("现在请选择这局一字棋游戏谁先走第一步,请输入0或1,0代表机器先下 1代表你先下\n");
scanf("%d",&first);
ChessBoard playChessBoard; //整局游戏的一盘棋,同时也可当作头结点
ChessBoard *playBoard = &playChessBoard; //棋盘指针
initialBoard(playBoard); //传指针
if(first == 1){
printf("-------------------\n") ;
printf("| 0 | 1 | 2 |\n\n");
printf("| 3 | 4 | 5 |\n\n");
printf("| 6 | 7 | 8 |\n");
printf("-------------------\n\n");
printf("请输入你下棋的位置:");
scanf("%d",&play);
PlayChess(1,play, playBoard); //用户选手下棋
DrawBoard(playBoard);
playNum++;
}else{
int AI = PlayAI(playBoard); //AI考虑下棋
printf("电脑下棋的位置: %d\n",AI);
PlayChess(2,AI, playBoard); //电脑选手下棋
playNum++;
DrawBoard(playBoard); //显示给用户下棋
printf("请你做下一步棋:");
scanf("%d",&play);
}
int playNext = 1; //定义一个整形数据,决定下一步谁下棋 1表示用户选手下棋 2表示电脑下棋
if(first == 1){
playNext = 2;
}
int finalResult = 0;
while(playNum<9){
if(playNext == 2){
int AI = PlayAI(playBoard);
PlayChess(2,AI, playBoard); //电脑下棋
printf("电脑下棋的位置: %d\n",AI);
DrawBoard(playBoard);
finalResult = judgeBoard(playBoard);
if(playNum != 8 && finalResult!= 2){
printf("请你做下一步棋:");
scanf("%d",&play);
}
playNext = 1;
}else if(playNext == 1){
PlayChess(1,play, playBoard); //用户选手下棋
DrawBoard(playBoard);
playNext = 2; //下一步电脑下棋
}
finalResult = judgeBoard(playBoard);
if(finalResult == 1){
printf("你赢了!\n");
break;
}
if(finalResult == 2){
printf("电脑赢了!");
break;
}
playNum++;
}
if(playNum == 9){
printf("结果平局\n");
}
printf("游戏结束!");
return 0;
}
//初始化一个棋盘,对一字棋棋盘的每个格子规定坐标
void initialBoard(ChessBoard *chessboard){
for(int i=0; i<=8; i++){ //将棋盘的所有棋子标为0,表示为未落子
// *chessboard.chessman[i] = 0;
chessboard->chessman[i] = 0;
}
}
//计算节点的静态估价值
int EvaluationFunction(ChessBoard *chessboard){
// ChessBoard *p = &chessboard;
int EvaluationAI = checkValue(1,2,chessboard); //AI的胜算
int EvaluationPlayer = checkValue(2,1,chessboard); //对手的胜算
int Evaluation = EvaluationAI - EvaluationPlayer;
int judge[8][3] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
int coordinate ;
int valueX;
int valueY;
for(int i=0; i<=7; i++){
valueX = 0;
valueY = 0;
for(int j=0; j<=2;j++){
coordinate = judge[i][j];
if(chessboard->chessman[coordinate] == 1){
valueX++;
}
if(chessboard->chessman[coordinate] == 2){
valueY++;
}
}
if(valueX == 3){
return MIN;
}
if(valueY == 3){
return MAX;
}
}
return Evaluation;
}
//判断某一方可能获胜结果的个数
int checkValue(int x, int y, ChessBoard *chessboard){
int value = 0;
int judge[8][3] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
int coordinate ;
for(int i=0; i<=7; i++){
int j = 0;;
for(j=0; j<=2; j++){
coordinate = judge[i][j];
//判断8个胜利的可能是否有对手的棋子,如果有,则可判定这个结果不可能胜算
if(chessboard->chessman[coordinate] == x ){
break;
}
}
if(j>2){
value++;
}
}
return value;
}
//下棋
void PlayChess(int x, int play, ChessBoard *chessboard){
chessboard->chessman[play] = x;
}
//绘画棋盘,给用户显示
void DrawBoard(ChessBoard *chessboard){
int i;
int num = 0;
printf("-------------------\n");
for(i=0; i<=8; i++){
if(chessboard->chessman[i] == 1){
printf("| X ");
}else if(chessboard->chessman[i] == 2){
printf("| 〇 ");
}else{
printf("| %d ",i);
}
num++;
if(num%3 == 0){
printf("|\n\n");
}
}
printf("-------------------\n\n");
}
//AI考虑下棋
int PlayAI(ChessBoard *chessboard){
for(int i=0; i<=8; i++){
//给头结点棋盘赋值 当前结点棋盘的棋子保持情况
Head.chessboard.chessman[i] = chessboard->chessman[i];
}
int aFatherValue[9]; //Max节点的估价函数值,选取该节点所有孩子节点的最小估价函数赋值
for(int i=0;i<=8;i++){
aFatherValue[i] = MIN; //初始化
}
BiTNode a[9][9]; //极大极小搜索树用数组表示
for(int i=0; i<=8; i++){ //这个for循环是遍历头结点的所有子节点,即max结点
for(int j=0; j<=8; j++){ //这个for循环是将max结点的所有子节点对局详情棋盘复写
for(int k=0; k<=8; k++){
a[i][j].chessboard.chessman[k] = Head.chessboard.chessman[k]; //将当前对局的棋保存在结点棋盘里
}
a[i][j].Value =MAX; //该节点估价函数赋值为MIN 初始为最大
a[i][j].CoordinateAI = -1;
a[i][j].CoordinatePlayer = -1;
}
}
//搜索树生成,并用极大极小值求出头结点的估价函数 求出电脑选手下棋的位置
int min = MAX;
for(int i=0; i<=8; i++){
if(Head.chessboard.chessman[i] == 0){
min = MAX;
for(int j=0; j<=8; j++){
a[i][j].CoordinateAI = i;
a[i][j].chessboard.chessman[i] = 2; //电脑可能下的棋
if(a[i][j].chessboard.chessman[j] == 0){
a[i][j].CoordinatePlayer = j; //选手可能下的位置
a[i][j].chessboard.chessman[j] = 1; //选手可能下的棋
ChessBoard *p = &a[i][j].chessboard; //定义一个指针 用来(求估价函数 )判断结果
a[i][j].Value = EvaluationFunction(p); //求估价函数 求估价函数值还是需要传指针
if(a[i][j].Value <= min){ //求出max结点的估价函数值
min = a[i][j].Value;
}
}
}
aFatherValue[i] = min; //给有叶子节点的max节点赋值 求其所有叶子节点中最小的赋值
// printf("电脑下%d位置的max节点值为%d\n\n\n\n",i,aFatherValue[i]);
// printf(aFatherValue[i]);
}
}
int max = MIN;
for(int i=0; i<=8; i++){
if(Head.chessboard.chessman[i] == 0){
if(aFatherValue[i] > max){
max = aFatherValue[i];
Head.CoordinateAI = i; //给头结点中电脑应下的位置做标记 有利于返回结果
}
}
}
return Head.CoordinateAI;
}
//当某一方下棋后,判断结果
int judgeBoard(ChessBoard *chessboard){
int Co;
int judge[8][3] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
int x = 1;
int y = 2;
int valueX = 0;
int valueY = 0;
for(int i=0; i<=7; i++){
valueX =0;
valueY = 0;
for(int j=0; j<=2; j++){
Co = judge[i][j];
if(chessboard->chessman[Co] == 1){
valueX++;
}
if(chessboard->chessman[Co] == 2){
valueY++;
}
}
if(valueX == 3){
return x;
}
if(valueY == 3){
return y;
}
}
return 0;
}