#java #if-statement #simulation
#java #if-statement #Симуляция
Вопрос:
Я создаю игру в стиле Falling Sand на Java, и у меня возникают странные проблемы с блоком if-else, который у меня есть. В моем методе doGravity () у меня есть различные блоки условий, которые будут вызывать разные вещи, и по какой-то странной причине один блок НИКОГДА не попадает.
Когда я заставляю этот блок подсчитывать, сколько раз выполняется каждое условие, левый и правый блоки попадают почти равномерно:
else if(world[x][y 1]==EMPTY amp;amp; (x-1 >= 0) amp;amp; world[x-1][y 1] == EMPTY amp;amp; (x 1 < world.length) amp;amp; world[x 1][y 1]==EMPTY) {
int r = rand.nextInt(50);
if(r == 0) {
world[x-1][y 1] = world[x][y];
//System.out.println("GO: right");
countRight ;
}
else if(r == 1) {
world[x 1][y 1] = world[x][y];
//System.out.println("GO: left");
countLeft ;
}
else {
world[x][y 1] = world[x][y];
countCenter ;
}
world[x][y] = EMPTY;
}
Далее следует это условие, которое также равномерно распределяет влево и вправо.
else if((x-1 >= 0) amp;amp; world[x-1][y 1] == EMPTY amp;amp; (x 1 < world.length) amp;amp; world[x 1][y 1]==EMPTY) {
if(rand.nextBoolean()) {
world[x-1][y 1] = world[x][y];
//countLeft ;
}
else {
world[x 1][y 1] = world[x][y];
//countRight ;
}
world[x][y] = EMPTY;
}
Но когда я считаю эти блоки, левый блок НИКОГДА не попадает, даже когда пространство слева открыто. Я чувствую, что это, вероятно, просто какая-то глупая опечатка, которую я по какой-то причине не вижу.
else if((x-1 >= 0) amp;amp; world[x-1][y 1] == EMPTY) {
world[x-1][y 1] = world[x][y];
world[x][y] = EMPTY;
countLeft ;
System.out.println("Hit Left");
}
else if((x 1 < world.length) amp;amp; world[x 1][y 1] == EMPTY) {
world[x 1][y 1] = world[x][y];
world[x][y] = EMPTY;
countRight ;
System.out.println("Hit Right");
}
ОБНОВЛЕНИЕ: Если я отмечу left
блок в конце, абсолютно ничего не изменится. Песок действует точно так же. Если я отмечу right
блок в конце, он действует так же, как если бы я отметил оба блока. Я не могу этого понять. Это должно сработать … но этого не происходит.
ОБНОВЛЕНИЕ: Вот полный исходный код. Я понятия не имею, что бы это могло быть. На самом деле, это сведет меня с ума. http://pastebin.com/mXCbCvmb
Комментарии:
1. Получаете ли вы правильные эффекты от блока Countrright ? В частности, имеет ли x разумные значения? Причиной может быть случайное присвоение 0 значению x.
2. Да, в этом аспекте все работает правильно. Если я запущу апплет, вы даже сможете увидеть, как песок падает на пол, начинает скапливаться, затем течет вправо, в то время как левая сторона представляет собой прямую линию. Затем, когда я отмечаю последние два
else if
блока, песок строит башню прямо в воздухе.3. Хорошо, моим последним предположением было бы попытаться удалить else перед левой проверкой if (первая строка последнего фрагмента), на случай, если у вас есть какие-то проблемы с вложенностью if / else.
4. Только что пробовал это, нет, это не то. Я добавил обновление с некоторыми дополнительными экспериментами. Это настоящая головоломка.
5. Что произойдет, если вы закомментируете любое из условий x-1> = 0 и world[…=EMPTY, какое из которых ведет себя неправильно?
Ответ №1:
Ваш код pastebin действительно показывает «Нажать влево», вам просто нужно изменить создание world (строка 65 pastebin) на
world = new Color[worldWidth][worldHeight 1];
Я бы предположил, что из-за части y 1. В остальном она растет как влево, так и вправо.
РЕДАКТИРОВАТЬ: http://pastebin.com/GVmSzN4z Я немного изменил вашу гравитацию, чтобы сделать капли немного более симметричными.
Комментарии:
1. Итак, получается, что левая сторона никогда не попадала под удар из-за того, как работает алгоритм гравитационной обработки. dropParticle () никогда не была проблемой, это просто тот факт, что doGravity () перемещалась слева направо и снизу вверх. Теперь ваша исправленная функция doGravity () работает ужасно медленно, учитывая все, что должно произойти в остальной части скрипта, но это правильная идея. Проблема решена!
2. @Nick, shuffle на самом деле довольно быстрый, просто переместите создание jS = new ArrayList . инициализируйте, и все будет в порядке. Также комментарии Джарродса очень полезны, когда они такие сложные, как этот.
3. Да, вероятно, это все. Я только что заметил значительное падение производительности, как только внедрил вашу версию, но, вероятно, это просто из-за создания переменной внутри метода. Я пытаюсь свести все к примитивам, чтобы заставить его работать быстрее, поэтому повторное создание убивает его.
Ответ №2:
Я не вижу ничего странного в опубликованном коде … однако «else» в начале второго блока заставляет меня думать, что, вероятно, вышеупомянутое условие выполняется в случаях, которые вы хотели бы обработать с помощью «левого» регистра. Какое условие в if
предшествующей этой части?
Редактировать
После проверки вашего полного исходного кода я, наконец, нашел, в чем проблема. Ваша doGravity
функция обновления всегда идет влево-> вправо, и это вносит асимметрию. Изменив его так, чтобы направление обновления чередовалось между left-> right и right-> left для четных / нечетных строк сканирования, асимметрия исчезает.
private void doGravity() {
for(int i = worldHeight - 1; i >= 0; i--) {
if (i % 2 == 0)
{
for(int j = 0; j < worldWidth; j ) {
if(world[j][i] != EMPTY) {
if(hasGravity(world[j][i])) {
dropParticle(j, i);
}
}
}
}
else
{
for(int j = worldWidth-1; j >= 0; --j) {
if(world[j][i] != EMPTY) {
if(hasGravity(world[j][i])) {
dropParticle(j, i);
}
}
}
}
}
}
Комментарии:
1. Я отредактировал его, чтобы включить промежуточный блок. Этот блок также распределен равномерно. Блок только для левой части просто никогда не попадает. Никогда.
2. Я тоже не вижу ничего плохого… какое
if
условие вверху? Весь этот код выполняется только в том случае, если это условие равно false…3. Что ж, весь этот код определенно выполняется.
if
Утверждение являетсяif(y == worldHeight-1)
. Это выполняется только в том случае, если частица находится в самом низу фрейма, что либо a.) удаляет ее, если этаж выключен, либо b.) ничего не делает, если этаж включен. Я могу запустить код, и счетчики работают должным образом в каждом блоке (у меня есть счетчики только в одном разделе за раз), за исключением последнего раздела. Left никогда не выполняется.4. Тогда ваша проблема в чем-то другом. Этот код действительно увеличивает как левый, так и правый счетчики (я скопировал и вставил из вашего вопроса, написал все остальное, необходимое для превращения его в полноценно работающую программу, и протестировал его).
5. Вот код. pastebin.com/mXCbCvmb Однако я уверен, что этот метод вызывает проблемы.
Ответ №3:
Я загрузил ваш код из paste bin. первое, что я сделал, это извлек этот метод и использовал его вместо проверки всех ячеек встроенного массива, чтобы я мог установить точку останова и посмотреть, какие значения для x
и y
и каково содержимое этой индексированной ячейки.
private boolean isEmpty(final int x, final int y)
{
return world[x][y] == EMPTY;
}
Я бы извлек все EMPTY
проверки во что-нибудь более читаемое, такое как isLeftEmpty(x,y)
и isRightEmpty(x,y)
и isNextLeftEmpty(x,y)
это поможет вам рассуждать о правильности вашей логики в вашем коде.
Я бы также извлек (x 1 < world.length)
to isNextXOutsideWorld(x)
, это поможет документировать ваши намерения и поможет с рассуждениями о логике, которую вы намереваетесь использовать.
Это также имеет побочный эффект упрощения логики в if/elseif/else
операторах.
Я провел небольшую отладку, дал ей поработать несколько минут и пришел к выводу, что следующая строка всегда совпадает и заменяет оператор next else if
.
else if ((x 1 < world.length) amp;amp; isEmpty(x 1, y 1) amp;amp;
(x - 1 >= 0) amp;amp; isEmpty(x - 1,y 1))
всегда true, когда я его запускаю, поэтому он никогда не достигает следующего оператора
else if ((x - 1 >= 0) amp;amp; isEmpty(x - 1,y 1))
Я бы попытался разбить каждое из else/if
утверждений на вызовы методов с описательными именами и просто расположить их все по порядку, используя Strategy
шаблон, поскольку все они взаимоисключающие. Такой большой метод определенно вызывает запах кода, усугубляемый всеми этими else/if
блоками, фактор вонючести высок.
Очень сложно экстраполировать предполагаемое поведение из всего шума в if/elseif/else
блоках.