Помощь - Поиск - Пользователи - Календарь
Полная версия: Наложение фигур
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
ТОХА
Здравствуйте!
при написании одного из модулей программы я столкнулся с такой проблемой как наложение фигур друг на друга. Как сделать так чтоб последующая фигура рисовалась на свободном месте экрана и не накладывалась на другие?
 uses Crt, Graph;
const k=100;
var
GraphDriver, GraphMode: Integer;
X1,y1, r: Integer;ch:char;
begin
GraphDriver := Detect;
InitGraph(GraphDriver, GraphMode, ' ');
if GraphResult<> grOk then
Halt(1);
repeat
ch:=readkey;
if ch=chr(13) then begin
X1 := Random(640-k)+k;
y1 := Random(480-k)+k;
r:=Random(k)+1;
circle(X1,y1,r);
end;
until ch=chr(27);
CloseGraph;
end.
мисс_граффити
фигуры - только круги? а что делать, если свободных мест не осталось вообще?
ТОХА
да, только круги
это просто часть моей игры на запоминание, сделаю их такого размера чтоб в районе 50 вмещалось, больше запомнить будет просто невозможно)
volvo
Если только круги - то можно сделать
что-то типа вот такого... (Показать/Скрыть)

Не забудь добавить проверку, чтоб цикл заканчивался после отрисовки максимум maxCircles кругов, иначе будут проблемы.
ТОХА
Цитата(volvo @ 28.03.2011 23:39) *

uses
(sqr(C[i].X - X1) + sqr(C[i].Y - Y1) > sqr(R + C[i].R))


Откуда такая интересная формула, если не секрет smile.gif
З.Ы. спасибо, сам бы не додумался
volvo
Чего ж тут такого особенного? Чистая логика. Когда новая окружность не будет пересекаться с уже отрисованной? Правильно, когда расстояние между центрами окружностей больше суммы их радиусов. Причем это должно проверяться для ВСЕХ уже отрисованных объектов.

Чтоб не вычислять квадратный корень, я оставил квадрат расстояния между центрами. Значит, сравнивать его надо с квадратом суммы радиусов. Всё просто.
ТОХА
точно это ж геометрия за 8 класс smile.gif
TarasBer
> repeat
random...
until ok;

Предлагаю придумать не потенциально-бесконечный алгоритм.
volvo
Цитата
Предлагаю придумать не потенциально-бесконечный алгоритм.
Не проблема. Только не надо мне рассказывать ,что "в некотором царстве, в некотором государстве" Random может бесконечно возвращать значения, большие некоего порога. Давай будем реалистами: Random - это генератор, который возвращает равномерно-распределенные случайные числа. То есть, в какой-то момент времени он вернет и 1, и 2, и 4, и 10.

Тогда для того, чтоб алгоритм стал НЕ потенциально бесконечным, достаточно, чтобы выполнялось условие
maxCircles * Pi * K2 < GetMaxX * GetMaxY

То есть, либо уменьшаем K до [Sqrt(GetMaxX * GetMaxY / (50 * Pi))] = 44

, либо уменьшаем MaxCircles до [GetMaxX * GetMaxY / (50 * K2)] = 9

, либо увеличиваем GetMaxX * GetMaxY так, чтобы их произведение превышало 1570797. С современными мониторами и компиляторами это ни разу не проблема: любой широкоформатный монитор выдаст разрешение 1920*1024, и GetMaxX * GetMaxY = 1963137. Опять никакого шанса алгоритму стать бесконечным...

Я уж не говорю о том, что можно одновременно уменьшить и радиус и maxCircles...
TarasBer
> Random - это генератор, который возвращает равномерно-распределенные случайные числа

Не случайные, а ПСЕВДОслучайные.
Будут ли тройки последовательно возвращаемых значений равномерно распределены?
Позволяют ли внутренние особенности именно данной реализации алгоритма надеяться на отсутствие возможности зацикливания?
ТОХА
смысл игры в том, что нужно запомнить какой шарик появился на поле и щелкнуть на него(пока вместо мыши энтер), я сомневаюсь что есть люди которые дойдут до зацикливания
TarasBer, надеюсь я ответил на твой вопрос


