回溯算法--三连游戏(人机对战)

  程序的核心部分在于计算机如何选择下棋的位置。采用的策略叫作极小极大策略。通过一个赋值函数来给一个位置的“好坏”定值。能使计算机获胜的位置得到值+1;平局得到0;使计算机输棋的位置得到值-1。通过考察盘面就能够确定输赢的位置叫作终端位置。

  如果一个位置不是终端位置,那么该位置的值通过递归假设双方最优棋步而确定。这叫做极小极大策略,因为下棋的一方(人)试图极小化这个位置的值,而另一方(计算机)却要使它的值达到极大。

  采用数组下标1-9代表九个格子,随机生成一个数来确定先手。如果计算机先手,因为此时盘面处于平局,计算机总会选择第一个位置,所以随机生成一个位置给计算机。

头文件

#include <vector>
using namespace std;
class TicTacToe
{
public:

    static const int COMP=1;
    static const int HUMAN=-1;

    TicTacToe():board(10){}

    bool fullBoard()
    {
        for(int i=1;i<=9;++i)
        {
            if(board[i]==0)
                return false;
        }
        return true;
    }
    bool isEmpty(int i)
    {
        if(board[i]==0)
            return true;
        else
            return false;
    }

    void place(int i,int player)
    {
        board[i]=player;
    }

    void unplace(int i)
    {
        board[i]=0;
    }

    bool immediateWin(int & bestMove,int player);


    int findCompMove(int & bestMove);
    int findHumanMove(int & bestMove);

    void setChessPiece(int location,int player);

    void showBoard();

    bool check(int i);

private:

    static const int DRAW=0;
    static const int COMP_WIN=1;
    static const int COMP_LOSS=-1;


    vector<int> board;



};

cpp文件

#include "TicTacToe.hpp"

#include <iostream>
bool TicTacToe::immediateWin(int & bestMove,int player)
{
    for(int i=1;i<=9;++i)
    {
        if(isEmpty(i))
        {
            bool flag=false;
            place(i, player);
            if(i==1)
            {
                if(
                   (board[i]==board[i+1]&&board[i]==board[i+2])
                   ||(board[i]==board[i+3]&&board[i]==board[i+6])
                   ||(board[i]==board[i+4]&&board[i]==board[i+8])
                   )
                {
                    flag=true;
                }

            }
            if(i==2)
            {
                if(
                   (board[i]==board[i+1]&&board[i]==board[i-1])
                   ||(board[i]==board[i+3]&&board[i]==board[i+6])
                   )
                {
                    flag=true;
                }
            }
            if(i==3)
            {
                if(
                   (board[i]==board[i-1]&&board[i]==board[i-2])
                   ||(board[i]==board[i+3]&&board[i]==board[i+6])
                    ||(board[i]==board[i+2]&&board[i]==board[i+4])
                   )
                {
                    flag=true;
                }

            }
            if(i==4)
            {
                if(
                   (board[i]==board[i+3]&&board[i]==board[i-3])
                   ||(board[i]==board[i+2]&&board[i]==board[i+1])
                   )
                {
                    flag=true;
                }

            }
            if(i==5)
            {
                if(
                   (board[i]==board[i+3]&&board[i]==board[i-3])
                   ||(board[i]==board[i-1]&&board[i]==board[i+1])
                   ||(board[i]==board[i-4]&&board[i]==board[i+4])
                   ||(board[i]==board[i-2]&&board[i]==board[i+2])
                   )
                {
                    flag=true;
                }

            }
            if(i==6)
            {
                if(
                   (board[i]==board[i-1]&&board[i]==board[i-2])
                   ||(board[i]==board[i+3]&&board[i]==board[i-3])
                   )
                {
                    flag=true;
                }

            }
            if(i==7)
            {
                if(
                   (board[i]==board[i+1]&&board[i]==board[i+2])
                   ||(board[i]==board[i-6]&&board[i]==board[i-3])
                   ||(board[i]==board[i-2]&&board[i]==board[i-4])
                   )
                {
                    flag=true;                }

            }
            if(i==8)
            {
                if(
                   (board[i]==board[i+1]&&board[i]==board[i-1])
                   ||(board[i]==board[i-6]&&board[i]==board[i-3])
                   )
                {
                    flag=true;
                }

            }
            if(i==9)
            {
                if(
                   (board[i]==board[i-1]&&board[i]==board[i-2])
                   ||(board[i]==board[i-6]&&board[i]==board[i-3])
                   ||(board[i]==board[i-8]&&board[i]==board[i-4])
                   )
                {
                    flag=true;                }

            }

            unplace(i);
            if(flag)
            {
                bestMove=i;
                return true;
            }

        }
    }

    return false;
}

