unity井字棋

参数:
1、
board为棋盘参数,用于程序判断棋盘各格状态。
turn指示当前下棋的玩家
mode用于切换游戏模式
initTurn用于切换玩家1先手与后手

private int[,] board = new int[3, 3];               //棋盘3*3
private int turn = 0;                               //轮次
private int mode = 1;                               //模式,切换人人或人机对战
private int initTurn = 0;                           //切换玩家1先手后手

2、
init():
`

  1. void init()
    {
    turn = initTurn;
    for(int temp1 = 0; temp1 < 3; temp1++)
    {
    for(int temp2 = 0; temp2 < 3; temp2++)
    {
    board[temp1, temp2] = 0;
    }
    }
    }`

棋盘初始化函数,将棋盘所有格恢复为初始状态。
3、
checkState():
用于检测当前游戏状态,判断游戏是否进行中或者已经停止。
判断逻辑比较简单,首先判断对角线棋子是否全部相同。
通过遍历的方式同时判断行与列的棋子是否相同,以及统计空白格的数量,提高运行效率。
//检测游戏状态
//返回值: 0-进行中, 1-玩家1获胜, 2-玩家2获胜, 3-平局
int checkState()
{
//判断交叉线是否符合获胜条件
if (board[0, 0] != 0 && board[0, 0] == board[1, 1] && board[0, 0] == board[2, 2])
return board[0, 0];
if (board[2, 0] != 0 && board[2, 0] == board[1, 1] && board[2, 0] == board[0, 2])
return board[2, 0];

    int cnt = 0;
    for (int temp1 = 0; temp1 < 3; temp1++)
    {   
        //判断temp1行是否符合获胜条件
        if (board[temp1, 0] == board[temp1, 1] && board[temp1, 0] == board[temp1, 2] && board[temp1, 0] != 0)
            return board[temp1, 0];
        //判断temp1列是否符合获胜条件
        if (board[0, temp1] == board[1, temp1] && board[0, temp1] == board[2, temp1] && board[0, temp1] != 0)
            return board[0, temp1];
        //统计temo1行的空白格数量
        for (int temp2 = 0; temp2 <3; temp2++)
        {
            if (board[temp1, temp2] == 0)
                cnt++;
        }
    }
    //若空白格已下完,则平局,否则游戏继续进行
    return cnt==0?3:0;
}

}
4、
OnGUI():
搭建游戏UI,也包含了程序的主要运行逻辑,因为OnGUI()每一帧都会运行,由此很适合携带游戏的主要逻辑。
代码上只是组建游戏画面,因此不进行分析。
UI搭建完毕后调用游戏下棋函数。

private void OnGUI()
{
    //小字体初始化
    GUIStyle style = new GUIStyle();
    style.normal.textColor = Color.white;
    style.normal.background = null;
    style.fontSize = 20;

    //大字体初始化
    GUIStyle bigStyle = new GUIStyle();
    bigStyle.normal.textColor = Color.white;
    bigStyle.normal.background = null;
    bigStyle.fontSize = 50;

5、
预先准备两个字体格式
//加载背景
GUI.Label(new Rect(0, 0, 920, 540), Backgroud);

    //加载游戏状态
    int state = checkState();
    switch (state)
    {
        case 0:
            GUI.Label(new Rect(500, 50, 200, 50), "状态: 进行中, 玩家"+(turn+1)+"执棋", style);
            break;
        case 1:
            GUI.Label(new Rect(500, 50, 200, 50), "状态: 玩家1获胜", style);
            break;
        case 2:
            GUI.Label(new Rect(500, 50, 200, 50), "状态: 玩家2获胜", style);
            break;
        case 3:
            GUI.Label(new Rect(500, 50, 200, 50), "结果: 平局", style);
            break;
    }

    //加载标题
    GUI.Label(new Rect(135, 25, 200, 50), "简易井字棋", bigStyle);

    //加载重置按钮
    if (GUI.Button(new Rect(200, 350, 100, 50), "重置"))
        init();

    //加载玩家1选择先手与后手的选项及实现功能
    if (GUI.Button(new Rect(200, 100, 100, 50), "玩家1:先手"))
    {
        initTurn = 0;
        init();
    }
    if (GUI.Button(new Rect(200, 150, 100, 50), "玩家1:后手"))
    {
        initTurn = 1;
        init();
    }

    //加载选择与人或与AI对战模式的选项及实现其功能
    if (GUI.Button(new Rect(200, 225, 100, 50), "玩家2:玩家"))
    {
        mode = 1;
        init();
    }
    if (GUI.Button(new Rect(200, 275, 100, 50), "玩家2:AI"))
    {
        mode = 2;
        init();
    }

对游戏UI进行搭建
//游戏运行逻辑
//mode1: 人vs人
//mode2: 人vsAI
if (mode == 1)
playerVsPlayer();
else
playerVsAIMode();
}
游戏UI搭建完毕后,进入游戏运行逻辑,根据mode的值来进行选择