осталось добавить мышку и небольшое мигание перед появлением каждого из шариков для усложнения запоминания, как закончу скину smile.gif
TarasBer
> TarasBer, надеюсь я ответил на твой вопрос

Нет, вопрос был не об этом. Вопрос был в том, что сама концепция выполнения случайного действия до выполнения какого-то условия мне видится сомнительной. Кто сказал, что условие когда-либо выполнится, мало ли как случайное действие себя вести будет?
volvo
Цитата
сама концепция выполнения случайного действия до выполнения какого-то условия мне видится сомнительной
Это твои заморочки. Оно ОБЯЗАНО отработать по изложенным выше причинам. А отработает оно за 0.0002 сек. или за 0.05 сек - это дело десятое (в данном конкретном случае), время реакции человека все равно гораздо больше.

Проверил на своей машине: сгенерировал (без вывода на экран) 50 окружностей, в цикле. Цикл прогнал 10000 раз. А потом - полтора миллиарда раз. И в первом и во втором случае среднее время генерации всех 50 окружностей приблизительно одно и то же. Если алгоритм за полтора миллиарда испытаний не дает не только сбоя (коим здесь является "вечный цикл"), но даже ощутимого увеличения времени выполнения - я бы его использовал без сомнений... Но если очень хочется пойти другим путем - изобретайте очередной велосипед... Меня эта отрасль машиностроения не интересует уже давно...
ТОХА
небольшой оффтоп
как пользоваться коммандой MouseIn для кругов и эллипсов?представлять их в виде многоугольников и ставить условие под каждый угол или же есть способ проще?
просто точность попадания в многоугольник будет зависеть от количества углов, а проверок получается очень много)
TarasBer
> Это твои заморочки. Оно ОБЯЗАНО отработать по изложенным выше причинам.

Причины недостаточно доказаны.

> А отработает оно за 0.0002 сек. или за 0.05 сек - это дело десятое (в данном конкретном случае)

Лишь бы раз в год оно не заработало за 50 сек.

> Проверил на своей машине: сгенерировал (без вывода на экран) 50 окружностей, в цикле. Цикл прогнал 10000 раз. А потом - полтора миллиарда раз. И в первом и во втором случае среднее время генерации всех 50 окружностей приблизительно одно и то же.

Возьми не среднее, а максимальное. А потом возьми другой ГСЧ, для него придётся доказывать всё по новой.

Это хорошо, что полтора миллиарда испытаний отработали как надо, но всё-таки само понятие случайного числа противоречит понятию алгоритма, и завязывание жизненно важных участков алгоритма на случайные числа лишает алгоритм права называться алгоритмом, поскольку делает его поведение непредсказуемым.
Ты математически можешь доказать, что алгоритм гарантировано даст нужный результат не более, чем за эн тактов процессора (или итераций цикла, или ещё каких-то условных единиц)? Нет, не можешь. Поэтому с такими алгоритмами надо быть очень осторожными. И если есть обходные пути, работающие за разумное время - то надо их искать. Иначе на этом алгоритме надо огромными красными буквами писать, что так как он основан на случайных событиях, то он ничего не гарантирует.

Добавлено через 2 мин.
> как пользоваться коммандой MouseIn для кругов и эллипсов?

Чтобы узнать, что точка с координитами mx, my попала в эллипс с центром в точке x, y и полуосями rx, ry, надо сравнить

sqr((mx-x)/rx) + sqr((my-y)/ry)

с единицей.
ТОХА
Спасибо )
ТОХА
немного запутался и возникло 2 проблемы:
мышь ползает только по верхней половине экрана
программа виснет после появления 8 шарика, почему именно 8 я без понятия
буду благодарен если кто-нить посмотрит))
volvo
Цитата
Возьми не среднее, а максимальное
Максимальное время различается не больше, чем на 20%. С учетом того, что речь идет о тысячных долях секунды - это не критично. Я тебе уже говорил, где нужна шлифовка тактов. В прикладной программе, которая ожидает реакции пользователя, я этим заниматься не собираюсь. И тебе не советую.

