简体   繁体   English

如果它在每次迭代后返回到其原始状态,我可以安全地改变我正在迭代的数组吗?

[英]Can I safely mutate an array I am iterating over, if it returns to its original state after each iteration?

I am writing a minimax algorithm for a game in Java, and, for speed purposes, mutating the game state as I recursively work through the decision tree. 我正在为Java中的游戏编写一个minimax算法,并且出于速度目的,当我递归地通过决策树时,改变游戏状态。 However, this involves modifying the list of moves I am iterating over. 但是,这涉及修改我迭代的移动列表。

public int minimax(int currentDepth) {
    if (currentDepth == depth || board.legalMoves.isEmpty()) {
        int eval = board.eval();
        board.takeBack(1);
        return eval;
    }
    int x = Integer.MIN_VALUE;
    for (Tuple move : board.legalMoves) {
        board.move(move);
        x = max(x, -1*minimax(currentDepth+1));
        board.takeBack(1);
    }
    return x
}

The board.move() method mutates the ArrayList legalMoves , but takeBack(1) brings it back to its original state. board.move()方法改变了ArrayList legalMoves ,但takeBack(1)将其恢复到原始状态。 Could this cause any problems? 这会导致任何问题吗?

In a word, yes. 总之,是的。

You don't specify the type of board.legalMoves . 您没有指定board.legalMoves的类型。 You say that it's array, but it can't be, since you're calling isEmpty() on it. 你说它是数组,但它不可能,因为你在它上面调用isEmpty() I therefore suspect that you mean ArrayList . 因此我怀疑你的意思是ArrayList If that's the case, the documentation is pretty clear: 如果是这种情况, 文档很清楚:

The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException . 此类的iteratorlistIterator方法返回的iterator是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的removeadd方法之外,迭代器将抛出ConcurrentModificationException Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future. 因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒着任意的,非确定性行为的风险。

I see two ways around this: 我看到两种解决方法:

1) Avoid structural modifications. 1) 避免结构修改。 In other words, it's OK to change the values of the elements, but it's not OK to add/remove elements. 换句话说,可以更改元素的 ,但添加/删除元素是不行的。

2) Iterate over the ArrayList using indices: 2) 使用索引迭代ArrayList

for (int i = 0; i < board.legalMoves.size(); i++) {
    Tuple move = board.get(i);
    ...
}

Yes, you can but it's dangerous. 是的,你可以,但这很危险。 I suggest to move the minmax algorithm to a new class and pass the data to analyze into the constructor. 我建议将minmax算法移动到一个新类并传递数据以分析到构造函数中。

Now, you can copy the data once in the constructor and the methods can operate on the copy. 现在,您可以在构造函数中复制一次数据,并且方法可以在副本上运行。 The algorithm can now modify the data in any way it wishes, it won't influence other parts of the game or other threads. 该算法现在可以以任何方式修改数据,它不会影响游戏的其他部分或其他线程。 Also, if you have any problems, they must come from the code in one class. 此外,如果您有任何问题,它们必须来自一个类中的代码。

The general goal is to give each modifying part of the code a copy of the data it needs to cut dependencies which can cause trouble. 总体目标是为代码的每个修改部分提供所需数据的副本,以减少可能导致问题的依赖性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM