首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Tic脚趾对抗Al

Tic脚趾对抗Al
EN

Code Review用户
提问于 2016-10-21 13:26:20
回答 1查看 533关注 0票数 3

我正在做一个可以选择和Al对战的项目,所以我开始在一个单独的类中完成,我只是扩展了主类,它有一个GUI类的对象,它可以绘制按钮和框架。

我的算法工作如下:

一旦一个按钮被点击:

  • 将文本设置为"X“
  • 检查玩家“X”(人类)是否获胜。如果是的话就是这样。如果没有:
    • 检查玩家“O”(计算机)是否有获胜的动作。如果是,那就去做。如果没有:
      • 检查玩家“X”(人类)是否有获胜的动作。如果是的话,就阻止它。如果没有:
        • 选择一个随机/空的地方,并将其文本设置为"O“。
        • 检查玩家“O”(计算机)是否获胜

我想知道是否有任何更新/更改,以改进我的代码,无论是在算法或代码本身。

代码语言:javascript
复制
public class Al extends main implements ActionListener{
int turn=0;
public void actionPerformed(ActionEvent e)
{
    JButton temp=(JButton)e.getSource();
    temp.setEnabled(false);

    temp.setText(turn%2==0?"X":"O");
    if(checkWin(turn%2==0?"X":"O"))
        gui.banner.setText("You won!");
    else{
        if(isClose(turn%2==0?"O":"X",turn%2==0?"O":"X")==false && isClose(turn%2==0?"X":"O", turn%2==0?"O":"X")==false)
            rand(turn%2==0?"O":"X");
        if(checkWin(turn%2==0?"O":"X"))
            gui.banner.setText("You Lost!");
    }

}
Al()
{
    gui.addbanner("Your Turn");
    gui.addnewbutton();
    gui.newgame.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            for(int i = 0;i < 9 ; i++){
                gui.buttons[i].setEnabled(true);
                gui.buttons[i].setBorder(BorderFactory.createBevelBorder(1,Color.black,Color.black));
                gui.buttons[i].setText("");

            }
                gui.banner.setText("Your Turn");
                turn++;
                if(turn%2==1)
                    rand("O");
        }
    });
    for(int i=0;i<9;i++){
        gui.buttons[i].addActionListener(this);
        gui.buttons[i].setText("");         
    }       

}
public Boolean isClose(String me, String al)
{
    for(int i=0;i<9;i++)
    {
        if(i%3==0)
        {
            if(gui.buttons[i].getText()==gui.buttons[i+1].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+2].getText()=="")
            {
                gui.buttons[i+2].setText(al);
                gui.buttons[i+2].setEnabled(false);
                return true;
            }
            if(gui.buttons[i+1].getText()==gui.buttons[i+2].getText()&&gui.buttons[i+1].getText()==me&&gui.buttons[i].getText()=="")
            {
                gui.buttons[i].setText(al);
                gui.buttons[i].setEnabled(false);
                return true;
            }
            if(gui.buttons[i].getText()==gui.buttons[i+2].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+1].getText()=="")
            {
                gui.buttons[i+1].setText(al);
                gui.buttons[i+1].setEnabled(false);
                return true;
            }
        }
        if(i<=2)
        {
            if(gui.buttons[i].getText()==gui.buttons[i+3].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+6].getText()=="")
            {
                gui.buttons[i+6].setText(al);
                gui.buttons[i+6].setEnabled(false);
                return true;
            }
            if(gui.buttons[i+3].getText()==gui.buttons[i+6].getText()&&gui.buttons[i+3].getText()==me&&gui.buttons[i].getText()=="")
            {
                gui.buttons[i].setText(al);
                gui.buttons[i].setEnabled(false);
                return true;
            }
            if(gui.buttons[i].getText()==gui.buttons[i+6].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+3].getText()=="")
            {
                gui.buttons[i+3].setText(al);
                gui.buttons[i+3].setEnabled(false);
                return true;
            }
        }
        if(i==0)
        {
            if(gui.buttons[i].getText()==gui.buttons[i+4].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+8].getText()=="")
            {
                gui.buttons[i+8].setText(al);
                gui.buttons[i+8].setEnabled(false);
                return true;
            }   
            if(gui.buttons[i+4].getText()==gui.buttons[i+8].getText()&&gui.buttons[i+4].getText()==me&&gui.buttons[i].getText()=="")
            {
                gui.buttons[i].setText(al);
                gui.buttons[i].setEnabled(false);
                return true;
            }
            if(gui.buttons[i].getText()==gui.buttons[i+8].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+4].getText()=="")
            {
                gui.buttons[i+4].setText(al);
                gui.buttons[i+4].setEnabled(false);
                return true;
            }
        }
        if(i==2)
        {
            if(gui.buttons[i].getText()==gui.buttons[i+2].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+4].getText()=="")
            {
                gui.buttons[i+4].setText(al);
                gui.buttons[i+4].setEnabled(false);
                return true;
            }
            if(gui.buttons[i+2].getText()==gui.buttons[i+4].getText()&&gui.buttons[i+2].getText()==me&&gui.buttons[i].getText()=="")
            {
                gui.buttons[i].setText(al);
                gui.buttons[i].setEnabled(false);
                return true;
            }   
            if(gui.buttons[i].getText()==gui.buttons[i+4].getText()&&gui.buttons[i].getText()==me&&gui.buttons[i+2].getText()=="")
            {
                gui.buttons[i+2].setText(al);
                gui.buttons[i+2].setEnabled(false);
                return true;

            }   
        }                   
    }
    return false;
}
public void rand(String al)
{
    int x;
    Random random=new Random();

    do
    {
        x=random.nextInt(9)-0;
    }
    while(gui.buttons[x].getText()!="" && isFull()==false);
    if(isFull()==false)
    {
        gui.buttons[x].setText(al);
        gui.buttons[x].setEnabled(false);           
    }


}
public Boolean isFull()
{
    for(int i=0;i<9;i++)
    {
        if(gui.buttons[i].getText()=="")
            return false;
    }
    return true;
}