Цитата
А потом возьми другой ГСЧ, для него придётся доказывать всё по новой.
Вот когда мне понадобится другой ГСЧ, и я получу его реализацию - я буду думать над этим. Решаем проблемы по мере поступления. А то ведь теоретически можно придумать такой ГСЧ, что он ЛЮБОЙ алгоритм (вообще любой, не только по этой задаче) запорет. Вот и сиди, и доказывай правильность алгоритма для ВСЕХ ВОЗМОЖНЫХ генераторов. У меня есть более интересные занятия.

А пока - перечитай первый абзац этого сообщения и первый абзац сообщения №9. Вот ты и начал мне рассказывать, что "где-то существует другой ГСЧ, который..." Я не пользуюсь другим. Я использую стандартный Random (который использовал еще в 1987 году, и до сих пор в учебных программах он меня более чем устраивает. В реальных - используются совершенно другие генераторы, и совершенно другие алгоритмы). Если б я написал свою функцию GetRandomNumber (пусть даже в ней был бы вызов того же Random-а) - у тебя был бы повод придраться, ибо я хоть какую-то возможность смены генератора предполагаю. Сейчас у тебя его нет, ибо я однозначно дал понять: использовать другой генератор не собираюсь, в коде жестко прописан тот, что есть. Так что про "другой ГСЧ" - это даже не обсуждается...

Цитата
программа виснет после появления 8 шарика, почему именно 8 я без понятия
Потому что у тебя генерация X, Y, R должна быть внутри repeat/until, а ее там нет. И что получилось? Сгенерированы значения, проверено по формуле, получено Ok = False. Ты опять присваиваешь Ok := True, и для тех же X, Y, R что и прежде, начинаешь проверку. Это неправильно. Надо сгенерировать другие значения для новой окружности, и проверять уже для них...
ТОХА
нашел, исправил, а что делать с мышкой?
TarasBer
> Максимальное время различается не больше, чем на 20%.

Ну если ты перебрал при этом все 4 млрд возможных стартовых состояния ГСЧ, то это подойдёт, как доказательство.

> Я тебе уже говорил, где нужна шлифовка тактов.

Как будто мне она тут нужна. Чё сразу - раз ТарасБер, значит шлифовка тактов?
Мне не нужно, чтобы раз в год программа затупливала на минуту. Конечно, когда пишешь игрушку, на это вообще все кладут - у 10 игроков игра упала, у 90 отработала, вот и зашибись. А в серьёзном программировании так нельзя.
ТОХА
мышку одолел,

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

можно ли рисовать черный прямоугольник на весь экран на секунду а потом убирать его и чтоб на нем сохранилось все что было до его рисования?
volvo
Цитата
можно ли рисовать черный прямоугольник на весь экран на секунду а потом убирать его и чтоб на нем сохранилось все что было до его рисования?
Вообще самым оптимальным было бы использовать граф. режим, в котором есть больше одной видеостраницы. Рисуешь на активной, в это время видимой установлена другая. Когда нужное время прошло - меняешь видимую страницу, у тебя мгновенно отображается рисунок.

Но...

1) чтобы было больше одной страницы, надо чем-то пожертвовать. В твоем случае - придется жертвовать разрешением. Например, вместо VgaHi (640*480) использовать VgaMed (640*350), там есть 2 страницы.
2) я не знаю, как будет вести себя мышь в случае использования нескольких видеостраниц.

ТОХА
а с помощью комманд getimage и putimage можно сделать так?:
1 нарисовать появившийся круг
2 сохранить весь экран
3 очистить
4 нарисовать сохраненный фрагмент
и если можно то насколько быстро это будет происходить чтоб не успеть воспринять 1 пункт, а то смысл игры становится не таким интересным
volvo
А ты знаешь, мне тут еще один финт в голову пришел. Попробуй, будет оно работать или нет, мне сейчас негде, Турбо Паскаля под рукой нет, а в FPC это не отработает.

{ Отрисовал картинку, теперь надо "погасить" на секунду }

