首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >TicTacToe AI需要优化

TicTacToe AI需要优化
EN

Code Review用户
提问于 2015-02-11 20:27:28
回答 4查看 2K关注 0票数 10

我如何将这个巨大的怪物浓缩成更易于管理的东西呢?我听说过命令模式,但我不知道如何使用它。还有什么其他的解决办法?

代码语言:javascript
运行
复制
public void AI(){

    count++;
    if(count % 2 == 0){
        letter = "O";
    }

    if(((buttons[1].getText().equals("X") && buttons[2].getText().equals("X"))
        || (buttons[3].getText().equals("X") && buttons[6].getText().equals("X"))
        || (buttons[4].getText().equals("X") && buttons[8].getText().equals("X")))
        &&  buttons[0].getText().equals("")
        ){
        buttons[0].setText("O");
        buttons[0].setEnabled(false);
    } else if(((buttons[0].getText().equals("X") && buttons[2].getText().equals("X"))
            || (buttons[4].getText().equals("X") && buttons[7].getText().equals("X")))
            &&  buttons[1].getText().equals("")
            ){
            buttons[1].setText("O");
            buttons[1].setEnabled(false);
    } else if(((buttons[0].getText().equals("X") && buttons[1].getText().equals("X"))
            || (buttons[4].getText().equals("X") && buttons[6].getText().equals("X"))
            || (buttons[5].getText().equals("X") && buttons[8].getText().equals("X")))
            &&  buttons[2].getText().equals("")
            ){
            buttons[2].setText("O");
            buttons[2].setEnabled(false);
    } else if(((buttons[4].getText().equals("X") && buttons[5].getText().equals("X"))
            || (buttons[0].getText().equals("X") && buttons[6].getText().equals("X")))
            &&  buttons[3].getText().equals("")
            ){
            buttons[3].setText("O");
            buttons[3].setEnabled(false);
    } else if(((buttons[0].getText().equals("X") && buttons[8].getText().equals("X"))
            || (buttons[1].getText().equals("X") && buttons[7].getText().equals("X"))
            || (buttons[3].getText().equals("X") && buttons[5].getText().equals("X"))
            || (buttons[2].getText().equals("X") && buttons[6].getText().equals("X")))
            &&  buttons[4].getText().equals("")
            ){
            buttons[4].setText("O");
            buttons[4].setEnabled(false);
    } else if(((buttons[2].getText().equals("X") && buttons[8].getText().equals("X"))
            || (buttons[3].getText().equals("X") && buttons[4].getText().equals("X")))
            &&  buttons[5].getText().equals("")
            ){
            buttons[5].setText("O");
            buttons[5].setEnabled(false);
    } else if(((buttons[0].getText().equals("X") && buttons[3].getText().equals("X"))
            || (buttons[4].getText().equals("X") && buttons[2].getText().equals("X"))
            || (buttons[7].getText().equals("X") && buttons[8].getText().equals("X")))
            &&  buttons[6].getText().equals("")
            ){
            buttons[6].setText("O");
            buttons[6].setEnabled(false);
    } else if(((buttons[6].getText().equals("X") && buttons[8].getText().equals("X"))
            || (buttons[1].getText().equals("X") && buttons[4].getText().equals("X")))
            &&  buttons[7].getText().equals("")
            ){
            buttons[7].setText("O");
            buttons[7].setEnabled(false);
    } else if(((buttons[2].getText().equals("X") && buttons[5].getText().equals("X"))
            || (buttons[4].getText().equals("X") && buttons[0].getText().equals("X"))
            || (buttons[6].getText().equals("X") && buttons[7].getText().equals("X")))
            &&  buttons[8].getText().equals("")
            ){
            buttons[8].setText("O");
            buttons[8].setEnabled(false);
    } else if(((buttons[1].getText().equals("O") && buttons[2].getText().equals("O"))
            || (buttons[3].getText().equals("O") && buttons[6].getText().equals("O"))
            || (buttons[4].getText().equals("O") && buttons[8].getText().equals("O")))
            &&  buttons[0].getText().equals("")
            ){
            buttons[0].setText("O");
            buttons[0].setEnabled(false);
    } else if(((buttons[0].getText().equals("O") && buttons[2].getText().equals("O"))
            || (buttons[4].getText().equals("O") && buttons[7].getText().equals("O")))
            &&  buttons[1].getText().equals("")
            ){
            buttons[1].setText("O");
            buttons[1].setEnabled(false);
    } else if(((buttons[0].getText().equals("O") && buttons[1].getText().equals("O"))
            || (buttons[4].getText().equals("O") && buttons[6].getText().equals("O"))
            || (buttons[5].getText().equals("O") && buttons[8].getText().equals("O")))
            &&  buttons[2].getText().equals("")
            ){
            buttons[2].setText("O");
            buttons[2].setEnabled(false);
    } else if(((buttons[4].getText().equals("O") && buttons[5].getText().equals("O"))
            || (buttons[0].getText().equals("O") && buttons[6].getText().equals("O")))
            &&  buttons[3].getText().equals("")
            ){
            buttons[3].setText("O");
            buttons[3].setEnabled(false);
    } else if(((buttons[0].getText().equals("O") && buttons[8].getText().equals("O"))
            || (buttons[1].getText().equals("O") && buttons[7].getText().equals("O"))
            || (buttons[3].getText().equals("O") && buttons[5].getText().equals("O"))
            || (buttons[2].getText().equals("O") && buttons[6].getText().equals("O")))
            &&  buttons[4].getText().equals("")
            ){
            buttons[4].setText("O");
            buttons[4].setEnabled(false);
    } else if(((buttons[2].getText().equals("O") && buttons[8].getText().equals("O"))
            || (buttons[3].getText().equals("O") && buttons[4].getText().equals("O")))
            &&  buttons[5].getText().equals("")
            ){
                buttons[5].setText("O");
                buttons[5].setEnabled(false);
    } else if(((buttons[0].getText().equals("O") && buttons[3].getText().equals("O"))
            || (buttons[4].getText().equals("O") && buttons[2].getText().equals("O"))
            || (buttons[7].getText().equals("O") && buttons[8].getText().equals("O")))
            &&  buttons[6].getText().equals("")
            ){
                buttons[6].setText("O");
                buttons[6].setEnabled(false);
    } else if(((buttons[6].getText().equals("O") && buttons[8].getText().equals("O"))
            || (buttons[1].getText().equals("O") && buttons[4].getText().equals("O")))
            &&  buttons[7].getText().equals("")
            ){
                buttons[7].setText("O");
                buttons[7].setEnabled(false);
    } else if(((buttons[2].getText().equals("O") && buttons[5].getText().equals("O"))
            || (buttons[4].getText().equals("O") && buttons[0].getText().equals("O"))
            || (buttons[6].getText().equals("O") && buttons[7].getText().equals("O")))
            &&  buttons[8].getText().equals("")
            ){
                buttons[8].setText("O");
                buttons[8].setEnabled(false);
    } else {

        boolean testing = true;
        for(int i = 0; i < 9; i++){
            if(buttons[i].getText().equals("") && testing == true){
                buttons[i].setText("O");
                buttons[i].setEnabled(false);
                testing = false;
            }
        }       
    }
}
EN

