0

我正在编写一个用于解决 Mastermind 游戏的程序。该程序的要点是列出所有可能的解决方案,并在每次猜测不正确后,从列表中删除至少不会给出该解决方案的任何内容。此方法用于比较两个字符串(guess 和 strFromArray)以查看它们是否获得相同的值。但是,我遇到了一个错误,我不知道为什么。任何帮助,将不胜感激。

    Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at Game.shortenTheList(Game.java:88)
at Game.guess(Game.java:76)
at Game.play(Game.java:40)
at Game.main(Game.java:23)


/*
 * Compares the two strings. If they would get the same output, return false. If they would get a different output, return true.
 */
public boolean compare(String guess, String strFromArray, int black, int white)
{
    int white2 = 0;
    int black2 = 0;

    char[] arr1 = guess.toCharArray();
    char[] arr2 = strFromArray.toCharArray();

    for(int i=0; i<guess.length(); i++)
    {
        if(arr1[i] == arr2[i])
        {
            black2 ++;
            arr1[i] = '$';
            arr2[i] = '%';
        }
    }

    for(int i=0; i<guess.length(); i++)
    {
        for(int j=0; j<strFromArray.length(); j++)
        {
            if(arr1[i] == arr2[j])
            {
                white2++;
                arr1[i] = '!';
                arr2[j] = '@';
            }
        }
    }

    if(black == black2 && white == white2)
        return false;

    else
        return true;
}

/*
 * Shortens the list of possible solutions by eliminating everything that wouldn't get at least the given output.
 */
public void shortenTheList(String guess, int black1, int white1)
{
    for (String str : possibleSolutions)
    {
        if(compare(guess, str, black1, white1))
        {
            possibleSolutions.remove(str);
        }
    }
}
4

4 回答 4

8

一旦你打开一个Iterator(你在使用时隐式执行的操作for(String str: possibleSolutions),对基础集合()的任何修改,possibleSolutions除非调用removeIterator都会导致一个ConcurrentModificationException;这在集合类中有非常清楚的记录。

如果您需要从集合中删除项目,请使用显式Iterator

Iterator<String> it = possibleSolutions.iterator();
while(it.hasNext()) {
    if(compare(guess, it.next(), black1, white1))
        it.remove();
}

正如@allprog 指出的那样,当您遇到如此明确的“过滤”问题时,功能方法会更好。在 Java 8 成为一个选项之前,使用 Guava 的Iterables#filterorIterables#removeIf可能是一个不错的选择;您只需包装您的compare方法并将其传递进去。

于 2013-09-10T20:25:09.383 回答
2
/*
 * Shortens the list of possible solutions by eliminating everything that wouldn't get at least the given output.
 */
public void shortenTheList(String guess, int black1, int white1)
{
    for (String str : possibleSolutions)
    {
        if(compare(guess, str, black1, white1))
        {
            possibleSolutions.remove(str);
        }
    }
}

有你的问题。

相反,使用:

/*
 * Shortens the list of possible solutions by eliminating everything that wouldn't get at least the given output.
 */
public void shortenTheList(String guess, int black1, int white1)
{
    Iterator<String> it = possibleSolutions.iterator();
    while(it.hasNext())
    {
        String str = it.next();
        if(compare(guess, str, black1, white1))
        {
            it.remove();
        }
    }
}

这是从您当前正在迭代的集合中删除对象的唯一干净方法。另一种不太优雅的方法是创建一个单独的Strings 列表来删除和迭代它。

于 2013-09-10T20:28:09.747 回答
1

当您使用 foreach 循环遍历它时,您无法修改列表possibleSolutions 。

将您的代码更改为以下内容:

public void shortenTheList(String guess, int black1, int white1)
{    
    for(Iterator<String> it = possibleSolutions.iterator(); it.hasNext()){
        String str = it.next();
        if(compare(guess, str, black1, white1)){
            it.remove();
        }
    }
}
于 2013-09-10T20:28:22.077 回答
0

就像 chrylis 所说,如果不使用迭代器,就无法从集合中删除元素。

例子:

public void shortenTheList(String guess, int black1, int white1)
{
for (String str : possibleSolutions)
{
if(compare(guess, str, black1, white1))
{
possibleSolutions.remove(str);
}
}
}

应该:

public void shortenTheList(String guess, int black1, int white1)
{
Iterator i = possibleSolutions.Iterator();
while(i.hasNext())
{
String str = (String) i.next();
if(compare(guess, str, black1, white1))
{
i.remove();
}
}
}
于 2013-09-10T20:34:56.953 回答