{ Гасим. Для этого просто все цвета сделаем "черными" }
for i := 1 to 15 do
begin
setpalette (i, black); { Нулевой цвет я бы не трогал. }
end;

readln; { Ждем какое-то время, можешь заменить на Delay }

{ "Проявляем" картинку }
for i := 1 to 15 do
begin
setpalette (i, i);
end;
{ ... и рисуем новую окружность сразу после "проявки"... }
Как тебе такой вариант?

P.S. Еще более наглый вариант - попробовать рисовать вслепую, пока цвета палитры сброшены в черный. То есть, устанавливаешь цвет через SetColor, и рисуешь. В принципе, не вижу причин, чтоб потом, при восстановлении палитры это не "проявилось".
ТОХА
работает, правда белый цвет поменялся на голубой, проверял на самом первом с кругами без меню, но все равно спасибо)))

Добавлено через 4 мин.
на основную программу не очень повлияло, там красный используется, курсор голубой только

Добавлено через 19 мин.
для окончательного завершения осталось только подправить функцию mousein, у меня 1 из 10 запусков она хоть как-то работает на шариках и то под восьмой сбивается
остальные случаи при нахождении курсора внутри она возвращает false, да и способ игры не очень получается, приходится ставить readkey, наводишь мышь и жать энтер, иначе она так быстро рисует и проверяет координаты что я даже навести не успеваю))

Добавлено через 5 мин.
Function MouseIn(KoordX,KoordY,x1,y1,r:word):boolean;
var
rdx,rcx:word;
begin
asm
mov ax,$03
int $33
mov rdx,dx
mov rcx,cx
end;
MouseIn := (sqr((KoordX-x1)/r) + sqr((KoordY-y1)/r))<=1
end;
{из основной}
if ButtonPressed=1 then begin
GetMouseXY(KoordX,KoordY);
if MouseIn(KoordX,KoordY,x1,y1,r) then next_circle:=true else next_circle:=false;
end;

volvo
Ты б прикрепил весь файл полностью (можно в приват), как только доберусь до TP - посмотрю, что там творится... А то так "глухие телефоны" получаются...
ТОХА
ок в приват скину, а то при защите найдут проект мой тута и скажут скачал
volvo
Что-то я не понял, чего ты творишь... Вот тут:
Цитата
   { из основной }
if ButtonPressed = 1 then
begin
GetMouseXY(KoordX,KoordY);
if MouseIn(KoordX,KoordY,x1,y1,r) then next_circle:=true else next_circle:=false;
end;

все логично: если нажата мышь, то взять её координаты. Это понятно. А потом проверить, эти координаты находятся ли внутри окружности радиуса R с центром в (X1, Y1)... Это тоже понятно. Но вот зачем ты внутри MouseIn опять получаешь координаты нажатия - это уже непонятно. Я бы сделал так:

{ Заметь, я сделал параметры типа LongInt сразу, чтоб предотвратить переполнение }
Function MouseIn (KoordX, KoordY, x1, y1, r : LongInt) : boolean;
begin
MouseIn := sqr(KoordX - X1) + sqr(KoordY - Y1) <= sqr®;
end;

Опять же, чисто теоретически, проверить будет где в лучшем случае послезавтра...
ТОХА
модуль мыши просто из FAQ брал,
как я и предпологал он рисует все круги сразу, как будто buttonpressed=1 это отсутсвие нажатия клавиши

Добавлено через 4 мин.
при изменении buttonpressed=1 -> buttonpressed=5 результат тот же, как будто условия вовсе нет
ТОХА
ошибка в buttonpress это 100%, изменил условие начала вместо левой кнопки на ентер с учетом координат мыши, работает
volvo
Так... Нашел DosBox с шестым Турбо-Паскалем... Вот это:

Function MouseIn (x1, y1, r : LongInt) : boolean;
var
C_X, C_Y: word;
begin
Asm
mov ax, $03
int $33
mov C_X, CX
mov C_Y, DX
end;
MouseIn := sqr(C_X - X1) + sqr(C_Y - Y1) <= sqr®;
end;

