代表Tic Tac Toe的游戏状态

时间:2009-11-18 22:40:51

标签: java design-patterns optimization

我目前正在为我的Data Structures类工作的作业的目标是创建一个Quantum Tic Tac Toe,其中AI可以获胜。

目前,我在寻找代表州的最有效方式时遇到了一些麻烦。

当前结构概述:

AbstractGame

  • 拥有并管理AbstractPlayers(game.nextPlayer()按int ID返回下一个玩家)
  • 在游戏开始时具有和初始化AbstractBoard
  • 有GameTree(初始化时调用完成,否则不完整)

AbstractBoard

  • 有状态,维度和父母游戏
  • 是播放器和状态之间的中介,(将状态从行集合转换为点表示
  • 是StateConsumer

AbstractPlayer

  • 是国家制作人
  • 有一个ConcreteEvaluationStrategy来评估当前的董事会

StateTransveralPool

  • 预先计算“3态”的可能横截面。
  • 将它们存储在HashMap中,其中Set包含给定“3状态”的nextStates

  • 包含3组 - 一组X-Move,O-Move和棋盘
  • 集合中的每个整数都是一行。这些Integer值可用于从StateTransversalPool
  • 获取下一个行状态

所以原则是 每行可以用二进制数000-111表示,其中0表示开放空间,1表示封闭空间。

因此,对于不完整的TTT板:

From the Set<Integer> board perspective:
X_X  R1 might be: 101
OO_  R2 might be: 110
X_X  R3 might be: 101, where 1 is an open space, and 0 is a closed space

From the Set<Integer> xMoves perspective:
X_X  R1 might be: 101
OO_  R2 might be: 000
X_X  R3 might be: 101, where 1 is an X and 0 is not

From the Set<Integer> oMoves perspective:
X_X  R1 might be: 000
OO_  R2 might be: 110
X_X  R3 might be: 000, where 1 is an O and 0 is not

然后我们看到x {R1,R2,R3}&amp; o {R1,R2,R3} =&gt;板{R1,R2,R3}

问题是快速生成GameTree的下一个状态。如果我有玩家Max(x)与棋盘{R1,R2,R3},那么获得R1,R2和R3的下一个行状态很简单..

Set<Integer> R1nextStates = StateTransversalPool.get(R1); 

问题是我必须将这些状态中的每一个与R1和R2组合在一起。

除了我可以使用的Set之外,还有更好的数据结构吗?总的来说是否有更有效的方法?我还发现Point&lt; - &gt;州调解很麻烦。我可以尝试另一种方法吗?

谢谢!

这是我的ConcretePlayer类的代码。它可能有助于解释玩家如何通过移动产生新状态,使用StateProducer(可能需要成为StateFactory或StateBuilder)。

public class ConcretePlayerGeneric extends AbstractPlayer {

 @Override
 public BinaryState makeMove() {
  // Given a move and the current state, produce a new state
  Point playerMove = super.strategy.evaluate(this);
  BinaryState currentState = super.getInGame().getBoard().getState();


  return StateProducer.getState(this, playerMove, currentState);
 }
}
编辑:我从正常的TTT开始,转向量子TTT。给定框架,它应该像创建几个新的Concrete类和调整一些东西一样简单。

2 个答案:

答案 0 :(得分:3)

我的建议:

  • 考虑表示单个方块而不是行,+1 == O-1 == X0表示空方块。 这允许您通过检查水平,垂直或对角线行的总和是等于+3还是-3来检测结束状态
  • 其次将这个2D 3x3矩阵“展平”为单个数组,其中元素[0-2]代表第一行,元素[3-5]代表第二行,元素[6-8]代表第三行。 / LI>
  • 根据董事会的当前状态,使用递归或迭代方法生成后续游戏状态。

修改

我感到无聊,于是决定写一些“玩具代码”来实现游戏板,包括确定它是否处于终端状态的方法,以及在下一次移动后生成一组板状态。它应该推广到任何规模的董事会,虽然我没有尝试过。享受......

示例输出

$ java Board
Creating board:

---
---
---

Initialising board:

-OX
O--
XO-
Terminal state: false


Generating next move states:

XOX
O--
XO-

-OX
OX-
XO-

-OX
O-X
XO-

-OX
O--
XOX

<强>代码

import java.util.List;
import java.util.LinkedList;
import java.util.Random;

public class Board {
    private final int[] squares;

    public Board() {
    this.squares = new int[9];
    }

    protected Board(int[] squares) {
    this.squares = squares;
    }

    public void init() {
    Random rnd = new Random();
    int turn = 1; // 'O' always goes first.

        for (int i=0; i<squares.length; ++i) {
        double d = rnd.nextDouble();

        if (d < 0.75) {
        squares[i] = turn;
        turn = turn == 1 ? -1 : 1; // Flip to other player's turn.
        } else {
        squares[i] = 0; // Empty square.
        }

        if (isTerminalState()) {
        break;
        }
    }
    }

    public boolean isTerminalState() {
    boolean ret = false;

    boolean foundEmpty = false;
    int hSum = 0;
    int[] vSum = new int[3];

    for (int i=0; i<squares.length; ++i) {
        hSum += squares[i];

        if (isWinningRow(hSum)) {
        ret = true;
        break;
        } else if (i == 2 || i == 5) {
        hSum = 0;
        }

        int col = i % 3;
        vSum[col] += squares[i];

        if (isWinningRow(vSum[col])) {
        ret = true;
        break;
        }

        if (squares[i] == 0) {
        foundEmpty = true;
        }
    }

    if (!ret) {
        if (!foundEmpty) {
        ret = true;
        } else {
        int diag1 = 0;
        int diag2 = 0;
        int rowSz = (int)Math.sqrt(squares.length);

        for (int i=0; i<squares.length; ++i) {
            if (i % (rowSz + 1) == 0) {
            diag1 += squares[i];

            if (isWinningRow(diag1)) {
                ret = true;
                break;
            }
            }

            if (i > 0 && i % (rowSz - 1) == 0) {
            diag2 += squares[i];

            if (isWinningRow(diag2)) {
                ret = true;
                break;
            }
            }
        }
        }
    }

    return ret;
    }

    private boolean isWinningRow(int rowSum) {
    return rowSum == 3 || rowSum == -3;
    }

    public List<Board> getNextStates() {
    List<Board> ret = new LinkedList<Board>();

    int tmp = 0;
    for (int i=0; i<squares.length; ++i) {
        tmp += squares[i];
    }

    // Next turn is 'O' (i.e. +1) if the board sums to 0.
    // Otherwise it's 'X's turn.
    int turn = tmp == 0 ? 1 : -1;

    if (!isTerminalState()) {
        for (int i=0; i<squares.length; ++i) {
        if (squares[i] == 0) { // Empty square          
            int[] squaresA = new int[squares.length];
            System.arraycopy(squares, 0, squaresA, 0, squares.length);
            squaresA[i] = turn;
            ret.add(new Board(squaresA));
        }
        }
    }

    return ret;
    }

    public String toString() {
    StringBuilder sb = new StringBuilder();

    for (int i=0; i<squares.length; ++i) {
        if (squares[i] == 1) {
        sb.append('O');
        } else if (squares[i] == -1) {
        sb.append('X');
        } else {
        assert squares[i] == 0;
        sb.append('-');
        }

        if (i == 2 || i == 5) {
        sb.append('\n');
        }
    }

    return sb.toString();
    }

    public static void main(String[] args) {
    System.err.println("Creating board:\n");
    Board bd = new Board();
    System.err.println(bd);

    System.err.println("\nInitialising board:\n");
    bd.init();
    System.err.println(bd);
    System.err.println("Terminal state: " + bd.isTerminalState() + '\n');

    System.err.println("\nGenerating next move states:\n");
    List<Board> nextStates = bd.getNextStates();

    for (Board bd1 : nextStates) {
        System.err.println(bd1.toString() + '\n');
    }
    }
}

答案 1 :(得分:0)

每个方格不应只有三种可能的状态(,X,O)吗?

存储三态方格的网格,或存储2个移动列表。您不需要存储整个电路板,因为它是由移动定义的。

另外,你的意思是:

  

为...生成下一个状态   对局树

什么是GameTree?什么是“下一个州”的例子?