人工智能实现简单的五子棋程序

我这个程序在QQ五子棋上实验了一下,结果是黑棋先手全胜,白棋后手的胜率却惨不忍睹,原因有下:
1、五子棋的先手是有优势的,所以职业比赛里都会有禁手来实现公平
2、水平有限,对局面的评估只有一小部分

主要思路就是博弈树,程序向前看一步,对对手可能的走法进行评估,评估的策略主要有两条:
1、扫描整个棋盘,判断出现了多少个三子成线并且两端未堵的情况,对方每出现一种该情况,评估大幅下降,因为这几乎是必堵的,反之评估大幅上升,程序追求的就是这种情况;
2、判断出现了多少个两子成线的情况,这种情况的评估值比上一种要少
此外还有一个几乎是没用的判断,是我从九宫格的评估方案上“拿”过来的,用两种颜色的棋子分别填满棋盘,判断出现了多少个五子成龙的情况,不过很鸡肋

#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <cstdio>
#include <set>
#include <math.h>
#include <algorithm>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
int changex=8,changey=8;
struct Node
{
    int A[16][16];
    int f;
};
void mcopy(int des[16][16],int src[16][16])
{
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            des[i][j]=src[i][j];
}
bool check(int flag,int tmp[16][16])
{
    int fflag;
    if(flag==0)
        fflag=1;
    else
        fflag=0;
    //棋谱1:四子连线,端点都在
    for(int i=1; i<=15; ++i) //水平方向
        for(int j=1; j<=10; ++j)
        {
            if(tmp[i][j]!=fflag&&tmp[i][j+1]==flag&&tmp[i][j+2]==flag&&tmp[i][j+3]==flag&&tmp[i][j+4]==flag&&tmp[i][j+5]!=fflag)
                return true;
        }
    for(int i=1; i<=10; ++i) //垂直方向
        for(int j=1; j<=15; ++j)
        {
            if(tmp[i][j]!=fflag&&tmp[i+1][j]==flag&&tmp[i+2][j]==flag&&tmp[i+3][j]==flag&&tmp[i+4][j]==flag&&tmp[i+5][j]!=fflag)
                return true;
        }
    for(int i=1; i<=10; ++i) //正斜方向
        for(int j=1; j<=10; ++j)
        {
            if(tmp[i][j]!=fflag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]==flag&&tmp[i+3][j+3]==flag&&tmp[i+4][j+4]==flag&&tmp[i+5][j+5]!=fflag)
                return true;
        }
    for(int i=1; i<=10; ++i) //反斜方向
        for(int j=15; j>=6; --j)
        {
            if(tmp[i][j]!=fflag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]==flag&&tmp[i+3][j-3]==flag&&tmp[i+4][j-4]==flag&&tmp[i+5][j-5]!=fflag)
                return true;
        }
    //棋谱2:最简单的五子成型
    for(int i=1; i<=15; ++i) //水平方向
        for(int j=1; j<=11; ++j)
        {
            if(tmp[i][j]==flag&&tmp[i][j+1]==flag&&tmp[i][j+2]==flag&&tmp[i][j+3]==flag&&tmp[i][j+4]==flag)
                return true;
        }
    for(int i=1; i<=11; ++i) //垂直方向
        for(int j=1; j<=15; ++j)
        {
            if(tmp[i][j]==flag&&tmp[i+1][j]==flag&&tmp[i+2][j]==flag&&tmp[i+3][j]==flag&&tmp[i+4][j]==flag)
                return true;
        }
    for(int i=1; i<=11; ++i) //正斜方向
        for(int j=1; j<=11; ++j)
        {
            if(tmp[i][j]==flag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]==flag&&tmp[i+3][j+3]==flag&&tmp[i+4][j+4]==flag)
                return true;
        }
    for(int i=1; i<=11; ++i) //反斜方向
        for(int j=15; j>=5; --j)
        {
            if(tmp[i][j]==flag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]==flag&&tmp[i+3][j-3]==flag&&tmp[i+4][j-4]==flag)
                return true;
        }
    return false;
}
int h(int flag,int A[16][16])
{
    int tmp[16][16];
    mcopy(tmp,A);
    int fflag;
    if(flag==1)
        fflag=0;
    else
        fflag=1;
    int val=0;
    //出现没有堵住的三子,对己方不利的评价要很高
    for(int i=1; i<=15; ++i) //水平方向
        for(int j=1; j<=11; ++j)
        {
            if(tmp[i][j]!=flag&&tmp[i][j+1]==fflag&&tmp[i][j+2]==fflag&&tmp[i][j+3]==fflag&&tmp[i][j+4]!=flag)
                val+= -1000;
            if(tmp[i][j]!=fflag&&tmp[i][j+1]==flag&&tmp[i][j+2]==flag&&tmp[i][j+3]==flag&&tmp[i][j+4]!=fflag)
                val+= 1000;
            /*if(tmp[i][j]!=flag&&tmp[i][j+1]==fflag&&tmp[i][j+2]!=flag&&tmp[i][j+3]==fflag&&tmp[i][j+4]!=flag)
                val+= -100;
            if(tmp[i][j]!=fflag&&tmp[i][j+1]==flag&&tmp[i][j+2]!=fflag&&tmp[i][j+3]==flag&&tmp[i][j+4]!=fflag)
                val+= 100;*/
        }
    for(int i=1; i<=11; ++i) //垂直方向
        for(int j=1; j<=15; ++j)
        {
            if(tmp[i][j]!=flag&&tmp[i+1][j]==fflag&&tmp[i+2][j]==fflag&&tmp[i+3][j]==fflag&&tmp[i+4][j]!=flag)
                val+= -1000;
            if(tmp[i][j]!=fflag&&tmp[i+1][j]==flag&&tmp[i+2][j]==flag&&tmp[i+3][j]==flag&&tmp[i+4][j]!=fflag)
                val+= 1000;
            /*if(tmp[i][j]!=flag&&tmp[i+1][j]==fflag&&tmp[i+2][j]!=flag&&tmp[i+3][j]==fflag&&tmp[i+4][j]!=flag)
                val+= -100;
            if(tmp[i][j]!=fflag&&tmp[i+1][j]==flag&&tmp[i+2][j]!=fflag&&tmp[i+3][j]==flag&&tmp[i+4][j]!=fflag)
                val+= 100;*/
        }
    for(int i=1; i<=11; ++i) //正斜方向
        for(int j=1; j<=11; ++j)
        {
            if(tmp[i][j]!=flag&&tmp[i+1][j+1]==fflag&&tmp[i+2][j+2]==fflag&&tmp[i+3][j+3]==fflag&&tmp[i+4][j+4]!=flag)
                val+= -1000;
            if(tmp[i][j]!=fflag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]==flag&&tmp[i+3][j+3]==flag&&tmp[i+4][j+4]!=fflag)
                val+= 1000;
            /*if(tmp[i][j]!=flag&&tmp[i+1][j+1]==fflag&&tmp[i+2][j+2]!=flag&&tmp[i+3][j+3]==fflag&&tmp[i+4][j+4]!=flag)
                val+= -100;
            if(tmp[i][j]!=fflag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]!=fflag&&tmp[i+3][j+3]==flag&&tmp[i+4][j+4]!=fflag)
                val+= 100;*/
        }
    for(int i=1; i<=11; ++i) //反斜方向
        for(int j=15; j>=5; --j)
        {
            if(tmp[i][j]!=flag&&tmp[i+1][j-1]==fflag&&tmp[i+2][j-2]==fflag&&tmp[i+3][j-3]==fflag&&tmp[i+4][j-4]!=flag)
                val+= -1000;
            if(tmp[i][j]!=fflag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]==flag&&tmp[i+3][j-3]==flag&&tmp[i+4][j-4]!=fflag)
                val+= 1000;
            /*if(tmp[i][j]!=flag&&tmp[i+1][j-1]==fflag&&tmp[i+2][j-2]!=flag&&tmp[i+3][j-3]==fflag&&tmp[i+4][j-4]!=flag)
                val+= -100;
            if(tmp[i][j]!=fflag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]!=fflag&&tmp[i+3][j-3]==flag&&tmp[i+4][j-4]!=fflag)
                val+= 100;*/
        }
    //出现未堵住的两子,评价次之
    for(int i=1; i<=15; ++i) //水平方向
        for(int j=1; j<=12; ++j)
        {
            if(tmp[i][j]!=flag&&tmp[i][j+1]==fflag&&tmp[i][j+2]==fflag&&tmp[i][j+3]!=flag)
                val+= -100;
            if(tmp[i][j]!=fflag&&tmp[i][j+1]==flag&&tmp[i][j+2]==flag&&tmp[i][j+3]!=fflag)
                val+= 100;
        }
    for(int i=1; i<=12; ++i) //垂直方向
        for(int j=1; j<=15; ++j)
        {
            if(tmp[i][j]!=flag&&tmp[i+1][j]==fflag&&tmp[i+2][j]==fflag&&tmp[i+3][j]!=flag)
                val+= -100;
            if(tmp[i][j]!=fflag&&tmp[i+1][j]==flag&&tmp[i+2][j]==flag&&tmp[i+3][j]!=fflag)
                val+= 100;
        }
    for(int i=1; i<=12; ++i) //正斜方向
        for(int j=1; j<=12; ++j)
        {
            if(tmp[i][j]!=flag&&tmp[i+1][j+1]==fflag&&tmp[i+2][j+2]==fflag&&tmp[i+3][j+3]!=flag)
                val+= -100;
            if(tmp[i][j]!=fflag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]==flag&&tmp[i+3][j+3]!=fflag)
                val+= 100;
        }
    for(int i=1; i<=12; ++i) //反斜方向
        for(int j=15; j>=4; --j)
        {
            if(tmp[i][j]!=flag&&tmp[i+1][j-1]==fflag&&tmp[i+2][j-2]==fflag&&tmp[i+3][j-3]!=flag)
                val+= -100;
            if(tmp[i][j]!=fflag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]==flag&&tmp[i+3][j-3]!=fflag)
                val+= 100;
        }
    /*if(val!=0)
    {
        return val;
    }*/
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            if(tmp[i][j]==8)
                tmp[i][j]=flag;
    int sum1=0;
    for(int i=1; i<=15; ++i) //水平方向
        for(int j=1; j<=11; ++j)
            if(tmp[i][j]==flag&&tmp[i][j+1]==flag&&tmp[i][j+2]==flag&&tmp[i][j+3]==flag&&tmp[i][j+4]==flag)
                sum1++;
    for(int i=1; i<=11; ++i) //垂直方向
        for(int j=1; j<=15; ++j)
            if(tmp[i][j]==flag&&tmp[i+1][j]==flag&&tmp[i+2][j]==flag&&tmp[i+3][j]==flag&&tmp[i+4][j]==flag)
                sum1++;
    for(int i=1; i<=11; ++i) //正斜方向
        for(int j=1; j<=11; ++j)
            if(tmp[i][j]==flag&&tmp[i+1][j+1]==flag&&tmp[i+2][j+2]==flag&&tmp[i+3][j+3]==flag&&tmp[i+4][j+4]==flag)
                sum1++;
    for(int i=1; i<=11; ++i) //反斜方向
        for(int j=15; j>=5; --j)
            if(tmp[i][j]==flag&&tmp[i+1][j-1]==flag&&tmp[i+2][j-2]==flag&&tmp[i+3][j-3]==flag&&tmp[i+4][j-4]==flag)
                sum1++;
    mcopy(tmp,A);
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            if(tmp[i][j]==8)
                tmp[i][j]=fflag;
    int sum0=0;
    for(int i=1; i<=15; ++i) //水平方向
        for(int j=1; j<=11; ++j)
            if(tmp[i][j]==fflag&&tmp[i][j+1]==fflag&&tmp[i][j+2]==fflag&&tmp[i][j+3]==fflag&&tmp[i][j+4]==fflag)
                sum0++;
    for(int i=1; i<=11; ++i) //垂直方向
        for(int j=1; j<=15; ++j)
            if(tmp[i][j]==fflag&&tmp[i+1][j]==fflag&&tmp[i+2][j]==fflag&&tmp[i+3][j]==fflag&&tmp[i+4][j]==fflag)
                sum0++;
    for(int i=1; i<=11; ++i) //正斜方向
        for(int j=1; j<=11; ++j)
            if(tmp[i][j]==fflag&&tmp[i+1][j+1]==fflag&&tmp[i+2][j+2]==fflag&&tmp[i+3][j+3]==fflag&&tmp[i+4][j+4]==fflag)
                sum0++;
    for(int i=1; i<=11; ++i) //反斜方向
        for(int j=15; j>=5; --j)
            if(tmp[i][j]==fflag&&tmp[i+1][j-1]==fflag&&tmp[i+2][j-2]==fflag&&tmp[i+3][j-3]==fflag&&tmp[i+4][j-4]==fflag)
                sum0++;
    return val+sum1-sum0;
}
int move1(int A[16][16])
{
    int tmp[16][16],num,ans=INF;
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            if(A[i][j]==8)
            {
                mcopy(tmp,A);
                tmp[i][j]=0; //对手下
                if(check(0,tmp))
                    num=-INF;
                else
                    num=h(1,tmp);
                //cout<<num<<endl;
                ans=min(ans,num);
            }
    return ans;
}
int move0(int A[16][16])
{
    int tmp[16][16],num,ans=INF;
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            if(A[i][j]==8)
            {
                mcopy(tmp,A);
                tmp[i][j]=1; //对手下
                if(check(1,tmp))
                    num=-INF;
                else
                    num=h(0,tmp);
                //cout<<num<<endl;
                ans=min(ans,num);
            }
    return ans;
}
void solve1(Node &node)
{
    int tmp[16][16],f,ans=-INF,anst[16][16]= {};
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            if(node.A[i][j]==8)
            {
                mcopy(tmp,node.A);
                tmp[i][j]=1; //自己下
                if(check(1,tmp))
                {
                    f=move1(tmp);
                    if(f!=-INF)
                        f=INF;
                }
                else
                    f=move1(tmp);
                //cout<<f<<endl;
                if(f>ans)
                {
                    //cout<<f<<endl;
                    ans=f;
                    mcopy(anst,tmp);
                }
            }
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            if(node.A[i][j]!=anst[i][j])
            {
                changex=i;
                changey=j;
                break;
            }
    mcopy(node.A,anst);
    node.f=ans;
    cout<<ans<<endl;
}
void solve0(Node &node)
{
    int tmp[16][16],f,ans=-INF,anst[16][16]= {};
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            if(node.A[i][j]==8)
            {
                mcopy(tmp,node.A);
                tmp[i][j]=0; //自己下
                if(check(0,tmp))
                {
                    f=move0(tmp);
                    if(f!=-INF)
                        f=INF;
                }
                else
                    f=move0(tmp);
                if(f>ans)
                {
                    //cout<<f<<endl;
                    ans=f;
                    mcopy(anst,tmp);
                }
            }
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            if(node.A[i][j]!=anst[i][j])
            {
                changex=i;
                changey=j;
                break;
            }
    mcopy(node.A,anst);
    node.f=ans;
    cout<<ans<<endl;
}
void show(int A[16][16])
{
    int sum=0;
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            sum+=A[i][j];
    if(sum==0)
        cout<<"无法继续!"<<endl;
    else
    {
        for(int i=0; i<=15; ++i)
        {
            for(int j=0; j<=15; ++j)
            {
                if(i==0)
                {
                    cout<<j<<" ";
                    if(j==0)
                        cout<<" ";
                }
                else if(j==0)
                {
                    cout<<i<<" ";
                    if(i<10)
                        cout<<" ";
                }
                else if((i==4&&j==4)||(i==4&&j==12)||(i==12&&j==4)||(i==12&&j==12)||(i==changex&&j==changey))
                {
                    if(A[i][j]==8)
                        cout<<".<";
                    else
                        cout<<A[i][j]<<"<";
                }
                else
                {
                    if(A[i][j]==8)
                        cout<<". ";
                    else
                        cout<<A[i][j]<<" ";
                }
                if(j>9&&i!=0)
                    cout<<" ";
            }
            cout<<endl;
        }
        cout<<endl;
    }
}
int main()
{
    int flag=1,myturn,first=1;
    int i,j;
    Node node;
    for(int i=1; i<=15; ++i)
        for(int j=1; j<=15; ++j)
            node.A[i][j]=8;
    cout<<"程序执黑棋(1)or白棋(0)?";
    cin>>myturn;
    while(1)
    {
        if(flag)
        {
            if(flag==myturn)
            {
                if(first)//人工智能第一次不会走中间,因为中间范围的评价相同,所以第一步要强制下在中间
                {
                    node.A[8][8]=1;
                    first=0;
                }
                else
                    solve1(node);
            }
            else
            {
                cout<<"对方的选择是?";
                cin>>i>>j;
                node.A[i][j]=1;
            }
            show(node.A);
            flag=0;
        }
        else
        {
            if(flag==myturn)
            {
                if(first)
                {
                    node.A[i-1][j-1]=0;
                    first=0;
                }
                else
                    solve0(node);
            }
            else
            {
                cout<<"对方的选择是?";
                cin>>i>>j;
                node.A[i][j]=0;
            }
            show(node.A);
            flag=1;
        }
    }
    return 0;
}

  • 11
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的六子棋人工智能程序实现,采用了极大值极小值算法和α-β剪枝优化。 ``` import numpy as np # 定义棋盘大小 BOARD_SIZE = 15 # 定义棋子类型 WHITE = 1 BLACK = -1 # 定义评估函数 def evaluate(board): # 统计每个玩家的棋子数 white_count = np.sum(board == WHITE) black_count = np.sum(board == BLACK) # 计算得分差 score = white_count - black_count return score # 定义极大值极小值算法 def minimax(board, depth, alpha, beta, is_maximizing): # 判断是否到达搜索深度或者已经有一方胜利 if depth == 0 or check_win(board): return evaluate(board), None # 初始化最佳下棋位置 best_move = None if is_maximizing: # 最大化玩家下棋 value = float('-inf') for move in get_moves(board, WHITE): # 递归调用极大值极小值算法 new_board = make_move(board, WHITE, move) new_value, _ = minimax(new_board, depth - 1, alpha, beta, False) if new_value > value: value = new_value best_move = move alpha = max(alpha, value) if alpha >= beta: break else: # 最小化玩家下棋 value = float('inf') for move in get_moves(board, BLACK): # 递归调用极大值极小值算法 new_board = make_move(board, BLACK, move) new_value, _ = minimax(new_board, depth - 1, alpha, beta, True) if new_value < value: value = new_value best_move = move beta = min(beta, value) if alpha >= beta: break return value, best_move # 定义α-β剪枝优化 def minimax_ab(board, depth, alpha, beta, is_maximizing): # 判断是否到达搜索深度或者已经有一方胜利 if depth == 0 or check_win(board): return evaluate(board), None # 初始化最佳下棋位置 best_move = None if is_maximizing: # 最大化玩家下棋 value = float('-inf') for move in get_moves(board, WHITE): # 递归调用极大值极小值算法 new_board = make_move(board, WHITE, move) new_value, _ = minimax_ab(new_board, depth - 1, alpha, beta, False) if new_value > value: value = new_value best_move = move alpha = max(alpha, value) if alpha >= beta: break else: # 最小化玩家下棋 value = float('inf') for move in get_moves(board, BLACK): # 递归调用极大值极小值算法 new_board = make_move(board, BLACK, move) new_value, _ = minimax_ab(new_board, depth - 1, alpha, beta, True) if new_value < value: value = new_value best_move = move beta = min(beta, value) if alpha >= beta: break return value, best_move # 定义获取可落子位置函数 def get_moves(board, player): moves = [] for i in range(BOARD_SIZE): for j in range(BOARD_SIZE): if board[i][j] == 0: moves.append((i, j)) return moves # 定义落子函数 def make_move(board, player, move): new_board = np.copy(board) new_board[move[0]][move[1]] = player return new_board # 定义判断是否有一方胜利函数 def check_win(board): # 检查行和列 for i in range(BOARD_SIZE): for j in range(BOARD_SIZE - 5): row = board[i][j:j+6] col = board[j:j+6,i] if np.sum(row) == 6 or np.sum(col) == 6: return True if np.sum(row) == -6 or np.sum(col) == -6: return True # 检查对角线 for i in range(BOARD_SIZE - 5): for j in range(BOARD_SIZE - 5): diagonal1 = [board[i+k][j+k] for k in range(6)] diagonal2 = [board[i+k][j+5-k] for k in range(6)] if np.sum(diagonal1) == 6 or np.sum(diagonal2) == 6: return True if np.sum(diagonal1) == -6 or np.sum(diagonal2) == -6: return True return False # 测试程序 def test(): # 初始化棋盘 board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int) # 人工智能为白方 ai_player = WHITE # 游戏循环 while True: # 人工智能下棋 _, move = minimax_ab(board, 3, float('-inf'), float('inf'), True) board = make_move(board, ai_player, move) print("AI move:", move) print(board) # 判断是否游戏结束 if check_win(board): print("AI wins!") break # 玩家下棋 row = int(input("Enter row: ")) col = int(input("Enter column: ")) board[row][col] = BLACK print(board) # 判断是否游戏结束 if check_win(board): print("Player wins!") break if __name__ == "__main__": test() ``` 在测试程序中,人工智能采用了α-β剪枝算法搜索深度为3,可以根据需要进行调整。玩家通过输入行和列来落子,程序会在控制台打印出当前棋盘状态并判断游戏是否结束。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值