Как заставить объект 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-тест называется базовым случаем вашей рекурсивной функции.