public boolean lineWin(String player, int i, int j, int k) {
    return gui.buttons[i].getText().equals(player) && gui.buttons[j].getText().equals(player) && gui.buttons[k].getText().equals(player);
}
public void finish(int i, int j, int k)
{
    gui.buttons[i].setBorder(BorderFactory.createBevelBorder(1, Color.CYAN, Color.CYAN));
    gui.buttons[j].setBorder(BorderFactory.createBevelBorder(1, Color.CYAN, Color.CYAN));
    gui.buttons[k].setBorder(BorderFactory.createBevelBorder(1, Color.CYAN, Color.CYAN));

    for(int m=0;m<9;m++)
    {
        gui.buttons[m].setEnabled(false);
    }


}

public Boolean checkWin(String chr){
    if(lineWin(chr,0,1,2))
    {
        finish(0, 1, 2);
        return true;
    }
    if(lineWin(chr,3,4,5))
    {
        finish(3, 4, 5);  
        return true;
    }
    if(lineWin(chr,6,7,8))
    {
        finish(6, 7, 8);
        return true;
    }
    if(lineWin(chr,0,3,6))
    {
        finish(0,3,6);
        return true;
    }
    if(lineWin(chr,1,4,7))
    {
        finish(1,4,7); 
        return true;
    }
    if(lineWin(chr,0,1,2))
    {
        finish(0, 1, 2);
        return true;
    }
    if(lineWin(chr,2,5,8))
    {
        finish(2,5,8);
        return true;
    }
    if(lineWin(chr,0,4,8))
    {
        finish(0,4,8);
        return true;
    }
    if(lineWin(chr,2,4,6))
    {
        finish(2,4,6);
        return true;
    }
    return false; }}
EN

回答 1

Code Review用户

回答已采纳

发布于 2016-10-22 13:55:24

未测试的

我还没有尝试过这些更改,因为如果没有更多的上下文,您的代码就无法运行。如果你提供了其他的课程,我可以运行它们,看看发生了什么。然后,我可以在本地IDE中进行更改,并对它们进行测试(至少最低限度)。实际上,我甚至不能保证这些更改会编译。

对于这样的小程序,请考虑包括问题中的所有代码。对于较大的程序,请考虑链接到具有更多上下文的外部存储库。

不要重复你自己(干)

temp.setText(turn%2==0?"X":"O"); if(checkWin(turn%2==0?"X":"O")) gui.banner.setText("You won!"); else{ if(isClose(turn%2==0?"O":"X",turn%2==0?"O":"X")==false && isClose(turn%2==0?"X":"O", turn%2==0?"O":"X")==false) rand(turn%2==0?"O":"X"); if(checkWin(turn%2==0?"O":"X")) gui.banner.setText("You Lost!"); }

