一字棋c语言实现

#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; 
}

你可能感兴趣的:(人工智能)