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

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

введите здесь описание изображения

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

введите здесь описание изображения

Одно из заданий состоит в том, чтобы написать метод, используя 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.

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


person Community    schedule 16.11.2016    source источник
comment
вы используете хвостовую рекурсию, но рекурсия должна быть завершена с некоторым условием, проверьте n ‹ = 0, проблема заключается в создании другого стека функций для каждого вызова, но остановки нет.   -  person Mithat Konuk    schedule 16.11.2016


Ответы (3)


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

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

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

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, если он также больше 0,25, поскольку ваша первая проверка уже подтвердила, что это так.

person Gelunox    schedule 16.11.2016

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

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

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

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

person marstran    schedule 16.11.2016

Это немного лучше? Я пробовал, вроде работает...

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);

    }
person Community    schedule 16.11.2016