{ и в основном коде: }

repeat { который после mouse_on }

{ ... }
repeat until ButtonPressed = 1; { вместо if ButtonPressed=1 then }
{ Просто ждем, пока будет нажата левая кнопка мыши,
а потом - проверяем, где именно она была нажата }

next_circle := MouseIn(x1, y1, r);

until next_circle = false;
работает достаточно стабильно. Но все равно где-то сбоит, попробуй пройтись отладчиком, посмотреть, какие значения функция MouseIn получает через параметры, и какие координаты мыши выдает Asm-часть кода.
ТОХА
Эврика smile.gif
все работает, буду до конца вечера тестить на баги)
без вас я бы не справился, это точно))
andriano
Цитата
Предлагаю придумать не потенциально-бесконечный алгоритм.

Действительно, стоит изменить лишь одну константу:
r := Random(k) + 20;
чтобы потенциально бесконечный алгоритм превратился в реально бесконечный.
Действительно, хороший алгоритм должен:
1. Давать правильный результат при корректных данных.
2. Давать предсказуемый результат (в частности, отсутствие деструктивных действий таких как завершение программы по ошибке, зацикливание, порча памяти...) при некорректных данных.
Очевидно, если алгоритм приводит к зацикливанию программы при изменении внешних констант (т.е. таких, которые не являются имманентной частью алгоритма), то это плохой алгоритм.
Желательно также, чтобы он сообщал пользователю о конкретной ошибке.
Предлагаю что-то вроде.
      IntIt := 0;
repeat
r := Random(k) + 20;
X1 := Random(GetMaxX - r*2) + r;
Y1 := Random(GetMaxY - r*2) + r;

ok := true;
for i := 1 to curr do
ok := ok and (sqr(C[i].X - X1) + sqr(C[i].Y - Y1) >
sqr(R + C[i].R));
inc(IntIt);
until ok or (IntIt > MaxIt);
inc(curr);
if IntIt > MaxIt then
writeln('Ошибка: невозможно разместить ',curr,'-ю окружность');



Да, прошу еще обратить внимание на порядок, в котором определяются характеристики окружностей, и как именно это сделано (3-5 строки листинга).
volvo
Цитата
Действительно, стоит изменить лишь одну константу:
А ты не меняй, и алгоритм бесконечным не будет. Если я этого не сделал - по какому праву это делаешь ты? Языком потрепать захотелось? Ты пришел по неверному адресу: я больше не буду молчать в ответ на всякие бредни. Ответ будет жестким. Не дойдет с первого раза - во второй раз будет еще жестче.

Цитата
Очевидно, если алгоритм приводит к зацикливанию программы при изменении внешних констант (т.е. таких, которые не являются имманентной частью алгоритма), то это плохой алгоритм.
В таком случае, хороших алгоритмов не существует. В любом случае можно так поменять внешнюю константу, что ЛЮБОЙ алгоритм (вернее, его реализация) перестанет работать.

Еще раз: без изменения констант ни одного зацикливания на миллиарды тестов не наблюдается. Разглагольствования типа "где-то там, у сферического пользователя в вакууме, это может быть не сработает, и программа зависнет" меня не интересуют. Я - практик. Программа зависает? Нет. Еще вопросы будут?
ТОХА
защитил проект сегодня удачно smile.gif
всем спасибо за помощь
кому интересно что получилось прикладываю проект, делимся на скока шариков у кого хватило зрительной памяти)
Lapp
Цитата(ТОХА @ 2.04.2011 17:31) *
кому интересно что получилось прикладываю проект, делимся на скока шариков у кого хватило зрительной памяти)
Мне было интересно, но - увы! у меня уже везде W7 или Vista. Даже и ТР есть, но полноэкранная графика для меня уже недоступна.

Все же это странно - обучать студентов на таком старье, как TP.
ТОХА
я не студент smile.gif
учусь в 10 классе)
hydroxychloroquine sulfate 200 m
Cialis Super Actif Plus
is gabapentin a controlled subst
Compro Viagra Poco Prezzo Mexico
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.