回答 4

Code Review用户

回答已采纳

发布于 2015-02-11 21:06:01

代码中充满了可以删除的重复。只要添加这两种方法,它就会变得更加可读性。

代码语言:javascript
运行
复制
private boolean IsValue(int buttonNumber, String value) {
  return buttons[buttonNumber].getText().equals(value);
}

private void SetValue(int buttonNumber, String value) {
  buttons[buttonNumber].setText(value);
  buttons[buttonNumber].setEnabled(false);
}

这将第一个块更改为:

代码语言:javascript
运行
复制
if (((IsValue(1, "X") && IsValue(2, "X"))
    || (IsValue(3, "X") && IsValue(6, "X"))
    || (IsValue(4, "X") && IsValue(8, "X")))
    &&  IsValue(0, "")) {
  SetValue(0, "O");
}
// ...

在抽动脚趾游戏中,细胞有三种有效的状态。然而,在应用程序中,单元格由字符串表示。这意味着可以存储的值数量是无限的。相反,您可以定义一个enum,以确保不存在无效的值。这意味着在业务逻辑和UI之间进行转换时,您需要做更多的工作,但是可以将其封装到简化大多数应用程序的函数中。

首先,您可以选择将值设置为letter,但永远不要使用它。

逻辑是硬编码的,以检查X和插入O。如果玩家想成为O,会发生什么情况?你的人工智能代码不再工作了。

票数 12
EN

Code Review用户

发布于 2015-02-11 21:03:34

所以你的人工智能基本上是在一排寻找两个,然后阻止那一行,对吗?

在这种情况下,我要做的第一件事是将代码分割成两种方法:setAI (实际上执行AI的移动)和findBlockable (找到一个连续阻止三块的字段)。你可以看看你能不能想出更好的名字。

我还假设您的代码中的counttesting部分没有被实际使用?如果那样的话,我会把它们移走。

