精华内容
下载资源
问答
  • 井子棋是棋类中最简单的一种,通常作为算法的练手项目,该资源使用极小极大算法实现了一个井字棋的人机对弈,只需运行资源里的play_to_bot就可以在命令行里与AI对弈了,可以肯定的是你绝对不可能战胜它。虽然实现它...
  • 创新学井字棋AI

    2015-10-27 19:37:15
    极小极大算法,估值,博弈树 Alpha-Beta搜索 井字棋算法详细分析
  • 1)包含的2个的样例,实现了三连棋(井字棋)游戏,含AI算法。 2) 样例运用C++语言, 使用QT 这个跨平台的C++图形用户界面应用程序框架 ,用来开发图形用户界面(GUI)程序的初始界面。 3)实现人机博弈,有人机...
  • AI井字棋游戏

    2019-01-23 10:03:43
    使用深度优先算法实现的图形化井字棋AI游戏,并利用α-β裁剪进行优化
  • 基于qt实现的三连,包括初始界面,有人机对战和双人对战,人机对战采用min-max搜索来实现,代码量较小,适合新手学习。
  • python实现AI井字棋极大极小算法和Alpha-beta算法程序设计思路主要步骤和代码对于两个算法流程图运行结果 程序设计思路 大致思路: 井字棋最后的结果无非就是玩家赢、电脑赢和平局三种结果,而最后的结果正对应这整...

    python实现AI井字棋极大极小算法和Alpha-beta算法

    程序设计思路

    大致思路:
    井字棋最后的结果无非就是玩家赢、电脑赢和平局三种结果,而最后的结果正对应这整棵棋盘生成树的叶子节点,那么可以把玩家赢、电脑赢和平局三种结果赋值,然后根据当前深度是Max层还是Min层来,往上推出该子节点的父子节点的值,一直往上走到根节点,这也正是极大极小搜索的一个过程,而alpha-beta算法只要在极大极小上加以修改即可。

    主要步骤和代码

    1、 棋盘:用一个长度为9的数组存储每一位的字符,其中空位为‘-’,玩家棋子默认为‘O’,电脑玩家默认为‘#’,该数组为全局变量;定义print_board()函数来输出当前棋盘状况;定义reset_board()函数来重置棋盘;
    2、 先手问题:定义一个变量first,根据输入来定义先手,输入1为玩家先手,输入-1为电脑先手;

    first=0#先手变量,玩家先手为1,电脑先手为-1
    board_list=['-' for i in range(9)]#棋盘位置以数组存储
    
    #重置棋盘
    def reset_board():
        global board_list#将其定义成全局变量
        board_list=['-' for i in range(9)]
    
    #输出棋盘
    def print_board():
        print("棋盘:")
        for i in range(1,10):
            if i%3==0:
                print(board_list[i-1])
            else:
                print(board_list[i-1],end="")
        return board_list
    

    3、 胜者判断:定义check_win( )函数来判断当前是否有练成一线的情况,胜利的情况有8种,水平线3种,竖直线3种,斜线2种,根据位置的下标加以判断;定义winner( )函数判断赢家,如果是玩家先手,则玩家赢赋值为1,电脑赢为-1,平局为0;如果是电脑赢,则电脑赢赋值为1,玩家赢为-1,平局为0,这样可以方便Max和Min的区别;

    #判断胜负
    def check_win(tag):
        return ((board_list[0] == tag and board_list[1] == tag and board_list[2] == tag) or # 顶水平连线
        (board_list[3] == tag and board_list[4] == tag and board_list[5] == tag) or # 中间水平连线
        (board_list[6] == tag and board_list[7] == tag and board_list[8] == tag) or # 底部水平连线
        (board_list[0] == tag and board_list[3] == tag and board_list[6] == tag) or # 左侧垂直连线
        (board_list[1] == tag and board_list[4] == tag and board_list[7] == tag) or # 中间垂直连线
        (board_list[2] == tag and board_list[5] == tag and board_list[8] == tag) or # 右侧垂直连线
        (board_list[0] == tag and board_list[4] == tag and board_list[8] == tag) or # 左斜线
        (board_list[2] == tag and board_list[4] == tag and board_list[6] == tag)) # 右斜线
    
    #判断赢家
    def winner():
        '''
        当玩家先手时,max为玩家,所以返回1表示玩家赢,返回-1表示电脑赢,返回0表示平局或者还没结束;
        当电脑先手时,max为电脑,所以返回1表示电脑赢,返回-1表示玩家赢,返回0表示平局或者还没结束。
        '''
        if check_win('O')==True and first==1 or check_win('X') and first==-1:
            return 1
        elif check_win('X')==True and first==1 or check_win('O') and first==-1: 
            return -1
        else:
            return 0
    

    4、 玩家下棋:定义player( )函数来实现玩家下棋,通过输入位置0-8来下自己想要下的位置,同时也需要判断下得位置是否能下;

    #玩家下棋
    def player():
        while(1):
            print("输入想要走的位置,0-8:")
            number=int(input())
            if board_list[number]=='-':
                board_list[number]='O'
                break
            else:
                print("该位置有棋子!请输入数字0-8!")
                continue   
    

    5、 极大极小算法:定义max_min_search( )函数实现极大极小算法。把玩家赢、电脑赢和平局三种结局的赋值当作当前叶子节点的评估值,然后根据当前深度是Max层还是Min层来,往上推出该子节点的父子节点的值,一直往上走,这一过程可以通过递归函数生成。比如玩家先手下了一个棋子,那么轮到电脑时,电脑调用极大极小算法,把剩下每个空位的值给算出来,然后比较选出这些位置中算出值最小的一个位置,而这计算空位的值时,电脑会自行模拟玩家选择当前最优的一步,这样自己交替下棋,完成一个棋盘的整个下棋动作。

    #极大极小值算法
    def max_min_search(player,nextplayer):
        '''
        通过递归,从叶子节点,推出父子节点(即往上推出)的值,该树的取值只有三种要么1,要么-1,要么0。
        player:当前玩家;
        nextplayer:下一个玩家;
        '''
        global first
        max_val=-2
        min_val=2
        win=winner()
        #如果是叶子节点,即最后棋局结果,就返回胜利者的值
        if win!=0:
            return win
        #如果下满没有赢家,为平局
        elif '-' not in board_list:
            return 0
        #如果不是叶子节点,则通过叶子节点来推出当下节点的值。遍历当前所有能下的位置,找到这层节点中最大或者最小的值。
        for left_index in range(len(board_list)):
            if board_list[left_index]=='-':
                board_list[left_index]=player
                val=max_min_search(nextplayer,player)
                board_list[left_index]='-'#还原
                if player=='O' and first==1 or player=='X' and first==-1:
                    if max_val<val:
                        max_val=val
                elif player=='X' and first==1 or player=='O' and first==-1:
                    if min_val>val:
                        min_val=val
        #需要对先手情况进行判断,先手返回的是max,后手返回的是min,然后将最大或者最小的值传给父子节点
        if player=='O' and first==1 or player=='X' and first==-1:
            reval=max_val
        elif player=='X' and first==1 or player=='O' and first==-1:
            reval=min_val
        return reval
    

    6、 Alpha-beta算法:定义alpha_beta_search( )函数实现Alpha-beta算法。在极大极小算法的基础上,加入alpha和beta来进行剪枝,因为这里三种结果的赋值为-1、0、1,这里设置alpha初始值为-2,beta值为2;如果当前子节点的父子节点为Min层,那么根据第一个子节点得出beta值下界,如果后面子节点比beta大则进行剪枝不再往下深究,如果后面子节点有比beta小的则更新beta的值,最后把全部子节点筛选完,父子节点就为beta值;如果当前子节点的父子节点为Max层,那么根据第一个子节点得出alpha值上界,如果后面子节点有比alpha小则进行剪枝,不再往下进行深究,alpha大的值则更新alpha,最后把全部子节点筛选完,父子节点就是alpha值。

    #alpha-beta算法
    def alpha_beta_search(player,nextplayer,alpha,beta):
        global first
        win=winner()
        if win!=0:
            return win
        elif '-' not in board_list:
            return 0
        for left_index in range(len(board_list)):
            if board_list[left_index]=='-':
                board_list[left_index]=player
                val=alpha_beta_search(nextplayer,player,alpha,beta)
                board_list[left_index]='-'
                if player=='O' and first==1 or player=='X' and first==-1:
                    if alpha<val:
                        alpha=val
                    if alpha>=beta:
                        return beta #直接返回当前的最大值beta,进行剪枝
                elif player=='X' and first==1 or player=='O' and first==-1:
                    if beta>val:
                        beta=val
                    if beta<=alpha:
                        return alpha #直接返回当前的最小值beta,进行剪枝
        #需要对先手情况进行判断,先手返回的是max,后手返回的是min,然后将最大或者最小的值传给父子节点
        if player=='O' and first==1 or player=='X' and first==-1:
            reval=alpha
        elif player=='X' and first==1 or player=='O' and first==-1:
            reval=beta
        return reval
    

    7、 电脑下棋:定义一个computer( )函数来实现电脑下棋,通过调用max_min_search( )或者alpha_beta_search( ),来推算出当前最优的下棋位置。这个推算过程中,电脑也来模拟人下棋,也是调用极大极小算法或者alpha-beta算法,算出当前对玩家最优位置。假设玩家先手走了第一部棋子,电脑把剩下的空位都走一遍第二步棋,电脑自行模拟玩家走第三步棋子,也是调用相应算法得出当前玩家最优的位置,这样轮流走到最后结果,然后电脑选出最后局面中对自己最优的结果,回溯得到第二步棋子应该下什么(假设玩家先手下了第一步棋)。

    #电脑决定下棋位置
    def computer():
        '''
        best_val:用来记录先手为玩家时,电脑取min时,能取的最小值
        best_val2:用来记录先手为电脑时,电脑取max时,能取的最大值
        my_moves:用来记录电脑能走的位置
        '''
        best_val=2
        best_val2=-2
        my_moves=[]
        for index in range(len(board_list)):
            if board_list[index]=='-':
                board_list[index]='X'
                val=max_min_search('O','X')
                #val=alpha_beta_search('O','X',-2,2)
                board_list[index]='-'
                if first==1:
                    if val < best_val:
                        best_val=val
                        my_moves=[index]
                    elif val==best_val:
                        my_moves.append(index)
                elif first==-1:
                    if val > best_val2:
                        best_val2=val
                        my_moves=[index]
                    elif val==best_val2:
                        my_moves.append(index) 
        print(my_moves)              
        return random.choice(my_moves)
    

    8、主函数:

    def main():
        while(1):
            global first
            while(1):
                first=int(input('选择是先手对象,如果选择玩家则输入1,选择电脑输入-1,退出输入0:'))
                if first==-1 or first==1 or first==0:
                    next_move=first
                    break
                else:
                    print('输入错误!重新输入!')
                    continue
            if next_move==0:
                break
            while '-' in board_list and winner()==0:
                print_board()
                if next_move==1 and '-' in board_list:
                    player()
                    next_move=-1
                if next_move==-1 and '-' in board_list:
                    computer_move=computer()
                    board_list[computer_move]='X'
                    next_move=1
                    print('电脑走了'+str(computer_move))
            print_board()
            if first==1:
                print(["电脑赢了", "平局", "你赢了"][winner()+1])
            else:
                print(["你赢了", "平局", "电脑赢了"][winner()+1])
            reset_board()
    
    main()
    

    对于两个算法流程图

    根据个人理解手写的,写得不好多见谅!如果实在理解不了可以在csdn再搜索,挺多的!
    在这里插入图片描述
    在这里插入图片描述

    运行结果

    结果挺多的,在这里我就贴一张极大极小算法玩家先手的情况:
    电脑胜利:
    在这里插入图片描述
    平局:
    在这里插入图片描述

    展开全文
  • 目录 井字棋游戏 准备的HTML: 准备的CSS: 第一部分点击出现O的JS... 现阶段效果: ...第四部分:之前我们很容易就能击败AI,所以现在要强化AI的难度 ...学习来源:JavaScript井字棋游戏开发与AI算法 井字棋游戏 ...

    目录

    井字棋游戏

    准备的HTML:

    准备的CSS:

    第一部分点击出现O的JS代码:

    现阶段效果:

    第二部分:判断胜利

    现阶段结果:

    第三部分:简单的智能AI

    现阶段结果:

    第四部分:之前我们很容易就能击败AI,所以现在要强化AI的难度

    完整JavaScript代码:

    结果:不多说了,还没赢过😂

    学习来源:JavaScript井字棋游戏开发与AI算法


     

    井字棋游戏

    当初在高中的时候课间无聊经常和同学会下井字棋游戏,突然想做一下有一个智能陪玩的井字棋游戏。

    然后就发现AI算法好难啊╭( ̄▽ ̄)╯╧═╧,放弃......

    去网上找找,发现了一个讲解比较详细的井字棋游戏搭建\(@^0^@)/

    做好之后,结果就没赢过了`(+﹏+)′

    ps:算法真的是惨无人道啊

    准备的HTML:

    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<link rel="stylesheet" type="text/css" href="css/jingzi.css"/>
    	</head>
    	<body>
    		<table>
    			<tr>
    				<td class="cell" id="0"></td>
    				<td class="cell" id="1"></td>
    				<td class="cell" id="2"></td>
    			</tr>
    			<tr>
    				<td class="cell" id="3"></td>
    				<td class="cell" id="4"></td>
    				<td class="cell" id="5"></td>
    			</tr>
    			<tr>
    				<td class="cell" id="6"></td>
    				<td class="cell" id="7"></td>
    				<td class="cell" id="8"></td>
    			</tr>
    		</table>
    		<div class="endgame">
    			<div class="text"></div>
    		</div>
    		<button onclick="startGame()">重新开始</button>
    		<script src="js/jingzi.js" type="text/javascript" charset="utf-8"></script>
    	</body>
    </html>
    

    准备的CSS:

    *{
    	margin: 0;
    	padding: 0;
    }
    
    td {
    	border: 2px solid #333;
    	width: 100px;
    	height: 100px;
    	text-align: center;
    	vertical-align: middle; //垂直	
    	font-family: "微软雅黑";
    	font-style:italic; 
    	font-size: 70px;
    	cursor: pointer; //光标属性
    }
    
    table {
    	/*margin: 30px auto;*/
    	position: absolute;
    	left: 40%;
    	top: 100px;
    	border-collapse: collapse;
    }
    /*去除最外部边框*/
    
    table tr:first-child td{
    	border-top: 0;
    }
    
    table tr:last-child td{
    	border-bottom: 0;
    }
    
    table tr td:first-child{
    	border-left: 0;
    }
    
    table tr td:last-child{
    	border-right: 0;
    }
    
    .endgame{
    	display: none;
    	width: 200px;
    	height: 120px;
    	background-color: rgba(205,132,65,0.8);
    	position: absolute;
    	left: 40%;
    	top:180px;
    	margin-left: 50px;
    	text-align: center;
    	border-radius: 5px;
    	color: white;
    	font-size: 2em;
    }
    

    第一部分点击出现O的JS代码:

    const winCombos =[
    	[0, 1, 2],
    	[3, 4, 5],
    	[6, 7, 8],
    	[0, 3, 6],
    	[1, 4, 7],
    	[2, 5, 8], 
    	[0, 4, 8],
    	[6, 4, 2]
    ]
    /*获取元素*/
    const cells = document.querySelectorAll(".cell");
    startGame();
    
    function startGame(){
    	document.querySelector(".endgame").style.display="none";
    	//设置阵列点  创建9个数组元素,元素的键0到8
    	origBoard = Array.from(Array(9).keys());
    //	console.log(origBoard);
    	for (var i = 0; i < cells.length; i++) {
    		//把文本先设置为空
    		cells[i].innerHTML = "";
    		//删除属性知道已经有人赢了
    		cells[i].style.removeProperty('background-color');
    		//点击方块
    		cells[i].addEventListener('click',turnClick,false);
    	}
    }
    
    function turnClick(square){
    	//控制台点击日志
    //	console.log(square.target.id);
    	//人类玩家点击
    	turn(square.target.id,huPlayer);
    }
    //参数是方块ID,播放器
    function turn(squareId,player){
    	//这些板阵列数组将属于玩家
    	origBoard[squareId] = player;
    	document.getElementById(squareId).innerHTML = player;
    
    }

    现阶段效果:

     

    第二部分:判断胜利

    /*1. Basic setup  一些变量并添加能力
    2. Determine winner  添加逻辑,获胜者并展示
    3. Basic AI and winner notificatior  创建一个基本AI
    4. Minimax a lgori thm !*/
    
    var origBoard;
    const huPlayer = 'O';
    const aiPlayer = 'X';
    /*胜利的线组,包括对角线*/
    const winCombos =[
    	[0, 1, 2],
    	[3, 4, 5],
    	[6, 7, 8],
    	[0, 3, 6],
    	[1, 4, 7],
    	[2, 5, 8], 
    	[0, 4, 8],
    	[6, 4, 2]
    ]
    /*获取元素*/
    const cells = document.querySelectorAll(".cell");
    startGame();
    
    function startGame(){
    	document.querySelector(".endgame").style.display="none";
    	//设置阵列点  创建9个数组元素,元素的键0到8
    	origBoard = Array.from(Array(9).keys());
    //	console.log(origBoard);
    	for (var i = 0; i < cells.length; i++) {
    		//把文本先设置为空
    		cells[i].innerHTML = "";
    		//删除属性知道已经有人赢了
    		cells[i].style.removeProperty('background-color');
    		//点击方块
    		cells[i].addEventListener('click',turnClick,false);
    	}
    }
    
    function turnClick(square){
    	//控制台点击日志
    //	console.log(square.target.id);
    	//人类玩家点击
    	turn(square.target.id,huPlayer);
    }
    //参数是方块ID,播放器
    function turn(squareId,player){
    	//这些板阵列数组将属于玩家
    	origBoard[squareId] = player;
    	document.getElementById(squareId).innerHTML = player;
    	//让游戏进行检查
    	var gameWin = checkWin(origBoard,player);
    	if(gameWin){
    		gameOver(gameWin);
    	}
    }
    /*检查是否胜利方法*/
    function checkWin(board,player){
    	//使用reduce累加器
    	let plays = board.reduce((a,e,i)=> 
    		(e===player) ? a.concat(i):a ,[])
    	let gameWin = null;
    	//如果是属于之前winCombos胜利组合
    	for (let [index,win] of winCombos.entries()) {
    		if (win.every(Element => plays.indexOf(Element) > -1)){
    			//现在我们知道是哪一个组合胜利了
    			gameWin = {index:index,player:player};
    			break;
    		}
    	}
    	return gameWin;
    }
    /*游戏结束*/
    function gameOver(gameWin){
    	for(let index of winCombos[gameWin.index]){
    		//人类获胜则为蓝色
    		document.getElementById(index).style.backgroundColor = 
    			gameWin.player == huPlayer? "blue":"red";
    	}
    	/*事件侦听器删除单击,已经结束了,你不能再点击*/
    	for (var i = 0; i < cells.length; i++) {
    		cells[i].removeEventListener('click',turnClick,false);
    	}
    }
    

    现阶段结果:

     

    第三部分:简单的智能AI

    /*1. Basic setup  一些变量并添加能力
    2. Determine winner  添加逻辑,获胜者并展示
    3. Basic AI and winner notificatior  创建一个基本AI
    4. Minimax a lgori thm !*/
    
    var origBoard;
    const huPlayer = 'O';
    const aiPlayer = 'X';
    /*胜利的线组,包括对角线*/
    const winCombos =[
    	[0, 1, 2],
    	[3, 4, 5],
    	[6, 7, 8],
    	[0, 3, 6],
    	[1, 4, 7],
    	[2, 5, 8], 
    	[0, 4, 8],
    	[6, 4, 2]
    ]
    /*获取元素*/
    const cells = document.querySelectorAll(".cell");
    startGame();
    
    function startGame(){
    	document.querySelector(".endgame").style.display="none";
    	//设置阵列点  创建9个数组元素,元素的键0到8
    	origBoard = Array.from(Array(9).keys());
    //	console.log(origBoard);
    	for (var i = 0; i < cells.length; i++) {
    		//把文本先设置为空
    		cells[i].innerHTML = "";
    		//删除属性知道已经有人赢了
    		cells[i].style.removeProperty('background-color');
    		//点击方块
    		cells[i].addEventListener('click',turnClick,false);
    	}
    }
    
    function turnClick(square){
    	//控制台点击日志
    //	console.log(square.target.id);
    //记住原来走过的方块
    	if(typeof origBoard[square.target.id] == 'number'){
    		//人类玩家点击
    		turn(square.target.id,huPlayer);
    		//由人类转向AI玩家
    		if(!checkTie()){
    			//电脑玩家将拐弯,走最合适的地方
    			turn(bestStep(),aiPlayer);
    		}
    	}
    	
    }
    //参数是方块ID,播放器
    function turn(squareId,player){
    	//这些板阵列数组将属于玩家
    	origBoard[squareId] = player;
    	document.getElementById(squareId).innerHTML = player;
    	//让游戏进行检查
    	var gameWin = checkWin(origBoard,player);
    	if(gameWin){
    		gameOver(gameWin);
    	}
    }
    /*检查是否胜利方法*/
    function checkWin(board,player){
    	//使用reduce累加器
    	let plays = board.reduce((a,e,i)=> 
    		(e===player) ? a.concat(i):a ,[])
    	let gameWin = null;
    	//如果是属于之前winCombos胜利组合
    	for (let [index,win] of winCombos.entries()) {
    		if (win.every(Element => plays.indexOf(Element) > -1)){
    			//现在我们知道是哪一个组合胜利了
    			gameWin = {index:index,player:player};
    			break;
    		}
    	}
    	return gameWin;
    }
    /*游戏结束*/
    function gameOver(gameWin){
    	for(let index of winCombos[gameWin.index]){
    		//人类获胜则为蓝色
    		document.getElementById(index).style.backgroundColor = 
    			gameWin.player == huPlayer? "blue":"red";
    	}
    	/*事件侦听器删除单击,已经结束了,你不能再点击*/
    	for (var i = 0; i < cells.length; i++) {
    		cells[i].removeEventListener('click',turnClick,false);
    	}
    	declareWinner(gameWin.player == huPlayer ? "你已经获得了胜利":"对不起,你输了");
    }
    
    function emptySquares(){
    	//过滤每一个元素,如果元素为number,返回所有方块
    	return origBoard.filter(s => typeof s=='number');
    }
    
    /*AI最优步骤*/
    function bestStep(){
    	return emptySquares()[0];
    }
    //眼睛功能,检查是否是平局
    function checkTie(){
    	if(emptySquares().length == 0){
    		for (var i = 0; i < cells.length; i++) {
    			cells[i].style.backgroundColor = "green";
    			cells[i].removeEventListener('click',turnClick,false);
    		}
    		//谁获胜了
    		declareWinner("Tie Game");
    		return true;
    	}else{
    		//平局
    		return false;
    	}
    	
    }
    
    function declareWinner(who){
    	document.querySelector(".endgame").style.display = 'block';	
    	document.querySelector(".endgame .text").innerHTML = who;
    }
    

    现阶段结果:

    第四部分:之前我们很容易就能击败AI,所以现在要强化AI的难度

    这里需要比较强的算法知识

    完整JavaScript代码:

    /*1. Basic setup  一些变量并添加能力
    2. Determine winner  添加逻辑,获胜者并展示
    3. Basic AI and winner notificatior  创建一个基本AI
    4. Minimax a lgori thm !*/
    
    var origBoard;
    const huPlayer = 'O';
    const aiPlayer = 'X';
    /*胜利的线组,包括对角线*/
    const winCombos =[
    	[0, 1, 2],
    	[3, 4, 5],
    	[6, 7, 8],
    	[0, 3, 6],
    	[1, 4, 7],
    	[2, 5, 8], 
    	[0, 4, 8],
    	[6, 4, 2]
    ]
    /*获取元素*/
    const cells = document.querySelectorAll(".cell");
    startGame();
    
    function startGame(){
    	document.querySelector(".endgame").style.display="none";
    	//设置阵列点  创建9个数组元素,元素的键0到8
    	origBoard = Array.from(Array(9).keys());
    //	console.log(origBoard);
    	for (var i = 0; i < cells.length; i++) {
    		//把文本先设置为空
    		cells[i].innerHTML = "";
    		//删除属性知道已经有人赢了
    		cells[i].style.removeProperty('background-color');
    		//点击方块
    		cells[i].addEventListener('click',turnClick,false);
    	}
    }
    
    function turnClick(square){
    	//控制台点击日志
    //	console.log(square.target.id);
    //记住原来走过的方块
    	if(typeof origBoard[square.target.id] == 'number'){
    		//人类玩家点击
    		turn(square.target.id,huPlayer);
    		//由人类转向AI玩家
    		if(!checkTie()){
    			//电脑玩家将拐弯,走最合适的地方
    			turn(bestStep(),aiPlayer);
    		}
    	}
    	
    }
    //参数是方块ID,播放器
    function turn(squareId,player){
    	//这些板阵列数组将属于玩家
    	origBoard[squareId] = player;
    	document.getElementById(squareId).innerHTML = player;
    	//让游戏进行检查
    	var gameWin = checkWin(origBoard,player);
    	if(gameWin){
    		gameOver(gameWin);
    	}
    }
    /*检查是否胜利方法*/
    function checkWin(board,player){
    	//使用reduce累加器
    	let plays = board.reduce((a,e,i)=> 
    		(e===player) ? a.concat(i):a ,[])
    	let gameWin = null;
    	//如果是属于之前winCombos胜利组合
    	for (let [index,win] of winCombos.entries()) {
    		if (win.every(Element => plays.indexOf(Element) > -1)){
    			//现在我们知道是哪一个组合胜利了
    			gameWin = {index:index,player:player};
    			break;
    		}
    	}
    	return gameWin;
    }
    /*游戏结束*/
    function gameOver(gameWin){
    	for(let index of winCombos[gameWin.index]){
    		//人类获胜则为蓝色
    		document.getElementById(index).style.backgroundColor = 
    			gameWin.player == huPlayer? "blue":"red";
    	}
    	/*事件侦听器删除单击,已经结束了,你不能再点击*/
    	for (var i = 0; i < cells.length; i++) {
    		cells[i].removeEventListener('click',turnClick,false);
    	}
    	declareWinner(gameWin.player == huPlayer ? "你已经获得了胜利":"对不起,你输了");
    }
    
    function emptySquares(){
    	//过滤每一个元素,如果元素为number,返回所有方块
    	return origBoard.filter(s => typeof s=='number');
    }
    
    /*AI最优步骤*/
    function bestStep(){
    	//简单AI
    //	return emptySquares()[0];
    	//智能AI
    	return minmax(origBoard,aiPlayer).index;
    }
    //眼睛功能,检查是否是平局
    function checkTie(){
    	if(emptySquares().length == 0){
    		for (var i = 0; i < cells.length; i++) {
    			cells[i].style.backgroundColor = "green";
    			cells[i].removeEventListener('click',turnClick,false);
    		}
    		//谁获胜了
    		declareWinner("Tie Game");
    		return true;
    	}else{
    		//平局
    		return false;
    	}
    	
    }
    
    function declareWinner(who){
    	document.querySelector(".endgame").style.display = 'block';	
    	document.querySelector(".endgame .text").innerHTML = who;
    }
    
    function minmax(newBoard,player){
    	//找到索引,空方块功能设置为a
    	var availSpots = emptySquares(newBoard);
    	
    	if(checkWin(newBoard,player)){
    		return {score:-10};
    	}else if(checkWin(newBoard,aiPlayer)){
    		return {score:20};
    	}else if(availSpots.length === 0){
    		return {score:0};
    	}
    	//之后进行评估
    	var moves = [];
    	//收集每个动作时的空白点
    	for (var i = 0; i < availSpots.length; i++) {
    		//然后设置空的索引号
    		var move = {};
    		move.index = newBoard[availSpots[i]];
    		newBoard[availSpots[i]] = player;
    		
    		if( player == aiPlayer){
    			//存储对象,包括得分属性
    			var result = minmax(newBoard,huPlayer);
    			move.score = result.score;
    		}else{
    			//存储对象,包括得分属性
    			var result = minmax(newBoard,aiPlayer);
    			move.score = result.score;
    		}
    		
    		newBoard[availSpots[i]] = move.index;
    		
    		moves.push(move);
    	}
    	var bestMove;
    	//如果是AI玩家,以非常低的数字和循环通过
    	if(player === aiPlayer){
    		var bestScore = -1000;
    		for (var i = 0; i < moves.length; i++) {
    			if(moves[i].score > bestScore){
    				bestScore = moves[i].score;
    				bestMove = i;
    			}
    		}
    	}else{
    		var bestScore = 1000;
    		for (var i = 0; i < moves.length; i++) {
    			if(moves[i].score < bestScore){
    				bestScore = moves[i].score;
    				bestMove = i;
    			}
    		}
    	}
    	
    	return moves[bestMove];
    }
    

    结果:不多说了,还没赢过😂

     

    学习来源:JavaScript井字棋游戏开发与AI算法

    代码链接:https://download.csdn.net/download/qq_36171287/12252143

     

    一起学习,一起进步 -.- ,如有错误,可以发评论

    展开全文
  • 井字游戏中Minimax AI算法的实现 什么是Minimax? Minimax是一种人工智能技术,适用于井字游戏,跳棋,国际象棋和围棋等两个玩家游戏。 该游戏被称为零和游戏,因为用数学表示形式:一个玩家赢(+1),其他玩家输...
  • 代码参考自中国大学mooc上人工智能与信息社会陈斌老师的算法,我在原来的基础上增加了玩家输入的异常捕获 AlphaBeta剪枝算法是对Minimax方法的优化,能够极大提高搜索树的效率,如果对这个算法感兴趣的可以去参考...
  • TicTacToe(井字棋)的算法——不比人的智商低的AI

    万次阅读 多人点赞 2013-03-28 19:12:42
    TicTacToe也俗称井字棋或三连棋(两人轮流在一有九格方盘上划加字或圆圈, 谁先把三个同一记号排成横线、直线、斜线, 即是胜者),男女老少皆宜的入门级棋类游戏。    关于游戏的实现方式,比较简单,在这就不多说...

          何为TicTacToe?

    TicTacToe也俗称井字棋或三连棋(两人轮流在一有九格方盘上划加字或圆圈, 谁先把三个同一记号排成横线、直线、斜线, 即是胜者),男女老少皆宜的入门级棋类游戏。

          

           关于游戏的实现方式,比较简单,在这就不多说了。直接谈一谈如何写出在TicTacToe游戏中不输给人类棋手的电脑。

           想要写出游戏AI,第一步是自己要会玩游戏,有自己的策略。第二部才是告诉我们的AI如何实现这样的策略。我们在玩的时候发现能尽可能占据有利的位置会帮助我们快速赢下比赛,玩游戏还能发现的一点就是一定要防住对面即将连成一条线的一路,还有很多,很多。这些特征可以说明,游戏中不同情况下,盘面的每一个位置似乎有着不同的重要性,我们完全可以利用这一点来指导我们的AI去驰骋沙场。(我一开始打算仔细判断每一种情况,比如双二单二什么的,结果不但代码量大而且效果和这样的思路没什么区别)

           也就是说,给与AI一个非常重要的变量(一个3*3的数组),表示每一个位置的权值,也就是该位置的重要性的体现。比赛中第一重要的当然是自己连成一条线,这可以赋予最高的权值。而且,这个权值应该大到什么地步呢?当然应该大到无论其他什么情况发生都以此为第一要素的地步。所以我们可以在AI检查出自己能成一条线的位置时,给这个位置赋值10000,代表这个位置至高无上的地位。

           第二重要的则是防止对手成一条线,此举的重要性,可谓一人之下万人之上,就在有这种情况的时候赋予这个位置1000的值吧。

           其他需要赋值的三种情况是:1.某条线仅仅有己方棋子一枚;2.某条线仅仅有敌方棋子一枚;3.某条线上空空如也。如果是我们的AI先手,我认为第一条的权重大于第二条大于第三条。而AI后手则2>3>1。

           因为玩过Tictactoe的朋友一定知道,这是一个先手赢不了,后手输不了的游戏。但是作为后手一旦失误就会输棋,先手若能抓住后手的失误则能赢棋。数年前中国五子棋第一人那威曾经说过“先手要攻,后手要守”。虽然是说五子棋,不过Tictactoe实际上就是三字棋,与五子棋的区别仅仅是少了很多很多的变化而已。所以我们需要给我们的AI贯彻这样的思想:先手要积极进攻,后手要小心放手。好了,AI的思路基本上就是这样了,下面贴上核心部分的代码(java)

     

    注:游戏的地图保存在一个叫net的数组里,每一个位置值为0表示没有棋,1表示为X棋,2表示为O棋

           int[][] net=new int[4][4];//0 means null;1 means X;2 means O;
           int level[][]=new int[4][4];//越大优先级越高 
           IOHelper h=new IOHelper();
           int o2=10000;//一个己方活二权值
           int x2=1000;//一个对方活二权值
           int x=10;//一个对方活一权值
           int o=6;//一个己方活一权值
           int nothing=4;//一个空行权值

         for(int i=0;i<3;i++){
          for(int j=0;j<3;j++){
           if(net[i][j]!=0)level[i][j]=0;
           else{
           //横竖两条,每人都有
           //自己活二,,220
           if(((net[0][j]+net[1][j]+net[2][j])==4)&&(net[0][j]*net[1][j]*net[2][j])==0&&((net[0][j]-1)*(net[1][j]-1)*(net[2][j]-1))==-1)
            level[i][j]=level[i][j]+o2;
           if(((net[i][0]+net[i][1]+net[i][2])==4)&&(net[i][0]*net[i][1]*net[i][2])==0&&((net[i][0]-1)*(net[i][1]-1)*(net[i][2]-1))==-1)
            level[i][j]=level[i][j]+o2;
           //对方活二,110
           if(((net[0][j]+net[1][j]+net[2][j])==2)&&(net[0][j]*net[1][j]*net[2][j])==0&&((net[0][j]-1)*(net[1][j]-1)*(net[2][j]-1))==0)
            level[i][j]=level[i][j]+x2;
           if(((net[i][0]+net[i][1]+net[i][2])==2)&&(net[i][0]*net[i][1]*net[i][2])==0&&((net[i][0]-1)*(net[i][1]-1)*(net[i][2]-1))==0)
            level[i][j]=level[i][j]+x2;
           //单个X,100
           if(((net[0][j]+net[1][j]+net[2][j])==1)&&(net[0][j]*net[1][j]*net[2][j])==0&&((net[0][j]-1)*(net[1][j]-1)*(net[2][j]-1))==0)
            level[i][j]=level[i][j]+x;
           if(((net[i][0]+net[i][1]+net[i][2])==1)&&(net[i][0]*net[i][1]*net[i][2])==0&&((net[i][0]-1)*(net[i][1]-1)*(net[i][2]-1))==0)
            level[i][j]=level[i][j]+x;
           //单个O,200
           if(((net[0][j]+net[1][j]+net[2][j])==2)&&(net[0][j]*net[1][j]*net[2][j])==0&&((net[0][j]-1)*(net[1][j]-1)*(net[2][j]-1))==1)
            level[i][j]=level[i][j]+o;
           if(((net[i][0]+net[i][1]+net[i][2])==2)&&(net[i][0]*net[i][1]*net[i][2])==0&&((net[i][0]-1)*(net[i][1]-1)*(net[i][2]-1))==1)
            level[i][j]=level[i][j]+o;
           //空行,000
           if(((net[0][j]+net[1][j]+net[2][j])==0)&&(net[0][j]*net[1][j]*net[2][j])==0&&((net[0][j]-1)*(net[1][j]-1)*(net[2][j]-1))==-1)
            level[i][j]=level[i][j]+nothing;
           if(((net[i][0]+net[i][1]+net[i][2])==0)&&(net[i][0]*net[i][1]*net[i][2])==0&&((net[i][0]-1)*(net[i][1]-1)*(net[i][2]-1))==-1)
            level[i][j]=level[i][j]+nothing;
           
           //分情况
           //主对角线
           if((i==0&&j==0)||(i==2&&j==2)||(i==1&&j==1)){
            //己方活二
            if(((net[0][0]+net[1][1]+net[2][2])==4)&&(net[0][0]*net[1][1]*net[2][2])==0&&
            ((net[0][0]-1)*(net[1][1]-1)*(net[2][2]-1))==-1)
            level[i][j]=level[i][j]+o2;
            //对方活二
            if(((net[0][0]+net[1][1]+net[2][2])==2)&&(net[0][0]*net[1][1]*net[2][2])==0&&
              ((net[0][0]-1)*(net[1][1]-1)*(net[2][2]-1))==0)
              level[i][j]=level[i][j]+x2;
            //单个X
            if(((net[0][0]+net[1][1]+net[2][2])==1)&&(net[0][0]*net[1][1]*net[2][2])==0&&
              ((net[0][0]-1)*(net[1][1]-1)*(net[2][2]-1))==0)
              level[i][j]=level[i][j]+x;
            //单个O
            if(((net[0][0]+net[1][1]+net[2][2])==2)&&(net[0][0]*net[1][1]*net[2][2])==0&&
              ((net[0][0]-1)*(net[1][1]-1)*(net[2][2]-1))==1)
              level[i][j]=level[i][j]+o;
            //空行,000
            if(((net[0][0]+net[1][1]+net[2][2])==0)&&(net[0][0]*net[1][1]*net[2][2])==0&&
              ((net[0][0]-1)*(net[1][1]-1)*(net[2][2]-1))==-1)
             level[i][j]=level[i][j]+nothing;
           }
           
           //副对角线
           if((i==0&&j==2)||(i==2&&j==0)||(i==1&&j==1)){
            //己方活二
            if(((net[0][2]+net[1][1]+net[2][0])==4)&&(net[0][2]*net[1][1]*net[2][0])==0&&
            ((net[0][2]-1)*(net[1][1]-1)*(net[2][0]-1))==-1)
            level[i][j]=level[i][j]+o2;
            //对方活二
            if(((net[0][2]+net[1][1]+net[2][0])==2)&&(net[0][2]*net[1][1]*net[2][0])==0&&
              ((net[0][2]-1)*(net[1][1]-1)*(net[2][0]-1))==0)
              level[i][j]=level[i][j]+x2;
            //单个X
            if(((net[0][2]+net[1][1]+net[2][0])==1)&&(net[0][2]*net[1][1]*net[2][0])==0&&
              ((net[0][2]-1)*(net[1][1]-1)*(net[2][0]-1))==0)
              level[i][j]=level[i][j]+x;
            //单个O
            if(((net[0][2]+net[1][1]+net[2][0])==2)&&(net[0][2]*net[1][1]*net[2][0])==0&&
              ((net[0][2]-1)*(net[1][1]-1)*(net[2][0]-1))==1)
              level[i][j]=level[i][j]+o;
            //空行,000
            if(((net[0][2]+net[1][1]+net[2][0])==0)&&(net[0][2]*net[1][1]*net[2][0])==0&&
              ((net[0][2]-1)*(net[1][1]-1)*(net[2][0]-1))==-1)
             level[i][j]=level[i][j]+nothing;
           }//the end of for if
           }//the end of if
          }//the end of for j
         }//the end of for j


    //寻找最大权值的位置
        int maxi = 0,maxj = 0,temp = 0;
               for(int i=0;i<3;i++){
                     for(int j=0;j<3;j++){
                          if(level[i][j]>temp)
                          {

                           temp=level[i][j];
                          maxi=i;
                          maxj=j;
                          }
                     System.out.println("net[i][j]="+net[i][j]);
                     System.out.println("level[i][j]="+level[i][j]);
                     }
               }

     

      觉得作者不容易的话请顶一个(*^__^*)  谢谢

    展开全文
  • 基于极大极小算法和alpha-beta剪枝实现AI井字棋

    万次阅读 多人点赞 2016-11-01 20:54:50
    说一下实现这个AI井字棋的思路:简单的来说就是计算机希望估值函数值最大,而下棋人希望这个估值最小,因此在计算机决策是就用递归的向前看,这里的递归其实蛮不好理解的,但是可以宏观的去理解。下面是代码的构成:...

    关于极大极小算法和alpha-beta剪枝可以参考文章的参考资料,这里仅对其进行代码实现。

    其实这个算法单纯的理解并不容易,下面用代码进行实现。

    说一下实现这个AI井字棋的思路:

    简单的来说就是计算机希望估值函数值最大,而下棋人希望这个估值最小,因此在计算机决策是就用递归的向前看,这里的递归其实蛮不好理解的,但是可以宏观的去理解。

    下面是代码的构成:

    1. 一个ChessBoard的类用来处理一些关于棋盘的事件。
    2. 一个TicTacToe的类用来实现游戏开始和计算机,玩家决策的事件

    ChessBoard.h

    //Author : yqtao
    //Date   :2016.10.30
    #ifndef CHESS_BOARD_H
    #define CHESS_BOARD_H
    #include<vector>
    #include<iostream>
    #include<string>
    using namespace std;
    
    const int ChessBoard_Row = 13;
    const int ChessBoard_Col = 26;
    const int GridNuber = 9;
    const char Comp_Char = 'X';
    const char Human_Char = 'O';
    const char Blank_Char = ' ';
    
    class ChessBoard {
    public:
        ChessBoard();
        bool isEmpty(int pos);
        bool isFull();
        bool canWin(char c);
        bool immediateComWin(int& bestMove);
        bool immediateHumanWin(int& bestMove);
        void placeComp(int pos);
        void placeHuman(int pos);
        void unPlace(int pos);
        void print();
    private:
        vector<char> boardInOneDimens;
        vector<string> board;
    
    };
    #endif // !CHESS_BOARD_H

    ChessBoard.cpp

    #include"ChessBoard.h"
    ChessBoard::ChessBoard() {             //默认构造函数
        boardInOneDimens.resize(GridNuber);
        for (int i = 0; i < GridNuber; i++)
            boardInOneDimens[i] = ' ';
        vector<string>tmp = {
            "- - - - - - - - - - - - -",
            "|       |       |       |",
            "|       |       |       |",
            "|       |       |       |",
            "- - - - - - - - - - - - -",
            "|       |       |       |",
            "|       |       |       |",
            "|       |       |       |",
            "- - - - - - - - - - - - -",
            "|       |       |       |",
            "|       |       |       |",
            "|       |       |       |",
            "- - - - - - - - - - - - -"
        };
        board = tmp;
    }
    //check the posion is empty or not 
    bool ChessBoard::isEmpty(int pos) {
        return boardInOneDimens[pos] == ' ';
    }
    //
    bool ChessBoard::isFull() {
        for (int i = 0; i < GridNuber; i++) {
            if (boardInOneDimens[i] == ' ')
                return false;
        }
        return true;
    }
    //
    bool ChessBoard::canWin(char c) {
        //check every row
        for (int i = 0; i <= 6; i+=3) {
            if (boardInOneDimens[i] == c&&boardInOneDimens[i] == boardInOneDimens[i + 1] &&
                boardInOneDimens[i] == boardInOneDimens[i + 2])
                return true;
        }
        //check every col
        for (int i = 0; i < 3; i++) {
            if (boardInOneDimens[i] == c&&boardInOneDimens[i] == boardInOneDimens[i + 3] &&
                boardInOneDimens[i] == boardInOneDimens[i + 6])
                return true;
        }
        //check every diagonals
        if (boardInOneDimens[0] == c&&boardInOneDimens[4] == c&&boardInOneDimens[8] == c)
            return true;
        if (boardInOneDimens[2] == c&&boardInOneDimens[4] == c&&boardInOneDimens[6] == c)
            return true;
        return false;
    }
    //
    bool ChessBoard::immediateComWin(int& bestMove) {
        for (int i = 0; i < GridNuber; i++) {
            if (isEmpty(i)) {
                boardInOneDimens[i] =Comp_Char;
                bool Win = canWin(Comp_Char); 
                boardInOneDimens[i] = Blank_Char;   //backtraceing
                if (Win) {
                    bestMove = i;
                    return true;
                }
            }
        }
        return false;
    }
    //
    bool ChessBoard::immediateHumanWin(int& bestMove) {
        for (int i = 0; i < GridNuber; i++) {
            if (isEmpty(i)) {
                boardInOneDimens[i] = Human_Char;
                bool Win = canWin(Human_Char);
                boardInOneDimens[i] = Blank_Char;   //backtraceing
                if (Win) {
                    bestMove = i;
                    return true;
                }
            }
        }
        return false;
    }
    //
    void ChessBoard::placeComp(int pos) {
        boardInOneDimens[pos] = 'X';
    }
    //
    void ChessBoard::placeHuman(int pos) {
        boardInOneDimens[pos] = 'O';
    }
    //
    void ChessBoard::unPlace(int pos) {
        boardInOneDimens[pos] = ' ';
    }
    //
    void ChessBoard::print() {
        int cnt = 0;
        for (int i = 2; i <= 10; i += 4) {
            for (int j = 4; j <= 20; j += 8) {
                board[i][j] = boardInOneDimens[cnt++];
            }
        }
        for (int i = 0; i < ChessBoard_Row; ++i) {
            cout << board[i] << endl;
        }
    }

    TicTacToe.h

    #ifndef TICTACTOE_H
    #define TICTACTOE_H
    #include "ChessBoard.h"
    enum Role { Human, Comp };
    static const int CompWin = 2;
    static const int Draw = 1;
    static const int HumanWin = 0;
    class TicTacToe {
    public:
        void start();
        bool handleGameOver();
        bool gameIsOver(bool &draw, Role &win);
        Role chooseFirstPlace();
        void compPlace();
        int getBestMove();
        void humanPlace();
        int getPlacePosition();
        void findCompMove(int& bestMove,int& value, int alpha, int beta);
        void findHumanMove(int& bestMove,int& value, int alpha, int beta);
    private:
        ChessBoard board;
    };
    #endif // !TicTacToe

    TicTacToe.cpp

    #include "TicTacToe.h"
    void TicTacToe::start() {
        Role firstPlace = chooseFirstPlace();
        if (firstPlace == Comp) {  // Choose computer to be the first
            compPlace();
        }
        while (1) {
            board.print();
            if (handleGameOver()) break;
            humanPlace();
            board.print();
            if (handleGameOver()) break;
            compPlace();
        }
    }
    Role TicTacToe::chooseFirstPlace() {
        int choose;
        while (1) {
            cout << "who will place first" << endl;
            cout << "0 : human first " << endl;
            cout << "1 : computer first" << endl;
            cin >> choose;
            if (choose == 0 || choose == 1) {
                cout << endl;
                break;
            }
            else
                cout << "error,please enter again" << endl;
        }
        return (Role)choose;
    }
    //
    void TicTacToe::humanPlace() {
        int pos = getPlacePosition();
        board.placeHuman(pos);
        cout << "Your choice:" << endl;
    }
    //
    int TicTacToe::getPlacePosition() {
        int m, n,pos;
        while (1) {
            cout << "It is your turn, please input where you want :" << endl;
            cout << "for example: 2 2 mean you want to add position 2 row,2 col:" << endl;
            cin >> m >> n;
            if (m < 0 || m>3 || n < 0 || n>3)
                cout << "error,please input again:" << endl;
            else {
                pos = (m - 1) * 3 + n - 1;
                if (board.isEmpty(pos))
                    break;
                else
                    cout << "error,please input again:" << endl;
            }
        }
        return pos;
    }
    //
    void TicTacToe::compPlace() {
        int bestMove = getBestMove();
        board.placeComp(bestMove);
        cout << "the computer choice is: " << endl;
    }
    int TicTacToe::getBestMove() {
        int bestMove = 0, value = 0;
        findCompMove(bestMove,value,HumanWin, CompWin);
        return bestMove;
    }
    void TicTacToe::findCompMove(int& bestMove,int &value, int alpha, int beta) {
        if (board.isFull())
            value = Draw;
        else if (board.immediateComWin(bestMove))
            value = CompWin;
        else {
            value = alpha;
            for (int i = 0; i < GridNuber&&value < beta; i++) {
                if (board.isEmpty(i)) {
                    board.placeComp(i);
                    int tmp = -1, response = -1;  // Tmp is useless
                    findHumanMove(tmp, response, value, beta);
                    board.unPlace(i);
                    if (response > value) {
                        value = response;
                        bestMove = i;
                    }
                }
            }
        }
    }
    
    void TicTacToe::findHumanMove(int& bestMove,int & value, int alpha, int beta) {
        if (board.isFull())
            value=Draw;
        else if (board.immediateHumanWin(bestMove)){
            value=HumanWin;
        }
        else {
            value = beta; 
            for (int i = 0; i < GridNuber&&value>alpha; i++) {
                if (board.isEmpty(i)) {
                    board.placeHuman(i);
                    int tmp = -1, response = -1;  // Tmp is useless
                    findCompMove(tmp, response, alpha, value);
                    board.unPlace(i);
                    if (response <value) {
                        value = response;
                        bestMove = i;
                    }
                }
            }
        }
    }
    //
    bool TicTacToe::gameIsOver(bool &draw, Role &win) {
        if (board.canWin(Comp_Char)) {
            win =Comp ;
            draw = false;
            return true;
        }
        else if (board.canWin(Human_Char)) {
            win = Human;
            draw = false;
            return true;
        }
        else if (board.isFull()) {
            draw = true;
            return true;
        }
        else {
            return false;
        }
    }
    
    bool TicTacToe::handleGameOver()  {
        bool draw = false;
        Role whoWin = Human;
        if (gameIsOver(draw, whoWin)) {
            if (draw) {
                cout << "Draw!" << endl;
            }
            else {
                if (whoWin == Comp) {
                    cout << "You lose!" << endl;
                }
                else if (whoWin == Human) {
                    cout << "Congratulations! You defeat the computer." << endl;
                }
            }
            return true;
        }
        else {
            return false;
        }
    }

    实现的结果如下图所示:

    这里写图片描述

    完成的代码和运行:

    在Linux的环境下:

    git clone https://github.com/yqtaowhu/DataStructureAndAlgorithm
    cd DataStructureAndAlgorithm/Algorithm/TicTacToe/
    make run

    在window的环境下可用VS进行编译。
    完整的代码在我的Github:
    https://github.com/yqtaowhu/DataStructureAndAlgorithm/tree/master/Algorithm/TicTacToe

    参考资料:
    1. 数据结构与算法分析——C++语言描述
    2. http://blog.csdn.net/tianranhe/article/details/8301756
    3. http://blog.csdn.net/qq_22885773/article/details/50967021

    展开全文
  • 极小极大 井字棋游戏中极小极大算法的 LISP 实现 我为我的 AI 入门课程编写了这段代码。 它使用极小极大算法实现井字棋游戏。 它没有任何类型的图形界面。
  • 继上一篇完成了井字棋(N子棋)的minimax 最佳策略后,我们基于Pygame来创造一个图形游戏环境,可供人机和机器对弈,为后续模拟AlphaGo的自我强化学习算法做环境准备。OpenAI Gym 在强化学习领域是事实标准,我们...
  • 最近有一门课结束了,需要做一个井字棋的游戏,我用JavaScript写了一个。首先界面应该问题不大,用html稍微写一下就可以。主要是人机对弈时的ai算法,如何使电脑方聪明起来,是值得思考一下的。开始游戏后,由玩家...
  • AlphaBeta剪枝算法是对Minimax方法的优化,能够极大提高搜索树的效率。代码参考自中国大学mooc上人工智能与信息社会陈斌老师的算法,我在原来的基础上增加了玩家输入的异常捕获
  • python GUI井字棋

    2020-07-20 10:24:01
    python实现的GUI井字棋游戏,精美的开始界面及开始按钮 游戏功能: 机器人:简单的AI人工智能算法 玩家:鼠标操作
  • 井字游戏人工智能 由极小极大算法驱动的井字棋 AI(带有 alpha-beta 修剪)。
  • 比如在井字棋中,总利益为0,以玩家A的视角看,A取得胜利获得的利益是1,则B在A获得胜利的情况下获得的利益则为-1,反之亦然,双方的利益总和为0。 棋类游戏是双方交替下棋的游戏,每一次落子都代表落子的
  • 使用mcts算法的近似ai,能够对战ten(超级井字棋) 超级井字棋:9个九宫格,每个玩家落子的格子由另一个玩家的落子决定。 玩家在任意一个九宫格井字棋胜利则占领这个九宫格,最终在9个九宫格中完成井字棋获胜。

空空如也

空空如也

1 2 3 4
收藏数 69
精华内容 27
关键字:

井字棋ai算法