决定最佳玩2人游戏的赢家

时间:2017-11-06 11:09:26

标签: algorithm recursion game-theory minmax

我遇到了this question。根据问题:

  

'samu'和'vibhu'正在玩一个游戏,桌子上有从1到N的N个整数。在每个回合中,玩家可以选择一个整数来标记从之前未访问过的整数。如果在一个回合中,玩家选择一个完成三个连续数字的选择的数字,他就赢了。即,如果玩家现在选择3,则在游戏2和4的某个阶段已经被选中(访问过),他获胜。假设samu首先开始并且两个球员完美地发挥最佳,谁是胜利者。

我尝试应用WL算法(在正确理解之后)described here,即:

boolean isWinning(position pos) {
    moves[] = possible positions to which I can move from the position pos;
    for (all x in moves) 
        if (!isWinning(x)) return true;
    return false; 
}

所以,我的代码是(在适当修改WL算法之后):

public class HelloWorld{

    public static boolean[] visited;
    public static int n;
    public static void main(String []args){

        n=12;
        visited=new boolean[n];
        java.util.Arrays.fill(visited,false);
        for(int i=0; i<n; i++){
            visited[i]=true;
            if(isWinning(i)){
                System.out.println("first one wins");
                System.exit(0);
            }
            visited[i]=false;
        }
        System.out.println("second one wins");
    }

    public static boolean isWinning(int x){
        if(threeStrikes()){
            return true;
        }
        for(int i=0; i<n; i++){
            if(!visited[i]){
                visited[i]=true;
                if(!isWinning(i)){
                    return true;
                }
                visited[i]=false;
            }
        }
        return false;
    }
    public static boolean threeStrikes(){
        for(int i=0; i<n-2; i++){
            if(visited[i]&&visited[i+1]&&visited[i+2]){
                return true;
            }
        }
        return false;
    }
}

问题在于它打印了#34;第一个获胜&#34;对于n = 6。在this discussion线程中,op表示对于n = 6,第二个应该获胜。我不知道他是错了还是我的代码遗漏了什么。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:0)

首先,这是您的代码的修订版:

public class HelloWorld {

    public static boolean[] visited;
    public static int n;
    public static void main(String []args){

        n=12;
        visited=new boolean[n];
        java.util.Arrays.fill(visited,false);
        for(int i=0; i<n; i++){
            visited[i]=true;
            if(!isOpponentWinning()){
                System.out.println("first one wins");
                System.exit(0);
            }
            visited[i]=false;
        }
        System.out.println("second one wins");
    }

    public static boolean isOpponentWinning(){
        for(int i=0; i<n; i++){
            if(!visited[i]){
                visited[i]=true;
                if(threeStrikes() || !isOpponentWinning()){
                    visited[i]=false;
                    return true;
                }
                visited[i]=false;
            }
        }
        return false;
    }
    public static boolean threeStrikes(){
        for(int i=0; i<n-2; i++){
            if(visited[i]&&visited[i+1]&&visited[i+2]){
                return true;
            }
        }
        return false;
    }
}

修改为:

  1. isWinning()实际上是在检查当前玩家的对手是否获胜,因此为了清楚起见,我将其更改为 isOpponentWinning()
  2. 在对手具有 threeStrikes()时返回 true 是错误的,因为它被调用方(获胜者)否定了。因此,当最后一个玩家进行三击时,停止标准现在成立,因此在此处返回正确的结果。
  3. 由于我们要检查对手是否获胜(而不是当前玩家),因此在第一次调用 isOpponentWinning()(在主函数中)时也应添加否定项。
  4. li>
  5. 为了进行正确的回溯,我在visited[i]=false中返回true之前添加了isOpponentWinning()

关于您有关n = 6的问题,的确是第二个应该赢。 假设玩家 A 首先播放,而 B 接下来播放。

  • 如果 A 选择1, B 可以选择4,然后 A 选择下一个 B 的任何人都可以赢下一个回合。
  • 如果 A 选择2, B 可以选择5,然后 A 选择下一个 B 的任何人都可以赢下一个回合。
  • 如果 A 选择3, B 可以选择6,然后 A 选择下一个 B 的任何人都可以赢下一个回合。

其余选项是对称的。 我们知道,无论 A 采取什么行动, B 都能保证获胜。