int TicTacToe::findCompMove(int & bestMove)
{
    int i,responseValue;
    int dc;                 //do not care
    int value;

    if(fullBoard())
        value=DRAW;

    else
    {
        if(immediateWin(bestMove, COMP))
            return COMP_WIN;
        else
        {
            value=COMP_LOSS;bestMove=1;

            for(i=1;i<=9;++i)
            {
                if(isEmpty(i))
                {
                    place(i, COMP);
                    responseValue=findHumanMove(dc);
                    unplace(i);
                    if(responseValue>value)
                    {
                        value=responseValue;
                        bestMove=i;
                    }
                }
            }
        }
    }
    return value;

}
int TicTacToe::findHumanMove(int & bestMove)
{
    int i,responseValue;
    int dc;
    int value;

    if(fullBoard())
        value=DRAW;

    else
    {
        if(immediateWin(bestMove, HUMAN))
            return COMP_LOSS;
        else
        {
            value=COMP_WIN;bestMove=1;

            for(i=1;i<=9;++i)
            {
                if(isEmpty(i))
                {
                    place(i, HUMAN);
                    responseValue=findCompMove(dc);
                    unplace(i);
                    if(responseValue<value)
                    {
                        value=responseValue;
                        bestMove=i;
                    }
                }
            }
        }
    }
    return value;

}


void TicTacToe::showBoard()
{
    for(int i=0;i<20;++i)
        cout<<"\n";
    vector<string> out(10);
    for(int i=1;i<=9;++i)
    {
        if(board[i]==0)
            out[i]=' ';
        else if(board[i]==-1)
        {
            out[i]="Ο";
        }
        else
        {
            out[i]="Χ";
        }
    }

    cout<<"________________"<<endl;
    cout<<"| "<<out[1]<<"  | "<<out[2]<<"  | "<<out[3]<<"  |"<<endl;
    cout<<"|    |    |    |"<<endl;
    cout<<"|—-——|—-——|—-——|"<<endl;
    cout<<"| "<<out[4]<<"  | "<<out[5]<<"  | "<<out[6]<<"  |"<<endl;
    cout<<"|    |    |    |"<<endl;
    cout<<"|——-—|—-——|—-——|"<<endl;
    cout<<"|    |    |    |"<<endl;
    cout<<"| "<<out[7]<<"  | "<<out[8]<<"  | "<<out[9]<<"  |"<<endl;
    cout<<"|____|____|____|"<<endl;

}

bool TicTacToe::check(int i)
{
    if(i==1)
    {
        if(
           (board[i]==board[i+1]&&board[i]==board[i+2])
           ||(board[i]==board[i+3]&&board[i]==board[i+6])
           ||(board[i]==board[i+4]&&board[i]==board[i+8])
           )
        {

            return true;
        }

    }
    if(i==2)
    {
        if(
           (board[i]==board[i+1]&&board[i]==board[i-1])
           ||(board[i]==board[i+3]&&board[i]==board[i+6])
           )
        {

            return true;
        }

    }
    if(i==3)
    {
        if(
           (board[i]==board[i-1]&&board[i]==board[i-2])
           ||(board[i]==board[i+3]&&board[i]==board[i+6])
           ||(board[i]==board[i+2]&&board[i]==board[i+4])
           )
        {

            return true;
        }

    }
    if(i==4)
    {
        if(
           (board[i]==board[i+3]&&board[i]==board[i-3])
           ||(board[i]==board[i+2]&&board[i]==board[i+1])
           )
        {

            return true;
        }

    }
    if(i==5)
    {
        if(
           (board[i]==board[i+3]&&board[i]==board[i-3])
           ||(board[i]==board[i-1]&&board[i]==board[i+1])
           ||(board[i]==board[i-4]&&board[i]==board[i+4])
           ||(board[i]==board[i-2]&&board[i]==board[i+2])
           )
        {

            return true;
        }

    }
    if(i==6)
    {
        if(
           (board[i]==board[i-1]&&board[i]==board[i-2])
           ||(board[i]==board[i+3]&&board[i]==board[i-3])
           )
        {

            return true;
        }

    }
    if(i==7)
    {
        if(
           (board[i]==board[i+1]&&board[i]==board[i+2])
           ||(board[i]==board[i-6]&&board[i]==board[i-3])
           ||(board[i]==board[i-2]&&board[i]==board[i-4])
           )
        {

            return true;
        }

    }
    if(i==8)
    {
        if(
           (board[i]==board[i+1]&&board[i]==board[i-1])
           ||(board[i]==board[i-6]&&board[i]==board[i-3])
           )
        {

            return true;
        }

    }
    if(i==9)
    {
        if(
           (board[i]==board[i-1]&&board[i]==board[i-2])
           ||(board[i]==board[i-6]&&board[i]==board[i-3])
           ||(board[i]==board[i-8]&&board[i]==board[i-4])
           )
        {

            return true;
        }

    }
    return false;
}

