Две (любые) области на холсте: выяснить, какая из них больше

Недавно я начал вместе изучать canvas+easeljs и сейчас работаю над 2D-игрой. Игрок (маленький красный прямоугольник) может перемещаться по холсту, и когда он находится «вне» (не рядом) границы, линия рисуется позади него.

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

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

Итак, что мне нужно выяснить:

  • какая площадь меньше/больше
  • подсчитайте шары (маленький красный кружок) в каждой области

Сетка, которая нарисована сзади, предназначена только для того, чтобы облегчить понимание логики, лежащей в основе пользовательского интерфейса: нули представляют собой пустые места (белые прямоугольники), двойки представляют серые прямоугольники (граница и наша линия).

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

Есть ли лучший способ понять это? Может быть, как-то рекурсивно?

Две области, которые мне нужно использовать

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

Ждем любых предложений, спасибо!

EDIT1: игра похожа на эту: http://xonix.vamplabs.com


person trainoasis    schedule 18.12.2013    source источник
comment
Пожалуйста, поделитесь кодом, с которым у вас возникли проблемы.   -  person    schedule 18.12.2013
comment
У меня действительно нет проблем с какой-то конкретной строкой или чем-то еще - я просто не уверен, какой подход выбрать. И код на данный момент составляет 500+ строк, так что, наверное, было бы не очень полезно его публиковать.   -  person trainoasis    schedule 18.12.2013
comment
Не могли бы вы объяснить свою игру лучше. Значит, игрок каким-то образом создает барьерные стены во время движения?   -  person markE    schedule 18.12.2013
comment
@markE Правильно. Он создает стену позади себя, так что теперь мяч может двигаться только в одной из областей, которые созданы этой стеной. И каждый раз, когда он создает стену, мне приходится выяснять, какая стена больше/меньше и есть ли на ней мяч или нет. Игра будет похожа на эту xonix.vamplabs.com Также отредактированный вопрос   -  person trainoasis    schedule 18.12.2013


Ответы (1)


Возможный, но довольно неэффективный подход:

  • Инвертируйте ваше представление для облегчения понимания. Пусть серые клетки равны 0, а белые клетки равны 1.
  • Активировать идентификацию области, когда игрок возвращается к границе. Сделайте временную копию игрового поля. Перебирайте все поле, пока не найдете ячейку с 1. Начните вычислять размер: (не забудьте внести все изменения значений в скопированное поле!)

  • Здесь вы можете попробовать рекурсивный подход. Выберите ячейку «1» и добавьте 1 к переменной счетчика. Поменяйте ячейку на 0 и посмотрите на любую соседнюю ячейку. Рекурсивно разветвляйтесь для любой ячейки со значением «1».

  • Что происходит сейчас, так это то, что вы начали в одной из ваших ОБЛАСТЕЙ и начали заполнять ОБЛАСТЬ «стенами», помня при этом, сколько полей вы заполнили. Из-за ответвления от границы вы должны попасть в любое содержащееся поле, продвигаясь к соседям, не выходя за границы области.

  • Когда область «завершена» (все поля обращены к 0, все рекурсивные ветви возвращены), ваша переменная-счетчик представляет размер области. Вы также можете проверить свои красные шары, перебирая область на предыдущих шагах, чтобы подсчитать их.

  • Чтобы перейти к следующей ОБЛАСТИ, просто снова начните перебирать все поле, пока не нажмете 1, и повторите предыдущие шаги.

  • Когда вы перебираете все поле и не находите 1, вы оцениваете все области и заканчиваете.

Как и предупреждали, ужасно неэффективно, но я не могу сейчас придумать лучшего способа, не сталкиваясь со сложными угловыми случаями...


ОБНОВЛЕНИЕ для уточнения см. комментарии к этому ответу для справки.

Псевдокод для рекурсивной оценки ячеек одной области:

int areaSize = 0;
//find the first starter cell to detect first area
Cell starter = findCellWithValue1();
//if starter is null, no cell with value 1 has been found
if( starter != null ) {
   //feed the starter cell into the recursive function
   areaSize = evaluateCell(starter);
}

