Как заставить объект Bug двигаться пять раз с помощью рекурсивной функции?

Я изучаю Java из книги Аллена Б. Дауни "Думай о Яве". В главе 5 вводится понятие GridWorld где у вас в основном сетка 10х10 с "актерами", такими как ошибка, сама скала и сетка, которая представляет объекты. Когда код установлен, GridWorld GUI покажет сетку, содержащую двух актеров, "жука" и "рок".

При нажатии на актера появляется выпадающее меню с методами, которые могут быть вызваны для этого актера.

Одним из заданий является написание метода, используя Math.random(); названный randomBug он принимает ошибку в качестве параметра и устанавливает направление ошибки равным 0, 90, 180 или 270, т. е. север, восток, юг, запад, с равной вероятностью, а затем перемещает ошибку, если может.

Следующее задание - изменить randomBug взять целое число n и повторить n раз.

Это мой код:

/* 
 * AP(r) Computer Science GridWorld Case Study:
 * Copyright(c) 2005-2006 Cay S. Horstmann (http://horstmann.com)
 *
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * @author Cay Horstmann
 */

import info.gridworld.actor.ActorWorld;
import info.gridworld.actor.Bug;
import info.gridworld.actor.Rock;

/**
 * This class runs a world that contains a bug and a rock, added at random
 * locations. Click on empty locations to add additional actors. Click on
 * populated locations to invoke methods on their occupants. <br />
 * To build your own worlds, define your own actors and a runner class. See the
 * BoxBugRunner (in the boxBug folder) for an example. <br />
 * This class is not tested on the AP CS A and AB exams.
 */

public class BugRunner
{
    public static void main(String[] args)
    {
        ActorWorld world = new ActorWorld();
        Bug redbug = new Bug();
        world.add(redbug);
        System.out.println(redbug.getLocation());
        world.show();

        randomBug(redbug, Math.random(), 5);
    }

    public static void randomBug(Bug x, double y, int n){

        if (y <= 0.2 && n >= 0){
            x.setDirection(0);
            if (x.canMove()) x.move();
        } else if (y >= 0.3 && y <= 0.5 && n >= 0){
            x.setDirection(90);
            if (x.canMove()) x.move();
        } else if (y >= 0.6 && y <= 0.8 && n >= 0){
            x.setDirection(180);
            if (x.canMove()) x.move();
        } else {
            x.setDirection(270);
            if (x.canMove()) x.move();
        }

        randomBug(x, Math.random(), n-1);

    }


}

Я пытаюсь использовать рекурсивную функцию, чтобы повторить процесс пять раз, поэтому ошибка должна двигаться пять раз, если она не достигает края сетки. Проблема, которая иногда возникает, заключается в том, что ошибка перемещается более 5 раз, она делает 6 или 10 шагов, хотя я ограничил ее с помощью условия n <= 0,

Что я должен изменить или добавить в свой код, чтобы я мог выполнить назначение?

3 ответа

Решение

Прежде всего, вы должны сделать свой код как можно более простым, постараться максимально разделить повторяющиеся элементы (в вашем коде как минимум 2).

Во-вторых, когда ваш n достигает 0, он не проходит все проверки и переходит к условию else. Затем он продолжает идти в этом направлении, пока не может больше. Я удивлен, что вы еще не получили переполнение стека.

в конце ваш код должен выглядеть примерно так:

void randomBug(Bug x, double y, int n)
{
    if( n <= 0 ) //separated repeated use of requirement
        return;

    if( [...] )
        x.setDirection( ... );
    else if ( [...] )
        x.setDirection( ... );
    [ more else ifs as needed ]

    if( x.canMove() ) //separated repeated use of action
        x.move();

    randomBug(x, Math.random(), n-1);
}

Наконец, вы продолжаете проверять, находится ли случайное число между двумя значениями, что не требуется в данном конкретном случае:

if( y <= .25 )
    // do if smaller than .25
else if( y <= .5 ) //no need to check inbetween
    // do if smaller than .5

нет необходимости проверять второй оператор if, если он также больше, чем.25, так как ваша первая проверка уже подтвердила, что это так.

Это немного лучше? Я попробовал, кажется, это работает...

public static void randomBug(Bug x, double y, int n){

        if (n <= 0) return;

        if (y <= 0.2){
            x.setDirection(0);
        } else if (y <= 0.5){
            x.setDirection(90);
        } else if (y <= 0.8){
            x.setDirection(180);
        } else {
            x.setDirection(270);
        }

        if (x.canMove()) x.move();

        randomBug(x, Math.random(), n-1);

    }

Проблема в том, что вы всегда звоните randomBug(x, Math.random(), n-1); в конце. Вы никогда не вернетесь из метода. Это бесконечный цикл.

Чтобы это исправить, я бы удалил n >= 0 проверить из всех веток, и просто добавить этот тест в верхней части функции.

if (n < 0) return; // Or n <= 0?

Этот if-тест называется базовым случаем вашей рекурсивной функции.

Другие вопросы по тегам