您可以使用并行逻辑多次计算当前和其他播放器。相反,考虑一下

代码语言:javascript
复制
    Player current = (turn % 2 == 0) ? Player.X : Player.O;
    Player other = current.getNext();
    temp.setText(current.toString());
    if (checkWin(current)) {
        gui.banner.setText("You won!");
    } else {
        if (!isClose(other, current) && !isClose(current, other)) {
            rand(other);
        }

        if (checkWin(other))
            gui.banner.setText("You Lost!");
        }
    }

请注意,这还需要一个带有手动定义的Player enum方法的getNext方法。在这种情况下,getNext将返回与current相反的内容。因此,如果currentX,它将返回O,反之亦然。

你可能会问为什么你不能

代码语言:javascript
复制
    String other = (turn%2 == 0) ? "O" : "X";

简短的回答是,你可以这样做,但可能不想这样做。更长远的答案是,这是脆弱的。例如,如果您更改了O首先和X秒,则必须更改原始代码中的每一个事件。在新代码中,你必须改变两个位置。如果您将第二个结果建立在第一个结果的基础上,则两者一起移动。将其移动到enum使您更有可能立即进行任何所需的更改。例如,如果你决定要字母是G和T。

出于类似的原因,最好使用enum,如果您碰巧输入了Y,就会发出抱怨。在这种情况下,当前的代码将悄无声息地无法工作,您必须进行运行时测试来确定原因。修改后的代码将给出编译时错误。

编写!isClose(current, other)比将它与false相比较更有习性。两者都做同样的事情,但前者是更常见的写作方式。

我更喜欢使用带大括号的块窗体,即使单个语句窗体可以工作。我发现它更一致,更容易阅读。此外,单个语句窗体容易受到块窗体不存在的某种类型的编辑错误的影响。

避免幻数

for(int i=0;i<9;i++){ gui.buttons[i].addActionListener(this); gui.buttons[i].setText(""); }

您多次使用此模式。最明显的修正是常量,您可以使用如下

代码语言:javascript
复制
    for (int i = 0; i < BUTTONS_COUNT; i++){
        gui.buttons[i].addActionListener(this);
        gui.buttons[i].setText("");         
    }

然后所有的人都会一起行动。但是实际上我们这里有一个更好的解决方案,它更简单,并且节省了定义一个额外的常量:

代码语言:javascript
复制
    for (JButton button : gui.buttons) {
        button.addActionListener(this);
        button.setText("");         
    }

现在,我们不声明只用于取消数组引用的迭代变量。我们直接处理数组的内容。我们只和那些在那里的人一起工作。如果我们改变棋盘中的方格数,它会自动调整。我们永远不能增加或减少按钮的数量,但忘记了一个地方,我们手动交互。

不要使多个Random对象

Random random=new Random();

如果将它变成类上的static final变量,则只需创建一次并将其种子化。

代码语言:javascript
复制
public static final Random random = new Random();

不要重复工作

我们实际上可以简化整个方法。

int x; Random random=new Random(); do { x=random.nextInt(9)-0; } while(gui.buttons[x].getText()!="" && isFull()==false); if(isFull()==false) { gui.buttons[x].setText(al); gui.buttons[x].setEnabled(false); }

isFull方法每次都会返回相同的结果。所以我们可以先这么做。

代码语言:javascript
复制
    if (isFull())
    {
        return;
    }

    int x;
    do
    {
        x = random.nextInt(9)-0;
    }
    while (gui.buttons[x].getText() != "");

    gui.buttons[x].setText(al);
    gui.buttons[x].setEnabled(false);

这至少节省了对isFull的一个调用,可能还保存了更多。

一种替代的

但是如果我们做不同的检查,我们实际上可以做得更好。