void TicTacToe::setChessPiece(int location,int player)
{
    if(location>0&&location<10&&isEmpty(location))
    {
        board[location]=player;
    }
    else
    {
        cout<<"try again";
        cin>>location;
        setChessPiece(location, player);
    }
}

main.cpp

#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "TicTacToe.hpp"
using namespace std;
int main()
{
    TicTacToe board;
    board.showBoard();
    int move;

    srand((unsigned)time(NULL));
    bool turn=rand()%2;             //决定先手

    if(turn==0)
    {
        sleep(1.5);
        move=rand()%9+1;            //随机选择一个位置
        board.setChessPiece(move, board.COMP);
        board.showBoard();
        turn=1;
    }
    else
    {
       cout<<"Human First";
    }
    while (1)
    {
        if(turn)
        {
            cin>>move;

            board.setChessPiece(move, board.HUMAN);
            turn=0;
        }
        else
        {
            sleep(1.5);
            board.findCompMove(move);
            board.setChessPiece(move, board.COMP);
            turn=1;
        }

        board.showBoard();

        if(board.check(move))
        {
            if(!turn)
                cout<<"human win"<<endl<<endl;
            else
                cout<<"computer win"<<endl<<endl;
            return 0;
        }
        if(board.fullBoard())
        {
            cout<<"draw"<<endl<<endl;
            return 0;

        }

    }
    return 0;
}

结果


这里写图片描述


这里写图片描述


这里写图片描述


这里写图片描述


这里写图片描述


这里写图片描述


这里写图片描述


这里写图片描述


这里写图片描述


这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
五子棋是一种古老的策略游戏,它是一种简单而又极具深度的游戏。基于α-β剪枝算法的五子棋人机对战是一种比较经典的实现方式。在Python中,我们可以使用对抗搜索和α-β剪枝算法来实现五子棋人机对战。 首先,我们需要创建一个五子棋的棋盘表示,可以使用二维数组来表示。接着,我们需要编写一个评估函数来评估当前棋盘局面的好坏。评估函数可以根据当前棋盘的情况来给出一个分数,用来评估当前局面的优劣。 接下来,我们可以使用递归的方式来实现对抗搜索和α-β剪枝算法。对抗搜索是一种搜索算法,它可以搜索当前局面下的所有可能着法,并根据评估函数来选择最优的着法。而α-β剪枝算法则可以帮助我们剪枝,减少搜索的时间复杂度,从而提高搜索的效率。 在实现对抗搜索和α-β剪枝算法的过程中,我们需要考虑一些细节问题,比如搜索的深度、搜索的时间、剪枝的条件等等。同时,我们还需要处理一些特殊情况,比如提前胜利、防守对方的提前胜利等等。 最后,我们可以将人机对战的整个过程进行封装,让玩家可以和计算机进行五子棋的对战。玩家可以选择先手或者后手,然后通过与计算机进行对战来提高自己的水平。 综上所述,基于α-β剪枝算法的五子棋人机对战的实现,包括棋盘表示、评估函数、对抗搜索和剪枝算法的实现,以及人机对战的封装。这样的实现方式既能提高计算机的对战水平,也能帮助玩家提高自己的棋艺水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值