Как убедиться, что следующий элемент в изменяемом массиве действительно следующий при цикле? - PullRequest
1 голос
/ 17 марта 2012

Это должно быть очень просто, но мне нужна помощь. Например, вы храните информацию о монстрах в массиве и выполняете цикл ~, чтобы каждый монстр атаковал / двигался в свою очередь следующим образом

for( i <- 0 to monsters.length-1) monsters(i).act 

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

существует ли какой-либо быстрый / умный способ убедиться, что каждый элемент в массиве будет выполняться один раз и только один раз в цикле, даже если вам действительно пришлось вносить изменения в массив во время цикла?

Ответы [ 7 ]

2 голосов
/ 17 марта 2012

Коллекции Scala, как правило, не предполагают, что вы будете манипулировать ими, когда они используют метод, подобный foreach (или выполняют цикл for). Если вы хотите действовать таким образом, самый простой класс для использования - это Java java.util.concurrent.ConcurrentSkipListMap.

.
// This helps you use Java collections like Scala ones
import collection.JavaConversions._

case class Monster(name: String, hp: Int) {}
val horde = new java.util.concurrent.ConcurrentSkipListMap[Int,Monster]

horde put (0, Monster("wolf",7))
horde put (1, Monster("orc",3))

for (h <- horde) println(h)   // Prints out both

Iterator.iterate(Option(horde.firstEntry)) {
  case None => None
  case Some(e) =>
    val m = e.getValue
    if (m.name=="wolf") horde.remove(1)     // Kill the orc
    else if (m.name=="orc") horde.remove(0) // Kill the wolf
    Option(horde.higherEntry(e.getKey))
}.takeWhile(_.isDefined).foreach(_=>())

for (h <- horde) println(h)   // Prints out just the wolf

Теперь, конечно, это скорее беспорядок, но он работает, и дает хороший случайный доступ к вашим монстрам. Вы должны поддерживать ключи в разумном порядке, но это не так уж сложно.

В качестве альтернативы, как указали другие, вы можете добавить метод isAlive или isDead и действовать только на живых монстров. Затем, после того, как вы один раз прошли список, вы .filter(_.isAlive) выбросили всех мертвых монстров (или .filter(! _.isDead)) и снова запустили его.

2 голосов
/ 17 марта 2012

Я полагаю, что ваш монстр [i] не умрет в свой ход, а скорее от какого-нибудь другого несчастного монстра?

Если вы подсели на массивы или не против времени обработки(а то, что вы делаете, я думаю, вам все равно), просто сохраняйте логическое значение для каждого монстра isDead.Если монстр умирает из-за какого-то ... я не знаю, причина, просто пометьте "isDead" как истину.

Затем, в вашем методе "монстр", просто проверьте, является ли монстр "isDead" или нет.

После каждого цикла вы можете просто обрезать список, чтобы сохранить живых монстров (переместить всех живых существ в новый список и начать заново, обрезать список на месте, что вам проще).

2 голосов
/ 17 марта 2012

Я бы либо использовал условный оператор для проверки свойства монстра isAlive в цикле перед тем, как вызвать act, либо сделал бы эту проверку внутри самого метода act.

1 голос
/ 17 марта 2012

РЕДАКТИРОВАТЬ : Этот первый график неверно истолковывает ваш вопрос.Тем не менее, мое решение все еще должно работать для вас.

То, что вы запрашиваете, - это потокобезопасный массив, который может быть доступен одновременно нескольким «потокам» выполнения.Учитывая, что вы новичок в Java, я предполагаю, что ваша игра не будет многопоточной, и поэтому, если вы удалите элемент в массиве, это обязательно произойдет до запуска следующего цикла.

* 1006Тем не менее, если вы действительно хотите, вы можете добавить булеву функцию «monster.dead» в ваш массив и установить ее в значение true, когда умирает монстр.Тогда в вашем цикле вы скажете:
for( i <- 0 to monsters.length-1) 
    if (monsters[i].dead == false)
        monsters(i).act  

Скорее всего, вы не столкнетесь с этой проблемой.

Редактировать : просто перечитайтеваш пост, и понял, что вы будете удалять монстров, когда ваш массив работает.Помните, что каждая выполняемая вами строка происходит последовательно, поэтому, когда вы удаляете монстров [i], она исчезнет при следующей оценке цикла for.Если у вас есть массив монстров с 5 монстрами в нем, и вы удалите второго, когда цикл снова будет выполнен,

monsters.length - 1  

теперь оценивается в 3.Вы никогда не столкнетесь с моментом, когда попадете на удаленный элемент массива.

0 голосов
/ 17 марта 2012

Удаление элементов из массива , пока зацикливается на нем - это вообще ужасная идея. Что если вы удалите элемент до того, как достигнете его в цикле? Если вы не удалите его до конца цикла или пропустите его?

Я рекомендую что-то еще подобное:

var monsters = ... initial list of monsters ...
monsters = for (m <- monsters; if m.alive) yield { m.act; m }

Используйте преимущества yield и if в сочетании с циклом for, который позволяет создавать новый список.

0 голосов
/ 17 марта 2012

сделать копию исходного массива и пройти копию.если монстр удалит монстра, он будет удален только из оригинала

0 голосов
/ 17 марта 2012

Если вы удалите запись в массиве, этот элемент будет null .
Поэтому вы должны проверить каждый элемент вашего массива, например:

for(int i = 0; i <= array.lenght - 1; i++) {
  // check null
  if(array[i] != null) {
    // do stuff
  }
}

Надеюсь, что этопомогло, повеселись!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...