不同结构

通常,我会把矩阵看作是结构,而不是数组(因为这就是字段)。然后,您可以以buttons[x][y]的形式访问它,这更有意义。然后,通过迭代x (对于水平的)、y (用于垂直的)以及xy (用于对角线),并计算所设置的部分,就可以解决问题。

如果您愿意,也可以使用将数组索引映射到矩阵索引,然后使用这种方法。

与您的结构

但让我们坚持你的方法。你有一个这样的领域:

代码语言:javascript
运行
复制
0 1 2
3 4 5
6 7 8

因此,每个场由3和它的垂直邻居,4从它的对角线邻居,和1从它的水平邻居分开。因此,您的代码可能如下所示:

代码语言:javascript
运行
复制
public boolean blocksTwoInARow(int i, Button[] buttons) {
    // check horizontal
    if (blocksTwoInARowHelper(i, buttons, 1)) {
        return true;
    }
    // check vertical
    else if (blocksTwoInARowHelper(i, buttons, 3)) {
       return true; 
    }
    // check diagonal
    else if (blocksTwoInARowHelper(i, buttons, 4)) {
        return true;
    }
    return false;
}

public boolean blocksTwoInARowHelper(int i, Button[] buttons, int steps) {
    // TODO bounds check
    int neighborCount = 0;
    for (int j = i - 2*steps; j < i + 2*steps; j+=steps) {
        if (j >= 0 && j < array.length && "0".equals(buttons[j].getText())) {
            neighborCount++;
        }
    }
    return neighborCount == 2;    
}

然后被这样使用:

代码语言:javascript
运行
复制
for(int i = 0; i < buttons.length; i++){
    if (blocksTwoInARow(i, buttons)) {
        buttons[i].setText("O");
        buttons[i].setEnabled(false);
        break;
    }
}

再说一遍,这些名字只是占位符,我相信你能想出更好的一次。

实际上,我认为您的代码更具可读性,但是如果您计划扩展您的字段,这可能会有更大的适应性(尽管如果您确实计划扩展代码,我将使用一个矩阵)。

顺便说一句,tic战术脚趾是一个解决了游戏,所以你可以硬编码这些规则做一个完美的人工智能。当然有点无聊。如果你对人工智能感兴趣,你应该看看min/αβ剪枝算法

票数 10
EN

Code Review用户

发布于 2015-02-11 21:22:23

模型

我强烈建议你从你正在做的任何渲染中抽象出toe模型。看上去你用纽扣来代表董事会。我认为这是好的测试,但它使代码非常丑陋。像这样重复的电话:

代码语言:javascript
运行
复制
buttons[2].getText().equals("X")
buttons[6].getText().equals("X")
buttons[0].setText("O");
buttons[0].setEnabled(false);

不是很好,因为你要求你的渲染信息,关于tic脚趾板的状态。

我建议您将整个模型与呈现分离开来,无论呈现是按钮、精灵,还是控制台。这意味着要创造一些东西,比如tic-tac-脚趾游戏、棋盘和玩家。Game对象可以将BoardPlayers作为对象。Board对象可以表示为行和列,并且可以包含Square (或TileGamePiece)对象,这些对象的状态为X、O和空。

Game将等待每个玩家请求其Move的调用,这也可以表示为一个类。然后Game将在Board上执行该Move并处理结果。通过这种方式,可以轻松地将Player替换为AIPlayer,而无需更改任何其他内容。如果您有一个人工播放器,则您的渲染器或场景或您在顶层拥有的任何东西都可以根据播放机的操作创建这些Move对象,并将这些对象传递给Game。然后,渲染器可以读取更新的Board,然后在屏幕上呈现。

通过这种方式,您可以在不改变抽搐-脚趾游戏模型的情况下,稍后将呈现转换成任何您想要的呈现。

混淆代码

这段代码没有多大意义:

代码语言:javascript
运行
复制
count++;
if(count % 2 == 0){
    letter = "O";
}

看起来你想决定是哪个球员,但我不确定。如果是这样的话,我可能会将该信息作为参数传递到方法中,或者更改变量名来指示实际发生的事情。

这件事也令人困惑:

代码语言:javascript
运行
复制
    boolean testing = true;
    for(int i = 0; i < 9; i++){
        if(buttons[i].getText().equals("") && testing == true){
            buttons[i].setText("O");
            buttons[i].setEnabled(false);
            testing = false;
        }
    }   

如果游戏有某种测试模式,我认为应该将其提取到另一种方法中,并单独调用。

票数 8
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/80302

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档