| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: Общие вопросы > игра "точки" -> помогите с заливкой |
| Автор: Immortal 15.8.2003, 12:42 |
| Я вот решился наконец написать логическую игру "точки". Сделал кучу возможно никому и ненужных настроек (размер поля, изменение точек при захвате и многое другое). Написал нерекурсивный и довольно экономичный алгоритм поиска самой короткой линии захвата, но вот одна проблема мне надо залить область ограниченную этими линиям (значения массива 2- линия захвата, 0 - пустая клетка). Я использовал рекурсивную заливку, но она сильно долгая На http://algolist.manual.ru есть хороший (я думаю) алгоритм заливки, но все алгоритмы, что там есть написаны на C, а C я не знаю Если у кого есть предложения по заливке или желание перевести алгоритмы из C в Delphi, то буду благодарен. |
| Автор: <Spawn> 15.8.2003, 12:51 |
| А может можно построить регион(CreatePolygonRgn) по этим точкам и заполнять его функцией FillRgn? Или я что то не так понял? |
| Автор: <Spawn> 15.8.2003, 13:26 | ||
Вот тебе примерчик:
|
| Автор: p0s0l 15.8.2003, 15:49 |
| А я так понял, что у Immortal есть матрица, состоящая из 2 и 0. Например: 0 0 0 0 0 0 0 0 0 0 0 0 2 2 0 0 0 2 0 0 0 0 2 0 0 2 0 2 0 2 2 0 0 2 0 0 0 2 0 0 0 2 0 0 0 2 2 2 0 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 И это должно закраситься вот так: 0 0 0 0 0 0 0 0 0 0 0 0 * * 0 0 0 * 0 0 0 0 * * * * 0 * * * * 0 0 * * * * * * * * * 0 0 0 * * * 0 * * * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Т.е. координаты концов отрезков ему как бы так сразу и неизвестны. Хотя это только предположения... |
| Автор: &-ray 15.8.2003, 19:28 |
| Если это та игра в точки, про которую я думаю, то любую "захваченную" область можно разбить на элементарные составляющие - треугольники. Таким образом, обработав все игровое поле, можно построить соответствующие треугольники с заливкой (используй Canvas.Poligon) |
| Автор: Immortal 15.8.2003, 19:43 |
| Конечно сиасмбо за предоставленную информуцию, но мне нодо нечто иное. У меня есть массив в котором я собираюсь производить заливку в начале кождого хода он пуст (все 0) игра происходит на другом массиве. Как только ставится точка которая образует замкнутую линию, я нахожу эту линию (уже написал алгоритм) и уже тогда эту линию я отмечаю на этом массиве. Точку внутри области я тоже знаю. Мне надо что бы программа из точки внутри прошлась по области оганиченной линией (этими самыми 2), побывав на каждой точке всего желательно один раз. Что программа будет изменять, оказавшись на кождой из внутренних точек это моя забота (там организуется счётчик захваченных тобою точек). Например: 0 0 0 0 0 0 0 2 2 0 0 0 2 * * 2 0 0 2 * * * 2 0 0 2 2 2 0 0 0 0 0 0 0 0 * - точки (элементы массива), которые должны просматриваться прогой. А закрашивать область в какой-то цвет мне совсем не надо За раннее спасибо. |
| Автор: December 15.8.2003, 20:44 | ||
Immortal, Я так понимаю, массивы максимум 100х100 (ни фига себе захват! |
| Автор: Immortal 15.8.2003, 22:51 | ||
| Заливка медленна относительно. Моя заливка такая;
tempArray - мой массив по которому я реализую заливку vector - массив Point с напрвлениями 1. Алгоритм рекурсивный, отсюда следует требуется довольно много памяти; 2. При просмотре окружающих точек за каждый вызов просматриваются 4 точки, отсюда следует, что при захвате области в 100 точек просмотров будут 400. Если ставишь точку ты это работает быстро, но в алгоритме интеллекта таких просмитров будет довольно много. |
| Автор: &-ray 16.8.2003, 22:03 |
| А ты проверял свой код, он рабочий Я имею ввиду: он полностью обходит весь замкнутый "регион" и заполняет массив единицами? Мне кажется, что нет, так как у тебя рекурсия происходит сразу же после первого найденного значения 0 в массиве, и остальные рядом находящиеся ячейки могут так и остаться нулями (а возможно и нет, все зависит от формы "региона" и выбора начальной точки для "заливки") |
| Автор: Immortal 16.8.2003, 22:52 |
| Ты ошибаешься &-ray Рекурсия успешно обходит 4-х связную область. Объясню тебе: да рекурсия вызывается сразу как обнаружит вокруг текущей точки хотя бы один 0, но даже если эта ветка не зальёт всю область, то вокруг этой точки будут проверятся оставшиеся 3 точки и если какая-то будет не залита, то будет создана ещё ветка (я поэтому и написал эту тему в форум, так как в каждом вызове функции приходится просматривать четыре точки вокруг текущей). Такой алгоритм зальёт любую 4-х связную область при любой начальной точки (лишь бы точка была внутри области) Только после такой заливки приходится пробегать всё поле (без этого никак) и очищять от 1 и 2, да и рекурсия долгая и требует много памяти. ------ Я был бы благодарен если бы у кого нибудь нашёлся алгоритм, заливающий область имея в распоряжении массив всех вершин (в данном случае всех точек цепи), Причём желательно без необходиимости временного массива (в рекурсии приходится заполнять 1, что бы она не стала бесконечной). Такой алгоритм есть на http://algolist.manual.ru, но он на C, а я С не знаю. |
| Автор: Medved 16.8.2003, 23:08 |
| Запостите сюда этот код на С, думаю найдутся люди, кому будет не лень перевести. А вообще батенька надо С изучать..... |
| Автор: Immortal 16.8.2003, 23:33 | ||||
Ну ладно я хотел по хорошему, а вы сами напросились
Это заливка графической области по пикселям, но ведь что мне мешает использовать вместо пикселей мои точки. И ещё здесь заливается многоугольник если известны его вершины, а у меня изветно не только это, но и координаты кождого граничащего элемента (точки), може это можно использовать для упрощения. Но это не главное, главное переведите кто-нибудь её на Delphi :-( Кстати к ней пралагалась Сортировка методом распределяющего подсчета:
Help me :-) |
| Автор: December 17.8.2003, 00:16 |
| Вообще, есть замечательная функция FloodFill, она вполне может подойти тебе - если найдёшь её исходники. Она существует с первых версий паскаля и до D7 |
| Автор: Immortal 17.8.2003, 09:27 |
| Я конечно поищу, но FloodFill функция заливки области то есть во время заливки она будет просматривать соседние пиксели на поиск границы, а выше приведённому исходнику насколько я понял нужен только массив вершин. |
| Автор: p0s0l 17.8.2003, 21:02 |
| Immortal, может тебе просто твой Enemy под asm переделать ? Я проверял - ускорение на больших площадях от 3 до 5 раз... |
| Автор: Immortal 17.8.2003, 22:15 |
| Конечно спасибо огромное за совет, но есть онда меленькая проблемка Буду благодарен. |
| Автор: p0s0l 18.8.2003, 11:26 | ||
Т.к. я не знаю структуру твоего массива, то сам подправишь:
Надо вызывать Enemy3. |
| Автор: Immortal 18.8.2003, 13:29 |
| p0s0l спасибо тебе за помощь, но он чёй-то говорит, что не знает, что такое _fld в функции Enemy3, если не трудно посмотри. |
| Автор: p0s0l 18.8.2003, 14:27 |
| Ага, там надо вместо mov esi, [_fld] поставить lea esi, [tmpArray]... |
| Автор: Immortal 18.8.2003, 16:26 |
| asm'овская заливка в среднем на небольших захватах работает в 2-3 раза быстрее, это очень даже не плохие результаты, но последняя просьба |
| Автор: p0s0l 18.8.2003, 17:25 | ||
| Про стек - убери вообще эту константу (_stacksize). Это атавизм - нужен был для проверки больших площадей, чтобы не было stack overflow. Для byte надо изменить начало Enemy3:
Мне интересно узнать: какую область ты заливаешь, например, в таком случае (точку поставят на место плюса): _ _ 2 2 2 _ _ _ (4 области) _ 2 _ _ _ 2 _ _ 2 _ 2 _ 2 _ 2 _ 2 _ _ + _ _ 2 _ 2 _ 2 _ 2 _ 2 _ _ 2 _ _ _ 2 _ _ _ _ 2 2 2 _ _ _ или в таком упрощенном варианте: _ 2 _ 2 _ (2 области) 2 _ + _ 2 _ 2 _ 2 _ И как ты находишь точку внутри захваченной области ? Ведь область может быть какой-нибудь извилистой ? |
| Автор: Immortal 18.8.2003, 17:49 |
| В 1 примере я область не заливаю вообще так как она уже залита раньше, а во втором примере от этой точки по алгоритму А* я ищу все кротчайшие пути в эту же точку Но есть интересная особенность путь продолжается искаться не до прохода в начальную точку, а до соприкосновения с другим путём например: 1 * * * * * * * * 1 * * * 4 * * * * 1 * 4 * 4 * * * * + * * * 3 * * 2 * 3 * 3 * * * 2 * * 3 * * * * * 2 3 * * * В данном случае + это начальная точка а цифры это пути: когда 3 встречается с 4, то считается, что 3-4 пстреча уже есть, в дальнейшем если 3 и 4 ещё встретятся это за замкнутость считаться не будет. Затем 2 встречается с 3 это происходит первый раз и поэтому русуется замкнутость. путь 1 не встечается не с кем и замкнутость не образует. И начсёт точки внутри. Т. к. я ищу только кротчайшие пути, то получается следующее. * * 2 2 2 * * * 2 * * * 2 * * 2 * * о 2 * * * 2 2 2 * * * * * * * * * Я нахожу из всего массива точек замкнутости две которые имеют наибольшую симму координат в данном случае это две нижних правых точки. И беру от них минимальный Х и минимальный Y и получаю координату точки о. * * 2 2 2 * * * 2 * * * 2 * * 2 * * о 2 * * * 2 2 2 2 * * * * * * * * единственный случай когда это не срабоет, но он невозможен, так как путь ищется самый короткий, а самая ижняя левая двойка будет добавлять одно лишнее звено. Если будут ещё вопросы спрашивай, мне будет даже интересно поделиться опытом |
| Автор: p0s0l 18.8.2003, 21:39 |
| Метод интересный, только это быстро работает ? Если хочешь, то я тебе кину еще одну asm-функцию Enemy4 (люблю оптимизировать и ускорять Функция: 1) ищет и заливает незалитые замкнутые области автоматически (не надо давать точку внутри области) 2) возвращает кол-во новых залитых ячеек Т.е. так искать пути, области и точки внутри областей не нужно. Но если у тебя все работает быстро, то тогда лучше оставь как есть, т.к. эта функция работает медленнее: если Enemy3 у меня в среднем 0,1..0,5 мс, то Enemy4 - 1..2 мс... Особенно заметна разница на маленьких площадях, т.к. Enemy4 проверяет всё поле. Если чо, дак сообщи в PM. |