7、
playerVsPlayer():
PVP对抗函数,以遍历整个棋盘的方式,判断玩家是否落子。
探测到玩家落子后,将棋盘相对应的数据标记为玩家代号,储存玩家身份信息并表示玩家已落子。
每次都会根据棋盘的信息来显示相应的图片(O,X或空白)
//玩家对战游戏逻辑
void playerVsPlayer()
{
//通过遍历所有棋格,判断玩家落子位置
for (int temp1 = 0; temp1 < 3; temp1++)
{
for (int temp2 = 0; temp2 < 3; temp2++)
{
switch (board[temp1, temp2])
{
case 0:
//玩家已落子,更新棋盘
if (GUI.Button(new Rect(450 + temp1 * 100, 100 + temp2 * 100, 100, 100), Space) && checkState() == 0)
{
board[temp1, temp2] = turn + 1;
turn = 1 - turn;
}
break;
case 1:
GUI.Button(new Rect(450 + temp1 * 100, 100 + temp2 * 100, 100, 100), O);
break;
case 2:
GUI.Button(new Rect(450 + temp1 * 100, 100 + temp2 * 100, 100, 100), X);
break;
}
}
}
}

8、
playerVsAIMode():
PVE对抗函数,逻辑与PVP相似,只是在AI回合时会调用AITurn()进行落子

//人机对战游戏逻辑
void playerVsAIMode()
{
    //遍历所有棋格,在玩家回合判断玩家落子位置,在AI回合唤醒AI进行落子
    for (int temp1 = 0; temp1 < 3; temp1++)
    {
        for (int temp2 = 0; temp2 < 3; temp2++)
        {
            switch (board[temp1, temp2])
            {
                case 0:
                    if (turn == 0)
                    {
                        //玩家回合: 
                        if (GUI.Button(new Rect(450 + temp1 * 100, 100 + temp2 * 100, 100, 100), Space) && checkState() == 0)
                        {
                            board[temp1, temp2] = 1;
                            turn = 1;
                        }
                    }
                    else
                    {
                        //AI回合
                        AITurn();
                        turn = 0;
                    }
                    break;
                case 1:
                    GUI.Button(new Rect(450 + temp1 * 100, 100 + temp2 * 100, 100, 100), O);
                    break;
                case 2:
                    GUI.Button(new Rect(450 + temp1 * 100, 100 + temp2 * 100, 100, 100), X);
                    break;
            }
        }
    }
}

9、
AITurn():
AI落子函数,在这个函数中AI会比较简单的选择局部最优的选择,选择逻辑如下。

如果可以获胜,则获胜
对每个空白格进行检测,判断落子后是否可以获胜,若可以,则直接落子。
如果不能获胜,且玩家已将军,则堵上玩家的棋子
在步骤1的基础上,判断空白格如果是玩家落子后,玩家是否会获胜,若玩家会获胜,说明玩家已将军,记下当前位置。
若所有空白格检测完毕后,不能获胜,则选择记下的位置进行落子。
如果既不能获胜,玩家也没有将军,则随机选择一个空白格
在对步骤1, 2进行检测的时候,用mp记下空白格的数量以及空白格的数量cnt。
如果步骤1, 2均不能满足,则产生一个0-cnt之间的随机数rd,从mp取出rd对应的棋子位置,进行落子
//AI回合,AI视棋盘情况进行落子
void AITurn()
{
//游戏不在进行中,不进行落子
if (checkState() != 0)
return;

    /*
     * (tarLoseX, tarLoseY)  玩家下一回合如下此处,玩家将胜利
     * cnt                   棋盘空闲格数量
     * mp                    储存棋盘空闲格位置
     */
    int tarLoseX, tarLoseY, cnt;
    int[] mp = new int[9];
    cnt = 0;
    tarLoseX = tarLoseY = -1;

    //遍历棋盘,计算下一次落子位置
    for(int temp1 = 0; temp1 < 3; temp1++)
    {
        for(int temp2 = 0; temp2 < 3; temp2++)
        {
            if(board[temp1, temp2] == 0)
            {
                //判断AI落子此处是否会胜利,若胜利,则落子
                board[temp1, temp2] = 2;
                if (checkState() == 2)
                    return;

                //判断玩家落子此处是否会胜利,若胜利,则记下当前位置(玩家已将军)
                board[temp1, temp2] = 1;
                if (checkState() == 1)
                {
                    tarLoseX = temp1;
                    tarLoseY = temp2;
                }

                //恢复棋盘,记下当前空白格位置
                board[temp1, temp2] = 0;
                mp[cnt++] = temp1*3+temp2;
            }
        }
    }

    //若存在玩家将军,则落子
    if (tarLoseX != -1) {
        board[tarLoseX, tarLoseY] = 2;
        return;
    }

    //AI落子后既不会胜利,也不存在玩家将军,则随机选择一个空白格落子
    int rd = (int)Random.Range(0, cnt);
    board[mp[rd] / 3, mp[rd] % 3] = 2;
}

完成
``@TOC

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值