int evaluateCell(Cell selected) {
    //counter variable to accumulate branched values
    int counter = 1;
    //set this cell to 0 to not hit it again when evaluating neighbours
    selected.setValue(0);

    //check neighbour to the left
    Cell neighbour = getCellAt(selected.getX()-1, selected.getY());
    if(neighbour.getValue()==1) {
        counter += evaluateCell(neighbour);
    }
    //check neighbour to the right
    neighbour = getCellAt(selected.getX()+1, selected.getY());
    if(neighbour.getValue()==1) {
        counter += evaluateCell(neighbour);
    }
    //check top neighbour
    neighbour = getCellAt(selected.getX(), selected.getY()+1);
    if(neighbour.getValue()==1) {
        counter += evaluateCell(neighbour);
    }
    //check bottom neighbour
    neighbour = getCellAt(selected.getX(), selected.getY()-1);
    if(neighbour.getValue()==1) {
        counter += evaluateCell(neighbour);
    }

    //return accumulated size
    return counter;
}

Это выполнит довольно много ненужных проверок, но я не думаю, что они слишком дороги, если только вы не планируете иметь гигантское игровое поле.

Окончательный размер области будет содержимым переменной areaSize.

person kasoban    schedule 18.12.2013
comment
Проблема в том, как вы узнаете, что пришли во вторую область? Линия, которую вы делаете, может пройти куда угодно, прежде чем достигнет границы. Так что может быть странно понять это, это не всегда прямоугольник - и даже если бы это было так, как вы узнаете, что пришли в Зону 2? извините, я немного озадачен здесь - person trainoasis; 18.12.2013
comment
1-й: с помощью предложенного алгоритма области могут иметь любую форму, если все белые поля области соприкасаются хотя бы сбоку. 2-й: Вы не подходите ко второй области, оценивая одну. Все ваши области окружены нулями, поэтому, когда вы переходите от 1 к 1 при оценке области, вы никогда не выходите за эту окружающую границу. Вы попадете во вторую область только тогда, когда удалите первую область в скопированном поле, а затем снова начнете поиск любой другой области. - person kasoban; 19.12.2013
comment
Постараюсь реализовать предложенное вами сегодня и сообщу - - person trainoasis; 19.12.2013
comment
Хорошо, у меня проблема с вашим алгоритмом. Эта часть, где вы попадаете в 1 ячейку -> и смотрите на любую соседнюю ячейку. Разветвляться рекурсивно для любой ячейки со значением 1. -> Как просмотреть соседнюю ячейку? Хотите каждый раз проверять ВСЕХ соседей? - person trainoasis; 19.12.2013
comment
да. В противном случае вы пропустите угловые случаи. Я обновлю свой ответ небольшим псевдокодом. - person kasoban; 19.12.2013
comment
Привет! Мне удалось рекурсивно посчитать, насколько велика каждая область, на самом деле это было не так уж сложно! Я не использовал копию всего поля, но в противном случае использовал ваш подход. (цифры оставил как были - хотел попробовать как можно скорее :D ) Теперь у меня новая проблема - граница, которую создал игрок, теперь рисуется поверх всего, поэтому игрока не видно при перемещении по новой границе. Вы знаете что-нибудь о многослойности здесь? Но я думаю, что это уже новый вопрос, теперь приму ваш :) спасибо - person trainoasis; 19.12.2013
comment
Единственная проблема, оставшаяся здесь с этим вопросом, заключается в следующем: как сохранить одну определенную начальную точку (индексы) ОБЕИХ областей, чтобы я мог позже решить, в какой области я хочу что-то выполнить… Для первой области это тривиально: сохранить index, где вы нашли первое пустое место. А вторая область? РЕДАКТИРОВАТЬ: Я знаю - здесь пригодится ваш второй холст. И ваш второй счет после первого. это требует времени/ресурсов, но это сработает, да. вы были правы, сэр. Еще раз спасибо (извините за мысли вслух :D) - person trainoasis; 19.12.2013
comment
Пожалуйста. Без сомнения, есть лучший способ сделать это, но это сильно зависит от ваших структур данных и используемых инструментов. - person kasoban; 19.12.2013