蛮力青蛙跳跃游戏

时间:2017-02-26 09:33:48

标签: java brute-force

青蛙跳跃的最后一个变体显示在the video的末尾。

  

简而言之,你有一个系列中的 n 数量的百合花垫和一只青蛙   每一个。

     

在最后一个变体(我想要暴力),第二个   第一个和第二个睡莲垫没有青蛙。你的目标是   把所有青蛙都放到同一个睡莲垫上。每只青蛙都可以向右或向左跳   根据其百合垫上的青蛙数量,但不能跳上一个   空百合垫。   
(带1只青蛙的垫子移动1个点,带有n个青蛙的垫子移动 n个点)

     

n = 12的解的例子:( 12以下没有解)

     

[1,0,1,1,1,1,1,1,1,1,0,1] - 开始形成青蛙。 (数数   青蛙从0到11.)
[1,0,1,0,2,1,1,1,1,1,0,1] - 青蛙3.跳跃   右一[1,0,1,0,2,1,2,0,1,1,0,1] - 青蛙7.向左跳   [1,0,1,0,4,1,0,0,1,1,0,1] - 青蛙6.跳左   [5,0,1,0,0,1,0,0,1,1,0,1] - 青蛙4.向左跳   [0,0,1,0,0,6,0,0,1,1,0,1] - 青蛙0.跳到右边   [0,0,1,0,0,0,0,0,1,1,0,7] - 青蛙5.跳到右边   [0,0,1,0,0,0,0,0,0,2,0,7] - 青蛙8.跳到右边   [0,0,1,0,0,0,0,0,0,0,0,9] - 青蛙9.跳到右边   [0,0,10,0,0,0,0,0,0,0,0,0] - 青蛙11.跳左 - 解决了

如果解决方案存在,我想找到n个青蛙的解决方案。我手工知道12,14,15,16,17,18,19,20至少有一个解决方案, 1-11和13没有解决方案。

我尝试编写一段代码,通过所有组合来找到 n 百合花垫的解决方案。

编辑:由于OleV.V.,代码现在可以正常运行,还添加了日志记录。

import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;

// # Brute Force # Brute Force # Brute Force # Brute Force # Brute Force # //
public class Frogger {

    /** 
     * PUBLIC STATIC GLOBAL VARIABLES - Modify these as you wish.
     * 
     * Time Data: Levels < 20 ~ around couple seconds
     *            Level = 20 ~ around a minute
     *            Level = 21 ~ around a quarter of an hour
     *            Level = 22 ~ around a sixth of a minute
     *            Level = 23 ~ around half an hour
     *            Level = 24 ~ around a minute
     * 
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
        public static int Level = 12;
        public static boolean LogSolution = true;
        public static boolean LogAll = false;
    /** * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    // used for logging
    private static Deque<Jump> solution = new ArrayDeque<>(Level);
    private static double time;

    public static void main(String[] args) {

        // log the time
        time = System.currentTimeMillis();

        // build the world & start jumping
        run(Level);
    }

    public static void run(int n) {

        // create the world
        int[] world = new int[n];
        for (int i = 0; i < n; i++) {
            world[i] = 1;
        }
        world[1] = 0;
        world[n-2] = 0;

        // start jumping
        if (Level > 11 && Level != 13) jump(world);
        else System.out.println("Unsolvable");
    }


    //////////////////////////////////////////////////////

    public static void jump(int[] world) {

    for (int i = 0; i < world.length; i++) {

        if (world[i] != 0) { // pad has a frog

            // check if it is solved at current pad
            if (world[i] == Level - 2) {
                System.out.println("SOLUTION: " + Arrays.toString(world));
                System.out.println(solution);
                System.out.println("\n" + (System.currentTimeMillis() - time) / 1000 + " seconds");
                System.exit(0);
            }   

            // roll-back var
            int temp = 0;

            // attempts to make a RIGHT jump 

                if (world[i] + i < world.length) { // right jump is in bound
                    if (world[i + world[i]]  != 0) { // can't jump on empty pad

                        temp = world[i];

                        // jump RIGHT
                        world[i + world[i]] += world[i];
                        world[i] = 0;

                        solution.push(new Jump(temp, i, i + temp)); // log the solution step 1/2
                        if (LogSolution) if (LogAll) System.out.println( "J: " + Arrays.toString(world)); // log the jump

                        // continue jumping
                        jump(world); 

                        // roll-back right jump
                        world[i] = temp;
                        world[i + world[i]] -= world[i];

                        if (LogAll) System.out.println("R: " + Arrays.toString(world)); // log the rollback
                        if (LogSolution) solution.pop(); // log the solution step 2/2
                    }
                }   

            // attempts to make a LEFT jump 

                if (i - world[i] >= 0) { // left jump is in bound
                    if (world[i - world[i]]  != 0) { // can't jump on empty pad

                        temp = world[i];

                        // jump LEFT
                        world[i - world[i]] += world[i];
                        world[i] = 0;

                        if (LogSolution) solution.push(new Jump(temp, i, i - temp)); // log the solution step 1/2
                        if (LogAll) System.out.println("J:" + Arrays.toString(world)); // log the jump

                        // continue jumping
                        jump(world); 

                        // roll-back left jump
                        world[i] = temp;
                        world[i - world[i]] -= world[i];

                        if (LogAll) System.out.println("R: " + Arrays.toString(world)); // log the rollback
                        if (LogSolution) solution.pop(); // log the solution step 2/2
                    }
                }
        }
    }
    }

}

旁注:此问题在所有可解决的 n (所有n> 11,除13之外,有一个解决方案,可通过广义方法访问)进行数学求解。这段代码只是我试图在java中做一些递归。

1 个答案:

答案 0 :(得分:1)

很高兴你得到它的工作。我认为你现在不需要我的代码,但我会在这个答案的底部给出以防万一。

首先,如何记录解决方案?我想你认为最终结果是[0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0]并不是那么有趣;我们想知道它是如何获得的。我将介绍两种方式。

更简单的方法是在尝试时存储每个步骤,然后在回溯时删除它。然后,当您到达解决方案时,您还存储了导致它的步骤。使用堆栈或类似的东西:

private static Deque<Jump> solution = new ArrayDeque<>(Level);

java.util.ArrayDeque是堆栈和队列的推荐类;对于堆栈ArrayList是另一种选择。)现在在代码中,log the jump执行

                    solution.push(new Jump(temp, i, i + temp));

log the rollback

                    solution.pop();

使用一个简单的辅助类Jump,例如:{/ p>

public class Jump {
    int count;
    int from;
    int to;

    public Jump(int count, int from, int to) {
        this.count = count;
        this.from = from;
        this.to = to;
    }

    @Override
    public String toString() {
        return "" + count + " frog/s jump from " + from + " to " + to;
    }
}

当我在我的解决方案中尝试它时,一次搜索花了20%的时间。我说这是可以接受的。如果您非常关注性能,只需在找到解决方案后登出即可。这将要求您返回一个布尔值来表示成功,而不是使用System.exit()来停止搜索。现在您的递归调用变为:

                    if (jump(world)) {
                        solution.push(new Jump(temp, i, i + temp));
                        return true;
                    }

您获得解决方案堆栈中的元素的顺序与之前相反,我希望您能够解决这个问题。而不是System.exit(0);return true;。在方法的底部,返回false。我没有测量性能影响,但我认为与没有记录任何东西相比,它只是微小的。现在您可以得到如下输出:

1 frog/s jump from 3 to 4
1 frog/s jump from 7 to 6
2 frog/s jump from 6 to 4
4 frog/s jump from 4 to 0
5 frog/s jump from 0 to 5
6 frog/s jump from 5 to 11
1 frog/s jump from 8 to 9
2 frog/s jump from 9 to 11
9 frog/s jump from 11 to 2

最后,这是我的方式,只是为了完整起见。我没有发现你的代码有任何有趣的差异。

public static void jump(int[] world) {
    for (int fromIndex = 0; fromIndex < world.length; fromIndex++) { // index of pad to jump from
        // any frog/s here?
        int frogsJumping = world[fromIndex];
        if (frogsJumping > 0) {
            // try to jump left; frogsJumping frogs jump frogsJumping places
            int targetIndex = fromIndex - frogsJumping;
            if (targetIndex >= 0 && world[targetIndex] > 0) { // must not jump to empty pad
                performJump(fromIndex, targetIndex, world, frogsJumping);
            }
            // try a right jump
            targetIndex = fromIndex + frogsJumping;
            if (targetIndex < world.length && world[targetIndex] > 0) {
                performJump(fromIndex, targetIndex, world, frogsJumping);
            }
        }
    }
}

private static void performJump(int fromIndex, int toIndex, int[] world, int frogsJumping) {
    solution.push(new Jump(frogsJumping, fromIndex, toIndex));
    world[fromIndex] = 0;
    world[toIndex] += frogsJumping;
    if (world[toIndex] == noOfFrogs) {
        System.out.println("Solved: " + Arrays.toString(world));
        System.exit(0);
    }
    jump(world);
    // backtrack
    world[toIndex] -= frogsJumping;
    world[fromIndex] = frogsJumping;
    solution.pop();
}