代码语言:javascript
复制
    List<Integer> openSquares = new ArrayList<>();
    for (int i = 0; i < gui.buttons.length; i++) {
        if (gui.buttons[i].getText() == "") {
            openSquares.add(i);
        }
    }

    if (openSquares.isEmpty()) {
        return;
    }

    JButton button = gui.buttons[openSquares.get(random.nextInt(openSquares.size())];

    button.setText(al);
    button.setEnabled(false);

isEmpty检查的结果与isFull检查的结果相同。因此,这样做的效果是什么都不做,如果没有空方块,return,因为板是满的。否则,它会选择一个随机的开方形并对其进行标记。请注意,这只会生成一个随机值。原始代码会一直生成随机值,直到找到一个起作用的值为止。这段代码的平均速度可能较慢,但最坏的情况更好。

干式2

在这个模式中有八个代码块:

if(lineWin(chr,0,1,2)) { finish(0, 1, 2); return true; }

请注意,将相同的三个参数传递给两个单独的方法。考虑把这个重写成这样

代码语言:javascript
复制
    int[] line = {0, 1, 2};
    if (lineWin(chr, line)) {
        finish(line);
        return true;
    }

使用lineWinfinish重写如下

代码语言:javascript
复制
public boolean lineWin(String player, int[] line) {
    for (int square : line)
    {
        if (!gui.buttons[square].getText().equals(player))
        {
            return false
        }
    }

    return true;
}

代码语言:javascript
复制
public void finish(int[] line)
{
    for (int square : line)
    {
        gui.buttons[square].setBorder(BorderFactory.createBevelBorder(1, Color.CYAN, Color.CYAN));
    }

    for (JButton button : gui.buttons)
    {
        button.setEnabled(false);
    }
}

这将确保将相同的值传递给这两个方法。

此外,这允许线的长度,而不是三个方格。

或者类似的东西

代码语言:javascript
复制
    for (Integer[] line : lines) {
        if (lineWin(player, line)) {
            finish(line);
            return true;
        }
    }

    return false;

其中可以定义lines,比如

代码语言:javascript
复制
private static final List<Integer[]> lines = new ArrayList<>();

static {
    lines.add(new Integer[]{0, 1, 2});
    lines.add(new Integer[]{3, 4, 5});
    lines.add(new Integer[]{6, 7, 8});

    lines.add(new Integer[]{0, 3, 6});
    lines.add(new Integer[]{1, 4, 7});
    lines.add(new Integer[]{2, 5, 8});

    lines.add(new Integer[]{0, 4, 8});
    lines.add(new Integer[]{2, 4, 6});
}

这只在应用程序的生存期内完成一次。

或者类似的东西

代码语言:javascript
复制
public class Board {

    private final String[] squares;
    private final List<Integer[]> lines = new ArrayList<>();

    Board(int width, int height) {
        squares = new String[width * height];
        for (int column = 0; column < width; column++) {
            lines.add(makeColumn(column, height, width));
        }

        for (int row = 0; row < squares.length; row += width) {
            lines.add(makeRow(row, width));
        }

        int rightEdge = width - 1;
        if (width >= height) {
            int difference = width - height + 1;
            for (int diagonal = 0; diagonal < difference; diagonal++) {
                lines.add(makeForwardDiagonal(0, diagonal, width, height));
                lines.add(makeBackwardDiagonal(0, rightEdge - diagonal, width, height));
            }
        } else {
            int difference = height - width + 1;
            for (int diagonal = 0; diagonal < difference; diagonal++) {
                lines.add(makeForwardDiagonal(diagonal, 0, width, width));
                lines.add(makeBackwardDiagonal(diagonal, rightEdge, width, width));
            }
        }
    }

    private Integer[] makeBackwardDiagonal(int row, int column, int width, int length) {
        Integer[] line = new Integer[length];
        for (int i = 0; i < length; i++) {
            line[i] = (row + i) * width + column - i;
        }

        return line;
    }

    private Integer[] makeForwardDiagonal(int row, int column, int width, int length) {
        Integer[] line = new Integer[length];
        for (int i = 0; i < length; i++) {
            line[i] = (row + i) * width + column + i;
        }

        return line;
    }

    private Integer[] makeRow(int row, int width) {
        Integer[] line = new Integer[width];
        for (int i = 0; i < width; i++) {
            line[i] = row + i;
        }

        return line;
    }

    private Integer[] makeColumn(int column, int height, int width) {
        Integer[] line = new Integer[height];
        for (int i = 0; i < height; i++) {
            line[i] = i * width + column;
        }

        return line;
    }

}

您可以通过添加

代码语言:javascript
复制
    public static void main(String[] args) {
        Board board = new Board(5, 3);
        for (Integer[] line : board.lines) {
            System.out.println(Arrays.toString(line));
        }
    }

如果需要,我将让您将其集成到您的应用程序中。请注意,一些相关的更改将发生在您发布的类之外。

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

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

复制
相关文章

相似问题

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