第6讲 棋类游戏井字棋游戏人机对弈
基于极大极小分析法的井字棋对弈
基于极大极小分析法的井字棋对弈任务分析:首先,我们要知道,“井字棋”游戏(又叫“三子棋”),是一款十分经典的益智小游戏,想必很多玩家都有玩过。
“井字棋”的棋盘很简单,是一个3×3的格子,很像中国文字中的“井”字,所以得名“井字棋”。
“井字棋”游戏的规则与“五子棋”十分类似,“五子棋”的规则是一方首先五子连成一线就胜利;“井字棋”是一方首先三子连成一线就胜利。
游戏时一方是电脑,另一方是玩家。
所以,这类游戏在开始时有两种方式:一种是玩家先走;另一种是电脑先走。
这是我们要考虑的第一个问题。
其次,由于与玩家对战的是计算机,所以我们要编写一个过程,它可以使程序模拟人的思维与人下棋(其实就是“人工智能”的体现),这个过程也是本游戏的关键。
此外,我们还要编写两个过程,其一用来时刻判断棋盘中是否有三个棋子连成一线;其二用来判断如果有三个棋子连成一线,是哪一方连成一线的,即判断哪一方获胜。
如图所示为井字棋的一个格局,而格局之间的关系是由比赛规则决定的.通常,这个关系不是线性的,因为从一个棋盘格局可以派生出几个格局.例如图左侧所示的格局可以派生出5歌格局.例如图右侧所示,而从每一个新的格局又可派生出4个可能出现的格局.因此,若将从对弈开始到结束的过程中所有可能出现的格局都画在一张图上,则可以得到一颗倒长的”树”.图1 对弈问题中格局之间的关系设计思路设有九个空格,由MAX,MIN二人对弈,轮到谁走棋谁就往空格上放一只自己的棋子,谁先使自己的棋子构成“三子成一线”(同一行或列或对角线全是某人的棋子),谁就取得了胜利。
用叉号表示MAX,用圆圈代表MIN。
为了不致于生成太大的博弈树,假设每次仅扩展两层。
估价函数定义如下:设棋局—为P,估价函数为e(P)。
(1) 若P对任何一方来说都不是获胜的位置,则e(P)=e(那些仍为MAX空着的完全的行、列或对角线的总数)-e(那些仍为MIN空着的完全的行、列或对角线的总数。
人工智能 井字棋
人工智能井字棋学院:信息工程学院教师:罗会兰专业:计算机软件和理论学号:6120160090姓名:朱玲简述5月23日,当今世界围棋第一人柯洁与计算机围棋程序“阿尔法狗”(Alpha Go)的第一场比赛结束,“阿尔法狗”以四分之一子优势赢得首场胜利。
这场比赛双方耗时4小时17分37秒,其中柯洁用时2小时46分43秒,“阿尔法狗”用时1小时30分54秒。
除了围观和好奇,人类骨子里的不服输以及想要看看人工智能到底有多厉害的求胜欲促成了这一挑战。
面对人类棋手注定完败于人工智能的结局,人类要做好的准备是全面迎接而非拒绝人工智能,努力去掌控而非臣服于人工智能。
接纳人工智能是今天社会发展、经济增长、人类演化的必然,更是人们生活的需求。
其实,很多人每天离不开的智能手机就是低端人工智能的应用。
更应当看到的现实是,人工智能的发展极具竞争性,未来谁在人工智能的研发和应用中落后,谁就会被淘汰。
而井字棋游戏的诞生更是吸引着不同年龄段的人群,无论男女老少都可以玩,也都喜欢玩,而当前微型计算机已经是在广大人群中流行者,用电脑来下井字棋更是一种时尚。
现在网络上出现了各种各样的井字棋软件,有大师级的,新手级的等等。
这些都满足了不同人群的需要,所以当前井字棋越来越被许多人所熟悉。
目前的井字棋程序的发展也非常快,从最初的双人发展到人机,然后到现在的网络对战,已经受到越来越多人的喜爱和重视。
井字棋不但容易上手,而且它区别于别的游戏,它不但能使人娱乐,而且能使人的头脑变的更加聪明。
而井字棋有两种对战模式,一是人机对战,二十人人对战。
这些给人无限乐趣的用途正式人工智能的杰作。
正因为这样它鼓励着人们对它不断的研究,这在很大程度上促进了人工智能的发展,反过来人工智能的理论和技术上的突破能够使井字棋程序更加完美,更受欢迎。
这是一个具有简单功能的井字棋游戏。
本设计的主要完成的是井字棋的人机对弈问题,即计算机与人交替落子,当行、列或对角有连续三个以上(包括三个)相同一方棋时,则判定一方胜利,如果所有位置都已经下满,且没有哪一方赢棋,则为和局。
C语言实现井字棋游戏(人机对弈)
C语⾔实现井字棋游戏(⼈机对弈)井字棋游戏:即三⼦棋,英⽂名叫Tic-Tac-Tic,是⼀种在3*3格⼦上进⾏的连珠游戏,和五⼦棋⽐较类似,由于棋盘⼀般不画边线框,格线排成井字故得名。
题⽬分析:要完成该游戏的编写,我们需要先分析出完成整个游戏过程都需要⼲什么?1.⾸先,需要定义出⼀个3*3的棋盘,根据相关知识,我们可以以⼆维数组的⽅式将棋盘表⽰出来;2.棋盘定义出来后,需要将棋盘初始化,将3*3⼆维数组的每⼀个位置初始化为‘ ’(空格);3.有了棋盘,我们就可以开始进⾏下棋了,⾸先要确定是玩家先下还是电脑先下。
在这⾥我们规定玩家先下且玩家的下棋⽅式为‘x’,电脑下棋⽅式为‘o’;4.每⼀次下完棋后需要进⾏检测,判断该下棋位置是否合法、判断是否胜利等等。
根据上述分析,可以⼤致定义出以下函数窗⼝:void InitGame();//初始化游戏(棋盘)void PrintChess();//输出棋盘void PlayerMove();//玩家下棋void ComputerMove();//电脑下棋char CheckGameOver();//判断游戏是否结束(玩家胜/电脑胜/和棋)初始化棋盘:将3*3的⼆维数组棋盘的每个位置初始化为‘ ’void InitGame(){for (int i = 0; i < ROW; i++){for (int j = 0; j < COL; j++)chess_board[i][j] = ' ';}}输出棋盘:输出棋盘时,棋盘的风格可以根据⾃⼰的喜好来设计void PrintfChess()//输出棋盘,棋盘的设计可以根据⾃⼰的喜好设计{for (int i = 0; i < ROW; i++){printf("| %c | %c | %c |\n", chess_board[i][0], chess_board[i][1], chess_board[i][2]);if (i < ROW - 1)printf("|---|---|---|\n");}}玩家下棋:玩家输⼊下棋位置后,需要判断该位置是否合法、输⼊位置是否已被占⽤void PlayerMove()//玩家下棋{printf("玩家落⼦.\n");int row, col;while (1){printf("请输⼊⼀组坐标(下棋位置):>");scanf("%d %d", &row, &col);//检查坐标的有效性if (row < 0 || row > ROW || col < 0 || col > COL){printf("输⼊⾮法,请重新输⼊...");continue;}if (chess_board[row][col] != ' '){printf("输⼊的位置已被占⽤,请重新输⼊...");continue;}chess_board[row][col] = 'x';//x代表玩家下的棋break;}}电脑下棋:电脑下棋时,下棋的位置利⽤srand函数随机产⽣void ComputerMove()//电脑下棋{srand(time(0));while (1){int row = rand() % ROW;int col = rand() % COL;if (chess_board[row][col] != ' '){continue;}chess_board[row][col] = 'o';//o代表电脑下的棋break;}}检查棋盘:在检测棋盘时,分别判断⾏、列、对⾓线,在这⾥我规定:'x'代表玩家赢 'o'代表电脑赢 'h'代表和棋 'c'代表继续char CheckGameOver()//检测游戏是否结束{//检查⾏for (int i = 0; i < ROW; i++){if (chess_board[i][0] != ' '&& chess_board[i][0] == chess_board[i][1]&& chess_board[i][0] == chess_board[i][2])return chess_board[i][0];}//检查列for (int j = 0; j < COL; j++){if (chess_board[0][j] != ' '&& chess_board[0][j] == chess_board[1][j]&& chess_board[0][j] == chess_board[2][j])return chess_board[0][j];}//检查对⾓线if (chess_board[0][0] != ' '&& chess_board[0][0] == chess_board[1][1]&& chess_board[0][0] == chess_board[2][2])return chess_board[0][0];if (chess_board[0][2] != ' '&& chess_board[0][2] == chess_board[1][1]&& chess_board[0][2] == chess_board[2][0])return chess_board[0][2];//判断是否和棋if (ChessFull())return 'h';return 'c';}⾄此,主要的功能函数均已编写完毕,整个程序的流程如下所⽰:1.初始化棋盘;2.输出棋盘;3.玩家下棋;4.检测棋盘;5.电脑下棋;6.检测棋盘#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <time.h>#include <stdbool.h>#include <stdlib.h>#define START 1#define QUIT 0#define ROW 3#define COL 3static char chess_board[ROW][COL];//定义棋盘void StartGame();void InitGame();void PrintfChess();void PlayerMove();void ComputerMove();char CheckGameOver();bool ChessFull();int main(int argc, char* argv[]){int select = 1;while (select){printf("*********************\n");printf("* [1] Start Game *\n");printf("* [2] Over Game *\n");printf("*********************\n");printf("请选择:>");scanf_s("%d", &select);if (select == QUIT)break;if (select != START){printf("输⼊有错,请重新输⼊.....\n"); continue;}StartGame();}printf("GoodBye.....");return 0;}void StartGame(){char winner;//1 初始化游戏(棋盘)InitGame();//2 进⼊游戏while (1){//3 输出棋盘PrintfChess();//4玩家下棋PlayerMove();//5检查结果winner = CheckGameOver();if (winner != 'c')break;//6电脑下棋ComputerMove();//7检查结果CheckGameOver();winner = CheckGameOver();if (winner != 'c')break;}if (winner == 'x')printf("玩家赢.\n");printf("电脑赢.\n");if (winner == 'h')printf("和棋.\n");}void InitGame(){for (int i = 0; i < ROW; i++){for (int j = 0; j < COL; j++)chess_board[i][j] = ' ';}}void PrintfChess()//输出棋盘,棋盘的设计可以根据⾃⼰的喜好设计{for (int i = 0; i < ROW; i++){printf("| %c | %c | %c |\n", chess_board[i][0], chess_board[i][1], chess_board[i][2]); if (i < ROW - 1)printf("|---|---|---|\n");}}void PlayerMove()//玩家下棋{printf("玩家落⼦.\n");int row, col;while (1){printf("请输⼊⼀组坐标(下棋位置):>");scanf("%d %d", &row, &col);//检查坐标的有效性if (row < 0 || row > ROW || col < 0 || col > COL){printf("输⼊⾮法,请重新输⼊...");continue;}if (chess_board[row][col] != ' '){printf("输⼊的位置已被占⽤,请重新输⼊...");continue;}chess_board[row][col] = 'x';//x代表玩家下的棋break;}}void ComputerMove()//电脑下棋{srand(time(0));while (1){int row = rand() % ROW;int col = rand() % COL;if (chess_board[row][col] != ' '){continue;}chess_board[row][col] = 'o';//o代表电脑下的棋break;}}/** 'x'代表玩家赢* 'o'代表电脑赢* 'h'代表和棋* 'c'代表继续*/char CheckGameOver()//检测游戏是否结束{//检查⾏for (int i = 0; i < ROW; i++){if (chess_board[i][0] != ' '&& chess_board[i][0] == chess_board[i][1]&& chess_board[i][0] == chess_board[i][2])return chess_board[i][0];}//检查列for (int j = 0; j < COL; j++){if (chess_board[0][j] != ' '&& chess_board[0][j] == chess_board[1][j]&& chess_board[0][j] == chess_board[2][j])return chess_board[0][j];}//检查对⾓线if (chess_board[0][0] != ' '&& chess_board[0][0] == chess_board[1][1]&& chess_board[0][0] == chess_board[2][2])return chess_board[0][0];if (chess_board[0][2] != ' '&& chess_board[0][2] == chess_board[1][1]&& chess_board[0][2] == chess_board[2][0])return chess_board[0][2];//判断是否和棋if (ChessFull())return 'h';return 'c';}bool ChessFull(){for (int i = 0; i < ROW; i++){for (int j = 0; j < COL; j++){if (chess_board[i][j] == ' ')return false;}}return true;}运⾏测试图:程序的运⾏界⾯我们还可以利⽤system("cls")对界⾯进⾏优化,这样可以使界⾯更加美观。
井字棋策略
一、问题描述井字棋的棋盘是一个九宫格(即3×3的方格),因此通常可以在纸上画一个井字来做棋盘用,井字棋因此得名。
下棋时双方交替向棋盘上布子,每个棋子要落在尚无棋子的方格内。
棋子落下后不能移动,无吃子一说。
当其中任意一方有三个棋子连成一线(横向、纵向或斜向均可)时,即为“胜”,另一方为“负”。
如果棋盘上9个棋格都摆满了棋子,双方都没有连成一线的三子,即为“和棋”。
二、算法分析在对弈问题中,计算机操作的数据对象是每走一步棋后形成的棋盘状态(格局),对每一个格局来说,它的下一步棋都有若干不同的走法,这样一层一层就形成了一个状态空间树。
处于某一格局时,计算机又是如何选择走下一步棋呢? 当然是选择对自己有利的格局,而电脑是如何识别有利的格局?一般是使用一个估价函数,对每个格局进行“估价”,假设估价函数值越大,表示对电脑走棋越有利,那么,电脑在走下一步棋时,只要搜索出估价函数值最大的格局即可。
实际上,很难找到一个准确的函数来完全反映复杂的格局,但希望它尽可能的接近。
在井字棋中,如果计算机赢value = + 1 ,对手赢value = - 1 ,平局value = 0 ,而这些格局可作为博奕树的终端结点;对于非终端结点,电脑走棋会选估价函数值高的格局,当然对手走棋会选函数值低的格局,这样非终端结点的函数值就由其下层结点的这种最大最小交替递归调用得到,称为最小最大搜索算法。
在图1 中,格局B、C 因对手走一步棋即赢,函数值为- 1 ,格局E 因电脑走一步棋即赢,函数值为+ 1 ,格局G平局,函数值为0 ,格局F 为电脑下棋,函数值F = Max( G) = 0 ,格局D 为对手下棋,D =Min(E ,F) = 0 ,格局A 为电脑下棋,A =Max(B ,C) = 0。
下面给出这种最小最大搜索算法中,电脑和对手的走棋程序int comp ( Int &move){int i ,response ,p ;int value = - 2 ; //设临时最大值初始为- ∞if (full () ) return(0) ;//棋盘满为平局if (win-comp () ) return(1) ;//走一步棋,计算机赢for (i = 0 ;i < 9 ;i + + )//测试棋盘上所有方格if (chess[ i ] = = 0) //方格未落子{chess[ i ] = 1 ;//计算机下子为1response = human() ;chess[ i ] = 0 ;//恢复棋盘if (response > value){ value = response ;move = i ; }}return value ;}int human(int &move){int i ,response ,p ;int value = 2 ; //设临时最小值初始为+ ∞+if (full () ) return (0) ;if (win- human() ) return ( - 1) ; //走一步棋,对手赢for (i = 0 ;i < 9 ;i + + )if (chess[ i ] = = 0){chess[ i ] = 2 ; //对手下子为2response = comp (p) ;chess[ i ] [ j ] = 0 ; //恢复棋盘if (response < value){ value = response ;move = I ;}}return value ;}对于一些更加复杂的游戏,如国际象棋、跳棋、五子棋等,要想搜索到终端结点是很困难的,甚至是不可能的,我们可以往下搜索几层,把最低一层看成终端结点,其估价函数值根据对格局的分析近似得出。
Python游戏设计案例实战第9章 游戏实战篇——人机对战井字棋游戏
def main():
computer, human = pieces()
turn = X
board = new_board()
display_board(board)
while not winner(board):
#当返回False继续,否则结束循环
if turn == human:
move = human_move(board, human)
(2)否则,如果有一步棋可以让玩家在本轮获胜,就选那一步走。
(3)否则,电脑机器人应该选择最佳空位置来走。最佳位置就是中间 那个,第二好位置是四个角,剩下的就都算第三好的了。
9.3 对战井字棋游戏设计步骤
1.确定谁先走
#询问玩家你是否先走 def ask_yes_no(question):
response = None while response not in ("y", "n"): #如果输入不是"y", "n",继续重新输入
print("\n玩家你先走.") human = X computer = O else: print("\n电脑先走.") computer = X human = O return computer, human
9.3 对战井字棋游戏设计步骤
2.产生新的保存走棋信息列表和显示棋盘
#产生保存走棋信息列表board def new_board():
board[move] = computer if winner(board) == computer:
print("电脑下棋位置..." ,move) return move # 取消走棋方案 board[move] = EMPTY
Python游戏设计案例实战第9章 游戏实战篇——人机对战井字棋游戏
9.3 对战井字棋游戏设计步骤
3.产生可以合法走棋位置序列 #产生可以合法走棋位置序列(也就是还未下过子位置) def legal_moves(board):
moves = [] for square in range(9):
if board[square] == EMPTY: moves.append(square)
print("\n玩家你先走.") human = X computer = O else: print("\n电脑先走.") computer = X human = O return computer, human
9.3 对战井字棋游戏设计步骤
2.产生新的保存走棋信息列表和显示棋盘
#产生保存走棋信息列表board def new_board():
if board[i]==EMPTY: board2[i]=i
print("\t", board2[0], "|", board2[1], "|", board2[2]) print("\t", "---------") print("\t", board2[3], "|", board2[4], "|", board2[5]) print("\t", "---------") print("\t", board2[6], "|", board2[7], "|", board2[8], "\n")
return moves
9.3 对战井字棋游戏设计步骤
数据结构课程设计报告(井字棋)
目录一、设计课题名 (1)二、设计目的 (1)三、问题描述及需求分析 (1)四、概要设计 (1)五、详细设计 (1)六、测试数据及测试结果 (5)七、课程设计小结 (7)八、用户手册 (8)一、设计课题名井字棋(人机对弈)二、设计目的1、课程设计是《数据结构》课程教学必不可缺的一个重要环节;2、通过课程设计加深课堂教学内容的理解和巩固;3、将《数据结构》课程的教学内容与解决实际问题结合起来,培养理论联系实际的学风;4、提高程序设计能力、培养自学能力;5、提高分析问题、解决问题的能力;6、提高收集资料、查找参考书的能力;7、锻炼书写报告的能力。
三、问题描述及需求分析本设计的主要完成的是井字棋的人机对弈问题,即计算机与人交替落子,当行、列或对角有连续三个相同一方棋时,则判定一方胜利,若无此情形则为和局。
要完成此设计则需一判定胜负函数及一计算机自行落子函数,一旦这两个函数完成则此程序主要部分可完成。
四、概要设计完成此程序需一合理数据结构,因其为井字棋游戏程序则此结构中应包含一存储当前棋局的数组;又因计算机在判定在何位置落子最佳时,需一搜索树因而我在设计时设置了一PARENT域和CHILD域;除了主程序外,它还包括具有以下功能的函数:(1) 棋盘初始化函数:void Init();(2) 打印棋盘函数:void PrintQP();(3) 用户输入落子位置函数:void UserInput();(4) 判断当前棋局是否有一方获胜,并判断哪一方获胜的函数:int IsWin(State s);(5) 评估函数值计算函数:int e_fun(State s);(6) 极大极小值算法主函数:int AutoDone()。
五、详细设计设计步骤:(1) 选定算法;(2) 建立一个简单的应用程序(如字符界面程序)来测试算法;(3) 选定要实现的其他功能(如双人对弈、悔棋、难易级别选定、联机对战等);(4) 实现井字棋程序。
第6讲 棋类游戏-井字棋游戏人机对弈
10
3.2 程序中用到的资源
资源有:快捷键 位图 光标 快捷键、位图 光标、 快捷键 位图、光标 对话框、图标 菜单、字符串 图标、菜单 字符串、 对话框 图标 菜单 字符串 工具栏等。 工具栏
11
位图: IDB_BITMAP1:bmBlackNew.bmp位图,对应于黑棋 IDB_BITMAP1 棋子(玩家)。 IDB_BITMAP2:bmRedNew.bmp位图,对应于红棋 IDB_BITMAP2 棋子(计算机)。 菜单(非向导生成的菜单命令): ID_START:重新开始 ID_START ID_SAVE:保存游戏 ID_SAVE ID_LOAD:载入游戏 ID_LOAD ID_REGRET:悔棋 ID_REGRET ID_ComputerFirst:计算机先下 ID_ComputerFirst ID_Level:难度(易) ID_Level
//视图类自定义成员变量 //QP[i][j]为1表示该位置上是黑方(玩家)棋子, //为-1表示是红方棋子,为0表示没有棋子 int QP[3][3]; //存储棋盘状态 int pre_qp[3][3]; //存储上一步(指计算机和玩家各走了一步)棋盘状态,以便悔棋
8
其他表示游戏状态 游戏状态的成员变量。 游戏状态
5
三、程序界面采用的技术和方法
程序界面具有的特点: 程序界面 单文档应用程序(下一个案例,五子棋,也是单文档应 单文档应用程序 用程序),在视图中绘图。 能保存游戏 保存游戏,能载入游戏 载入游戏。 保存游戏 载入游戏 能悔棋 悔棋(但只能悔一步)。 悔棋 通过一个菜单命令 一个菜单命令来选择先下的两种选项 两种选项:计算机先 一个菜单命令 两种选项 下、玩家先下。 通过一个菜单命令 一个菜单命令来选择两种游戏难度 两种游戏难度:难、易。 一个菜单命令 两种游戏难度
井字棋(人机对战版)
井字棋(⼈机对战版)游戏介绍井字棋,英⽂名叫Tic-Tac-Toe,是⼀种在3*3格⼦上进⾏的连珠游戏,和五⼦棋类似。
然后由分别代表O和X的两个游戏者轮流在格⼦⾥留下标记(⼀般来说先⼿者为X),任意三个标记形成⼀条直线(包括⾏、列、对⾓线、反对⾓线),则为获胜。
解决策略重点在于电脑⽅如何下棋,我们采取估计棋局每个位置的权重,⾸先要对棋局进⾏分类。
---3个为空,重要性最低,权值设置为1 //视为暂时不管---2个空1个对⽅,重要性次低,权值为10 //⼀下三个区别不⼤,可⽐较随意的设置----1个空格1个对⽅1个⼰⽅,重要⾏较低,权值50 ----2个空格1个⼰⽅,重要性较⾼,权值为100---1个空格2个对⽅,重要性次⾼,权值500 //不堵住会输---1个空格2个⼰⽅,重要性最⾼,权值1000 //可以直接赢注意⼏点:1、权值之间的间距可以设⼤⼀点2、对每个空位置,权值等于⾏权值+列权值+对⾓线权值+反对⾓线权值,这4中权值都可以⽤上⾯的估算,但不做改进会出bug考虑如下情况:(1,3)-->(3,1)-->(1,1)-->(2,1)电脑就输了---->--->-->-->⼈获胜关键在于第⼆步,应该选择⼀个⾮⾓的位置,原因在于此时右上⾓位置的权值⼤于中上位置,分析权值的来源右上⾓时,10+10+100(对⾓线⼰⽅),⽽中上时,10+100(⾏⼰⽅),所以同样是2空1⼰⽅时,⼰⽅位于⾏或列的权重应⼤于⼰⽅位于对⾓线。
所以按⾏或列计算时,2空1⼰⽅的权值可改为200代码实现1 #include<stdio.h>2 #include<Windows.h>34const int ROW = 3;5const int COL = 3;6int chessboard[ROW][COL];7int score[ROW][COL];89void Initmap();10void Showmap(); //打印棋局11bool isWin(); //判断是否有⼀⽅获胜12bool isFull(); //判断棋盘是否为满13void PcPlay(); //电脑下棋14void HumanPlay(); //⼈下棋1516int main()17{18 Initmap();19 Showmap();20while ((!isFull()) && (!isWin()))21 {22 HumanPlay();23 system("cls");24 Showmap();25if (isWin())26break;2728 Sleep(500); //模拟实际过程,让电脑慢点,hh29 PcPlay();34if (isFull())35 printf("\n\n平局\n");3637 system("pause");38return0;39}4041void Initmap()42{43for (int i = 0; i < ROW; i++)44for (int j = 0; j < COL; j++)45 chessboard[i][j] = 1;46}4748void Showmap()49{50for (int i = 0; i < ROW; i++)51 {52for (int j = 0; j < COL; j++)53 {54if (chessboard[i][j] == 1) //"1"代表空55 printf("□");56if (chessboard[i][j] == 2) //"2"代表⼈57 printf("■");58if (chessboard[i][j] == 5) //"5"代表电脑59 printf("●");60 }61 printf("\n");62 }63}6465bool isWin()66{67int sum = 0;68for (int i = 0; i < ROW; i++) //对每⾏判断是否获胜 69 {70for (int j = 0; j < COL; j++)71 sum += chessboard[i][j];7273if (sum == 6)74 {75 printf("⼈获胜!\n");76return true;77 }78if (sum == 15)79 {80 printf("电脑获胜!\n");81return true;82 }83 sum = 0;84 }8586for (int j = 0; j < ROW; j++) //对每列判断是否获胜 87 {88for (int i = 0; i < COL; i++)89 sum += chessboard[i][j];9091if (sum == 6)92 {93 printf("⼈获胜!\n");94return true;95 }96if (sum == 15)97 {98 printf("电脑获胜!\n");99return true;100 }105 sum += chessboard[i][i];106if (sum == 6)107 {108 printf("⼈获胜!\n");109return true;110 }111if (sum == 15)112 {113 printf("电脑获胜!\n");114return true;115 }116117 sum = 0;118for (int i = 0; i < ROW; i++) //对反对⾓线判断是否获胜119 sum += chessboard[i][2 - i];120if (sum == 6)121 {122 printf("⼈获胜!\n");123return true;124 }125if (sum == 15)126 {127 printf("电脑获胜!\n");128return true;129 }130131return false;132}133134bool isFull()135{136for (int i = 0; i < ROW; i++)137for (int j = 0; j < COL; j++)138if (chessboard[i][j] == 1)139return false;140return true;141}142143void HumanPlay()144{145int x, y;146 printf("请输⼊棋⼦的横坐标X:");147 scanf_s("%d", &x);148 printf("请输⼊棋⼦的纵坐标Y:");149 scanf_s("%d", &y);150151while (x < 1 || x>3 || y < 1 || y>3)152 {153 printf("\n请正确输⼊!\n");154 printf("x,y均属于1~3\n\n");155156 printf("请输⼊棋⼦的横坐标X:");157 scanf_s("%d", &x);158 printf("请输⼊棋⼦的纵坐标Y:");159 scanf_s("%d", &y);160 }161162while (chessboard[3 - y][x - 1] != 1)163 {164 printf("\n\n该位置已被占⽤!\n");165 printf("请选择正确的位置\n\n");166 Sleep(1000);167168 printf("\n请输⼊棋⼦的横坐标X:");169 scanf_s("%d", &x);170 printf("请输⼊棋⼦的纵坐标Y:");171 scanf_s("%d", &y);176177void PcPlay()178{179int sum = 0;180for (int i = 0; i < ROW; i++)181for (int j = 0; j < COL; j++)182 score[i][j] = 0;183184// 对每⾏进⾏分数统计185for (int i = 0; i < ROW; i++)186 {187for (int j = 0; j < COL; j++)188 sum += chessboard[i][j];189190switch (sum)191 {192case3: //1+1+1;重要性:最低;权重:1193for (int k = 0; k < COL; k++)194 {195if (chessboard[i][k] == 1)196 score[i][k] += 1;197 }198break;199case4: //1+1+2;重要性:次低;权重:10 200for (int k = 0; k < COL; k++)201 {202if (chessboard[i][k] == 1)203 score[i][k] += 10;204 }205break;206case8: //1+2+5;重要性:较低,权值50207for (int k = 0; k < COL; k++)208 {209if (chessboard[i][k] == 1)210 score[i][k] += 50;211 }212break;213case7: //1+1+5;重要性:较⾼;权重:200 214for (int k = 0; k < COL; k++)215 {216if (chessboard[i][k] == 1)217 score[i][k] += 200; //把⾏列的重要性⽐对⾓线⾼218 }219break;220case5: //1+2+2;重要性:次⾼;权重:500 221for (int k = 0; k < COL; k++)222 {223if (chessboard[i][k] == 1)224 score[i][k] += 500;225 }226break;227case11: //1+5+5;重要性:最⾼;权重:1000 228for (int k = 0; k < COL; k++)229 {230if (chessboard[i][k] == 1)231 score[i][k] += 1000;232 }233break;234 }235 sum = 0;236 }237238// 对每列进⾏分数统计239for (int j = 0; j < COL; j++)240 {241for (int i = 0; i < ROW; i++)242 sum += chessboard[i][j];247for (int k = 0; k < COL; k++)248 {249if (chessboard[k][j] == 1)250 score[k][j] += 1;251 }252break;253case4:254for (int k = 0; k < COL; k++)255 {256if (chessboard[k][j] == 1)257 score[k][j] += 10;258 }259break;260case8:261for (int k = 0; k <262 COL; k++)263 {264if (chessboard[k][j] == 1)265 score[k][j] += 50;266 }267break;268case7:269for (int k = 0; k < COL; k++)270 {271if (chessboard[k][j] == 1) //1+1+5;重要性:较⾼;权重:200 272 score[k][j] += 200;273 }274break;275case5:276for (int k = 0; k < COL; k++)277 {278if (chessboard[k][j] == 1)279 score[k][j] += 500;280 }281break;282case11:283for (int k = 0; k < COL; k++)284 {285if (chessboard[k][j] == 1)286 score[k][j] += 1000;287 }288break;289 }290 sum = 0;291 }292293// 对对⾓线进⾏分数统计294for (int i = 0; i < ROW; i++)295 sum += chessboard[i][i];296switch (sum)297 {298case3:299for (int i = 0; i < COL; i++)300 {301if (chessboard[i][i] == 1)302 score[i][i] += 1;303 }304break;305case4:306for (int i = 0; i < COL; i++)307 {308if (chessboard[i][i] == 1)309 score[i][i] += 10;310 }311break;312case8:313for (int i = 0; i < COL; i++)319case7: //1+1+5;权重:100320for (int i = 0; i < COL; i++)321 {322if (chessboard[i][i] == 1)323 score[i][i] += 100;324 }325break;326case5:327for (int i = 0; i < COL; i++)328 {329if (chessboard[i][i] == 1)330 score[i][i] += 500;331 }332break;333case11:334for (int i = 0; i < COL; i++)335 {336if (chessboard[i][i] == 1)337 score[i][i] += 1000;338 }339break;340 }341342// 对反对⾓线进⾏分数统计343 sum = 0;344for (int i = 0; i < ROW; i++)345 sum += chessboard[i][2 - i];346switch (sum)347 {348case3:349for (int i = 0; i < COL; i++)350 {351if (chessboard[i][2 - i] == 1)352 score[i][2 - i] += 1;353 }354break;355case4:356for (int i = 0; i < COL; i++)357 {358if (chessboard[i][2 - i] == 1)359 score[i][2 - i] += 10;360 }361break;362case8:363for (int i = 0; i < COL; i++)364 {365if (chessboard[i][2 - i] == 1)366 score[i][2 - i] += 50;367 }368break;369case7:370for (int i = 0; i < COL; i++)371 {372if (chessboard[i][2 - i] == 1) //1+1+5;权重:100 373 score[i][2 - i] += 100;374 }375break;376case5:377for (int i = 0; i < COL; i++)378 {379if (chessboard[i][2 - i] == 1)380 score[i][2 - i] += 500;381 }382break;383case11:384for (int i = 0; i < COL; i++)390 }391392int maxRow = 0, maxCol = 0;393for (int i = 0; i < ROW; i++)394for (int j = 0; j < COL; j++)395 {396if (score[i][j] > score[maxRow][maxCol]) 397 {398 maxRow = i;399 maxCol = j;400 }401 }402 chessboard[maxRow][maxCol] = 5;403 }。
井字棋实验报告
井字棋实验报告篇一:井字棋实验报告课程:班别小组成员人工智能原理及其应用12商本学号及姓名指导老师实验02井字棋1、总体要求:1.1总体功能要求:利用不同的方法,实现人机对战过程中呈现出不同程度的智能特征:(1)利用极大极小算法、α-β剪枝来提高算法的效率。
(2)使用高级语言,编写一个智能井字棋游戏。
(3)结合极大极小算法的使用方法和α-β剪枝,让机器与人对弈时不但有智能的特征,而且计算的效率也比较高。
1.2.开发平台要求:开发者开发的软件必须能够在不同系统的电脑上正常运行,因此开发平台为:开发环境:JDK1.6开发工具和技术体系:为了此游戏能够很好的在不同系统中运行,因选择javaee进行开发,利用eclipse1.3项目管理要求:(1)项目程序编写过程中要适当的写一些注释,以便下次作业时能够快速的上手和以后的修改:(2)项目程序要保存在一个固定的工作区间;(3)确保代码不要太多冗余2、需求分析:2.1软件的用户需求:井字棋游戏的用户希望游戏除了有一般的功能之外,还可以通过极大极小算法、α-β剪枝等方法是的井字棋游戏能够拥有智能特征,并是的电脑在人机对弈的过程中因玩家的难度选择而体现不同程度的智能状况。
2.2软件的功能需求:本游戏需要实现功能有:(1)游戏的重新设置(2)游戏统计(如:人赢的次数、电脑赢的次数等)(3)游戏的退出(4)不同智能程度下(脑残、懵懂、正常、智能),人机对弈(5)既可以选择难度,也可以选择谁走第一步(人or电脑) 2.3软件的性能需求:井字棋游戏需要以图形界面的形式表现出来,通过点击图标就可以进入游戏;在游戏进行时,人机对弈时电脑能够快速的反应并根据人的上一步动作作出,通过选择“脑残、懵懂、正常、智能”难度选择,电脑以不同程度的智能与人进行游戏对弈。
2.4 运行环境:能够运行java程序的环境(装有jdk 或者jre)2.5 用户界面设计:用gridlayout进行用户界面的设计把界面中分为不同的模块。
最大最小算法,人机井字棋游戏
最⼤最⼩算法,⼈机井字棋游戏⼤概是5⽉份⼈⼯智能导论的作业。
(在这贴⼀下代码和总结报告)⼀、问题:实现井字棋游戏。
即玩家先⼿或后⼿与电脑进⾏井字棋游戏,使得电脑⽅总是获胜或是平局。
井字棋游戏:在⼀个空⽩的3*3棋盘内,两名玩家轮流落⼦。
若有⼀⽅的棋⼦中有3个棋⼦可连为⼀条线(横线、竖线或对⾓线),则游戏结束,该玩家胜利。
若棋盘上已没有地⽅可以落⼦,则游戏结束,双⽅平局。
⼆、原理:最⼤最⼩值法。
对于棋盘有⼀个估值函数。
对于⼀个局⾯,其估值越⼤,对⼀⽅(记作A)越有利;其估值越⼩,对另⼀⽅(记作B)越有利。
当A⽅⾏动时,必定希望他落⼦后局⾯的估值最⼤;当B⽅⾏动时,必定希望他落⼦后局⾯的估值最⼩。
假定双⽅⾜够聪明,他们就会将接下来的棋局情况模拟⼀遍,选出那个在双⽅都不发⽣失误情况下对⾃⼰最有利的⼀步。
在这个程序中,设定了这样的估值函数,如果横线、竖线或对⾓线中,有1个玩家⽅的棋⼦和2个空⽩格⼦那么估值+1;有2个玩家⽅的棋⼦和1个空⽩格⼦那么估值+5;有1个电脑⽅的棋⼦和2个空⽩格⼦那么估值-1;有2个电脑⽅的棋⼦和1个空⽩格⼦那么估值-5;有3个玩家⽅的棋⼦那么估值+1000;有3个电脑⽅的棋⼦那么估值-1000。
(最后两种情况估值的设定是为了判断输赢)。
三、实现在程序中玩家每⾛完⼀步,电脑就会模拟⾃⼰将棋⼦下在当前的某⼀个空⽩格上后,玩家与电脑都选择最优策略所能达到的最后局⾯的估值,在这些落⼦⽅案中选择⼀个最后估值分数最⼩的作为⾃⼰的落⼦⽅案。
如果存在多个最后估值分数最⼩的落⼦⽅案,就在他们中随机⼀个作为最终的落⼦⽅案。
四、代码#include<cstdio>#include<cstring>#include<algorithm>#include<time.h>#include<stdlib.h>using namespace std;int tim,f[15];void print()//输出当前棋盘{for (int i=0;i<9;i++){if (f[i]==0) printf("_ ");else if (f[i]==1) printf("O ");else if (f[i]==2) printf("X ");if ((i+1)%3==0) printf("\n");}printf("\n");return;}int re(int x,int y,int z)//⾏、列、对⾓线分别估分{int i,a[5],cnt1=0,cnt2=0;a[0]=x;a[1]=y;a[2]=z;for (i=0;i<3;i++)if (a[i]!=0){if (a[i]==1) cnt1++;else if (a[i]==2) cnt2++;}if (cnt2==0){if (cnt1==1) return1;//⼀个玩家棋⼦和两个空格的得分if (cnt1==2) return5;// 两个玩家棋⼦和⼀个空格的得分if (cnt1==3) return1000;//玩家获胜}else if (cnt1==0){if (cnt2==1) return -1;//同理,电脑棋⼦的情况if (cnt2==2) return -5;if (cnt2==3) return -1000;}return0;}int jud()//估值函数,分数越低对电脑越有利,越⾼对玩家越有利{int i,cnt=0,sc=0;for (i=0;i<3;i++){sc+=re(f[i],f[i+3],f[i+6]);sc+=re(f[i*3],f[i*3+1],f[i*3+2]);}sc+=re(f[0],f[4],f[8]);sc+=re(f[2],f[4],f[6]);//3⾏,3列,2条对⾓线,⼀共8种return sc;//返回当前局⾯得分}int dfs(int player)//电脑模拟接下来的棋局,找到在接下来玩家没有失误的情况下对玩家最不利的下法{//player:0玩家,1电脑int now=jud();//当前局势评分if (now>900 || now<-900) return now;//玩家已赢或已输int i,re,flag=1,ma=-999999,mi=999999;for (i=0;i<9;i++)//枚举每种落⼦情况if (!f[i]){flag=0;f[i]=player+1;re=dfs(player^1);//递归f[i]=0;ma=max(re,ma);mi=min(re,mi);//接下来的最⾼/低评分}if (flag) return now;//flag==1代表棋盘已满if (player==0) return ma;//如果此时是玩家的回合,就选择评分最⾼的局⾯return mi;//如果此时是电脑的回合,就选择评分最低的局⾯}void player_(){int r_flag=1,x,y,k;printf("轮到你了,请输⼊棋⼦坐标x和y(0<=x,y<=2)\n");while (r_flag){scanf("%d%d",&x,&y);k=x*3+y;if (f[k] || x>2 || y>2 || x<0 || y<0) printf("⽆效输⼊,请重新输⼊\n");else r_flag=0;}f[k]=1;tim++;print();return;}void computer_(){int mi=999999,note[15],tot=0,i,now;for (i=0;i<9;i++)//枚举电脑的落⼦if (!f[i]){f[i]=2;if (jud()<-900){note[++tot]=i;break;}now=dfs(0);if (now<mi) tot=0,note[++tot]=i,mi=now;else if (now==mi) note[++tot]=i;f[i]=0;}now=note[rand()%tot+1];f[now]=2;tim++;printf("轮到电脑,棋⼦坐标%d,%d\n",now/3,now%3);print();return;}int play(){while (tim<9){player_();if (jud()>900) return1;//玩家获胜if (tim==9) break;computer_();if (jud()<-900) return0;//电脑获胜}return2;//平局}int main(){int i,op,fin;srand((unsigned)time(NULL));while (1){for (i=0;i<9;i++) f[i]=0;//每次游戏前清空棋盘tim=0;//时间重置为零printf("你想要先⼿(1)或后⼿(2)?\n");scanf("%d",&op);while (op!=1 && op!=2){printf("⽆效输⼊,请输⼊先⼿(1)或后⼿(2)\n");scanf("%d",&op);}if (op==2) computer_();else print();fin=play();if (fin==1) printf("你赢了\n");else if (fin==0) printf("你输了\n");else if (fin==2) printf("平局\n");printf("再来⼀局吗?是(1) or 否(0) \n");scanf("%d",&op);if (op==0) return0;else if (op!=1) printf("⽆效输⼊,那么我假设你想要再来⼀局\n"); }return0;}五、运⾏时截图⼀种玩家先⼿,电脑获胜的情况,如下图所⽰。
人工智能井字棋
实验报告课程名称:人工智能实验名称:井字棋学院:专业班级:学生姓名:学号:」、实验目的:(1)了解极大极小算法的原理和使用方法,并学会用a-B剪枝来提高算法的效率。
(2)使用C语言平台,编写一个智能井字棋游戏。
(3)结合极大极小算法的使用方法和a - B剪枝,让机器与人对弈时不但有智能的特征,而且计算的效率也比较高。
二、设计思想:井字棋是一个流传已久的传统游戏。
游戏由两个人轮流来下,分别用“X ”和“ 0”来代替自身的棋子。
棋盘分9个格,双方可以在轮到自己下的时候,可以用棋子占领其中一个空的格子。
如果双方中有一方的棋子可以连成一条直线,则这一方判胜,对方判负。
当所有的格子都被占领,但双方都无法使棋子连成一条直线的话,则判和棋。
这是一个智能型的井字棋游戏,机器可以模拟人与用户对弈。
当轮到机器来下的时候,机器会根据当前棋局的形势,利用极大极小算法算出一个评价值,判断如何下才对自身最有利,同时也是对方来说对不利的,然后下在评价值最高的地方。
另外利用a - B剪枝,使机器在搜索评价值的时候不用扩展不必要的结点,从而提高机器计算的效率。
在用户界面方法,用一个3X3的井字格来显示用户与机器下的结果。
当要求用户输入数据的时候会有提示信息。
用户在下的过程中可以中途按下“0”退出。
当用户与计算机分出了胜负后,机器会显示出比赛的结果,并按任意键退出。
如果用户在下棋的过程中,输入的是非法字符,机器不会做出反应。
三、程序主要流程(1)主函数部分:(一)打印出欢迎信息,提示用户输入是否先下,如果用户选择先下,跳到第二步,否则,跳到第三步。
(二)调用man()。
(三)调用com(),判断棋局是否分出胜负。
判断是否分出了胜负,是的话跳到第五步。
(四)调用man(),判断棋局是否分出胜负。
判断是否分出胜负,是的话跳到第五步。
否则跳到第三步。
(五)打印棋盘和比赛结果,退出程序。
(2)Man()函数部分(一)、让用户选择要下的位置,判断用户下完是否已经取胜。
C语言版井字棋
十五、井字棋【问题描述】设计一个井字棋的游戏程序【基本要求】游戏规则是:从一个空的棋盘开始,人为x一方,计算机为o一方,人机双方轮流放置棋子,人下的时候,字符x将被放入棋盘中指定的位置,轮到计算机下时,程序将扫描棋盘,并将字符o放入扫描到的第一个空格,某一方有3枚棋子占据了一横行、一竖行或一对角线则获胜,若整个棋盘被占满还没有一方获胜则为和局。
截图:代码://@author GXU-pengcheng#include<stdio.h>#include<windows.h>#include<conio.h>void Help();//帮助int Play(char player,int choice);//对弈void Init();//初始化棋盘void Display();//打印棋盘void Black(int choice);//黑棋void White(int choice);//白棋void Block(int choice);//添加选择框void Clear(int choice);//清空之前的选择框int Judge(int choice,char symbol);//判断输赢返回值0为无结果,1为获胜,2为平局int Funcx(int choice);//将标号转换为行号int Funcy(int choice);//将标号转换为列号void End(char symbol);//结束int Found();//返回第一个没有棋子的位置的编号char a[31][64];//用数组存放棋盘和棋子,a[行][列]int b=0;//棋子个数int main(){char player;int choice;system("title 井字棋");//设置标题system("mode con cols=64 lines=35");//设置窗口大小system("color 70");//设置颜色while(1){printf("\n\n\n\n\n\n\t\t\t井\t字\t棋");printf("\n\n\n\n\n\n\n\n\t\t\t1. 玩家先手\n\n\t\t\t2. 电脑先手\n\n\t\t\t3. 帮助\n\n\t\t\t4. 退出\n\n\n\n\n\t\t请输入: ");player=getch();if(player=='1'){Init();Block(5);choice=5;Play(player,choice);}else if(player=='2'){Init();Play(player,choice);}else if(player=='3'){Help();getch();system("cls");continue;}else if(player=='4'){return 0;}else{printf("\n\n\t\t 输入错误请重新输入!");Sleep(1000);system("cls");continue;}}return 0;}void Help(){system("cls");printf("\n\n\n\n\n\n\n\n\n\t\t\t 帮助\n\n\n");printf("\t 'W'上移, 'S'下移, 'A'左移, 'D'右移\n\n");printf("\t\t 游戏中按'4'退出");printf("\n\n\n\n\t\t 按任意键退出");}int Play(char player,int choice){//对弈char get;char symbol;int c=0;//Judge得出的结果while(1){system("cls");//每次循环清屏一次Display();if(player=='1'){//玩家下棋while(1){//确定要下的位置if((get=getch())!=' '){if(get=='4'){system("cls");return 0;}else if( (get=='w'||get=='W') &&choice-3>=1){Clear(choice);choice =choice-3;}else if((get=='s'||get=='S')&&choice+3<=9){Clear(choice);choice = choice+3;}else if((get=='a'||get=='A')&&(choice+2)/3==(choice+1)/3){Clear(choice);choice -= 1;}else if((get=='d'||get=='D')&&(choice-1)/3==choice/3){Clear(choice);choice += 1;}else{continue;}Block(choice);system("cls");Display();}else{if(a[((choice-1)/3)*10+2][((choice-1)%3)*21+4]!=' '){printf("该位置已有其他棋子!");continue;}else{Clear(choice);break;}}}//while结束b++;Black(choice);player='0';symbol='#';}//if结束else{//电脑下棋choice=Found();Block(choice);b++;White(choice);player='1';symbol='*';}if((c=Judge(choice,symbol))!=0){//判断输赢if(c==2)symbol='=';c=0;End(symbol);break;}}return 0;}void Init(){//初始化棋盘int x=0,y=0;int i='1';for(x=0;x<31;x++){for(y=0;y<64;y++){if((y==Funcy(1)||y==Funcy(2)||y==Funcy(3)||y==Funcy(2)+Funcy(3)))if(x==Funcx(1)||x==Funcx(4)||x==Funcx(7)||x==Funcx(4)+Funcx(7))a[x][y]='+';elsea[x][y]='|';}else if(x==Funcx(1)||x==Funcx(4)||x==Funcx(7)||x==Funcx(4)+Funcx(7)) a[x][y]='-';elsea[x][y]=' ';}}//for(x=1;x<=7;x=x+3)//在每个格子的左上角添加序号,范围1~9//{// for(y=1;y<=3;y++)// {// a[(Funcx(x)+1)][(Funcy(y)+1)]=i;// i++;// }//}}void Display(){//打印棋盘int x=0,y=0;for(x=0;x<31;x++){for(y=0;y<64;y++){printf("%c",a[x][y]);}}}void Block(int choice){//添加选择框int x,y;for(x=Funcx(choice)+1;x<Funcx(choice)+10;x++){for(y=Funcy(choice)+2;y<Funcy(choice)+20;y++)if(x==Funcx(choice)+1||x==Funcx(choice)+9){if(y==Funcy(choice)+2||y==Funcy(choice)+19)a[x][y]='+';else if(y<Funcy(choice)+7||y>Funcy(choice)+14)a[x][y]='-';else if(x<Funcx(choice)+4||x>Funcx(choice)+6)if(y==Funcy(choice)+2||y==Funcy(choice)+19)a[x][y]='|';}}void Clear(int choice){//清空选择框int x,y,i;for(i=1;i<=9;i++){if(a[Funcx(choice)+1][Funcy(choice)+2]=='+'&&i!=choice){for(x=Funcx(choice)+1;x<Funcx(choice)+10;x++){for(y=Funcy(choice)+2;y<Funcy(choice)+20;y++)if(x==Funcx(choice)+1||x==Funcx(choice)+9){if(y==Funcy(choice)+2||y==Funcy(choice)+19)a[x][y]=' ';else if(y<Funcy(choice)+7||y>Funcy(choice)+14)a[x][y]=' ';}else if(x<Funcx(choice)+4||x>Funcx(choice)+6)if(y==Funcy(choice)+2||y==Funcy(choice)+19)a[x][y]=' ';}}}}void Black(choice){//添加黑棋int x,y;for(x=Funcx(choice)+2;x<Funcx(choice)+9;x++){for(y=Funcy(choice)+4;y<Funcy(choice)+18;y++)if(x==Funcx(choice)+2||x==Funcx(choice)+8)a[x][y]='#';else if(y==Funcy(choice)+4||y==Funcy(choice)+17)a[x][y]='#';}}void White(choice){//添加白棋int x;int d=4;for(x=Funcx(choice)+2;x<=Funcx(choice)+8;x++){a[x][Funcy(choice)+d]='*';a[x][Funcy(choice)+20-d]='*';d=d+2;}}int Judge(int choice,char symbol){//判断输赢返回值0为无结果,1为获胜,2为平局if(((a[Funcx(choice)+2][Funcy(choice)+4]==a[Funcx(choice+3)+2][Funcy(choice)+4]&&a[Funcx(choice+3)+2][Funcy(choice)+4]==a[Funcx(choice+6)+2][Funcy(choice)+4])||(a[Funcx(choice)+2][Funcy(choice)+4]==a[Funcx(choice)+2][Funcy(choice+1)+4]&&a[Funcx(choice)+2][Funcy(choice+1)+4]==a[Funcx(choice)+2][Funcy(choice+2)+4]))||a[Funcx(5)+2][Funcy(5)+4]==symbol&&((a[Funcx(1)+2][Funcy(1)+4]==a[Funcx(5)+2][Funcy(5)+4]&&a[Funcx(5)+2][Funcy(5)+4]==a[Funcx(9)+2][Funcy(9)+4])||(a[Funcx(3)+2][Funcy(3)+4]==a[Funcx(5)+2][Funcy(5)+4]&&a[Funcx(5)+2][Funcy(5)+4]==a[Funcx(7)+2][Funcy(7)+4])))return 1;if(b==9)return 2;return 0;}int Funcx(int choice){//将标号转换为行号return (((choice-1)/3)%3)*10;}int Funcy(int choice){//将标号转换为列号return ((choice-1)%3)*21;}void End(char symbol){//结束system("cls");Display();if(symbol=='*')printf("\t\t\t 电脑胜利!\n\n");else if(symbol=='#')printf("\t\t\t 玩家胜利!\n\n");elseprintf("\t\t\t 平局!\n\n");b=0;printf("\t\t\t按任意键返回菜单");getch();system("cls");}int Found(){//返回第一个没有棋子的位置的编号int i;for(i=1;i<=9;i++){if(a[Funcx(i)+2][Funcy(i)+4]==' ')return i;}}。