Однажды мой коллега для кругозора заинтересовался темой построения треугольника Серпинского с помощью «игры в хаос». И познакомил с ней меня. Показал видео. Потом он сказал: «Ты же учишься программировать – попробуй написать программу, в которой это будет реализовано».
Я не специалист в этой области, могу ошибаться в терминах или не очень правильно их интерпретировать и применять.
Про этот треугольник
Треугольник Серпинского - это вот такая штука:
По сути это фрактал. Берётся равносторонний треугольник (пусть он будет ). Середины его сторон соединяются отрезками. Получаются четыре треугольника. Из удаляется треугольник, находящийся посередине. Остаётся три угловых треугольника Также поступают и с каждым из них. Получаются девять треугольников Продолжают до бесконечности – получается треугольник Серпинского.
Игра в хаос
Способ его построения с помощью игры в хаос заключается в следующем (здесь рассказывается с математикой). Берётся равносторонний треугольник (пусть углы будут A, B и C). Внутри произвольным образом выбирается начальная точка. Бросается игральная кость. Будем говорить для определённости, что выпадение того или иного числа на кости соответствует следующим результатам:
"1" или "4" - это А;
"2" или "5" - это В;
"3" или "6" - это С.
Разумеется, это условно. Важно лишь, чтобы А, В и С имели одинаковую вероятность выпадения.
Допустим, в результате первого броска выпала А. Тогда вершина А мысленно соединяется с начальной точкой отрезком, а на середине этого отрезка ставится точка. Пусть теперь она будет начальной.
Следующий бросок игральной кости. Допустим выпала С. Значит теперь уже мысленным отрезком соединяем новую начальную точку и вершину С, и, опять же, отмечаем середину этого отрезка точкой и перетаскиваем туда нашу начальную точку. И так далее.
После достаточно большого количества повторений из точек получим изображение того самого треугольника Серпинского. В теории, по крайней мере.
Не особо важные спойлеры.
Выяснилось, что
треугольник не обязательно должен быть правильным;
начальная точка может находиться и вне треугольника.
Ты же учишься программировать...
Я не работаю в сфере IT. Учусь программировать на C++ по учебникам. Но скорее просто для того, чтобы заставлять свою голову работать. Полагаю, сейчас, чтобы податься в IT нужно учиться владеть каким-то более высокоуровневым инструментом или чему-то более прикладному. Зерокодингу, например. Так что для меня это что-то вроде хобби или аналога разгадывания сканвордов.
Мой коллега знает об этом и не видит ничего плохого в том, чтобы подкинуть мне практику. На тот момент всё, что я умел, это выводить что-то в консоли. Я взял задачку себе на заметку. Со временем я пришёл к тому, как реализовать это в виде приложения для Windows. В итоге я написал эту программу с использованием WinAPI. В этом мне помогла книга Юрия Щупак «Win32 API. Эффективная разработка приложений», 2007. Это было довольно занятно.
Интерфейс приложения
Есть несколько рабочих версий программы. Последняя выглядит так:
На зелёную рамку не обращайте внимания. Я уже не помню точно, но, скорее всего, так я отрабатывал использование геометрических примитивов и разные цвета.
Ну так вот, всё просто. Пожалуй, прежде пройдусь по control’ам интерфейса.
Как видите, тут есть меню. Правда, не очень функциональное. «Выход» реально это и делает. А вот всё остальное просто выводит информационное диалоговое окно, у которого надо нажать «ОК» или закрыть:
А вот пункту «Параметры» в конструкторе меню его свойству «Всплывающее окно» присвоен «false», поэтому он не является раскрывающимся подменю следующего уровня:
Почему-то мне кажется, будто от горячих клавиш там лишь одно название. Пожалуй, не буду возвращаться и проверять это. Но знайте, что тему эту я прошёл и при желании могу реализовать. По крайней мере, знаю, где про это написано.
Так я осваивал создание меню.
Поле с контролами слева – это Modeless Dialog Box, или же диалоговое окно, которое не забирает себе монопольно фокус приложения, а вполне себе сосуществует с ним.
Кнопка "Do it!" выполняет установленное количество итераций с бросками игральной кости и рисованием точек внутри треугольника. Но делает она это только, если на рабочем поле имеются четыре точки – три вершины и начальная точка. А иначе:
Итерация – это:
генерация рандомного числа от 1 до 6;
на основании этого расчёт положения следующей точки;
её рисование.
Если для кого-то это важно, то перед rand() идёт srand(time(NULL)).
"Refresh" это "Clear".
Следующий элемент интерфейса – Edit Control для ввода количества выполняемых за одно нажатие «Do it!» итераций:
При запуске программы эта величина по умолчанию равна единице.
Почему не больше 100000? В общем-то, ничего страшного не произойдёт. Просто никакой речи о многопоточности на тот момент не было. Плюс, в какой-то момент я использовал вектор в качестве хранилища информации обо всех точках. Поэтому при генерации большого количества точек поток замыкается в себе до тех пор, пока все точки не нарисуются.
Уже много позже я научился обходиться без кнопки для ввода нового значения. Реализовал я это уже в другой тренировочной программе.
Combo Box позволяет выбрать радиус точки, рисуемой «Do it!». Под точкой подразумевается круг небольшого радиуса.
Про ввод количества углов позже.
Внизу есть Status Bar, где видна дежурная информация:
сколько итераций при нажатии «Do it!» происходит;
текущий радиус точки;
количество уже нарисованных точек;
какой n-угольник будет вначале (опять же, про это позже).
Работа приложения
Вначале я ввожу количество точек, рисуемых одним нажатием «Do it!», ну скажем, 10000. Затем делается три клика на рабочем поле, появляются вершины треугольника, которые автоматически последовательно соединяются линиями. Ещё один клик – создаёт начальную точку. Дальше нажимаем «Do it!». И Вуа ля!
Если ещё несколько раз понажимать, то линии станут чётче:
Когда я впервые в рабочем виде реализовал эту программу, я, честно говоря, был в шоке. Шеогоратова математика!
Вот ещё несколько реализаций:
Как я ранее писал, действительно, треугольник может быть каким-угодно. А ещё, если поставить начальную точку вне треугольника, то это ни на что не повлияет. Оно и логично! Потому что рано или поздно точка попадёт внутрь треугольника, а там уже по накатанной.
Итак, задача решена!
Про количество углов фигуры
Мне стало интересно, что же будет с n-угольником, где n > 3. Я добавил кое-какие изменения в код программы и реализовал задачу. В начальных версиях этого функционала не было.
Собственно, вводим в соответствующий Edit Control количество углов и смотрим. Как мне показалось, разные угольники ведут себя по-разному.
Для очень неправильного четырёхугольника выходит что-то такое:
Чем «параллельнее» несмежные стороны, тем однороднее получается распределение точек:
В центре можно разглядеть степень «ошибки параллельности».
И ещё кое-что. Если две вершины поставить достаточно близко друг к другу, получается эффект треугольника, но в той стороне, где находятся эти две близкие друг к другу вершины, плотность точек больше. Довольно логично.
С пентагоном и гексагоном тоже, вроде как, можно выделить какие-то закономерности:
А эффект треугольника на них тоже распространяется:
Наращивая дальше количество углов ничего особо интересного я уже не нашёл. Думал, может с октагоном будет что-то интересное, но нет.
Надеюсь, кому-то было интересно. Всем добра!
Комментарии (7)
felixd7u
00.00.0000 00:00+1Попробуйте подобным образом поиследовать и нарисовать логистическое отображение, это гораздо интереснее чем треугольник Серпинского
https://ru.wikipedia.org/wiki/Логистическое_отображение
Alexandroppolus
00.00.0000 00:00+2Да, впечатляет... Даже не поленился запилить, чтобы посмотреть :)
Важно лишь, чтобы А, В и С имели одинаковую вероятность выпадения.
Не обязательно. Просто будет некоторый "перекос" в очередности.
GBR-613
00.00.0000 00:00Вместо того, чтобы писать в тексте диалога про ограничение 100000, можно было бы просто ограничить длину текстового поля 5 позициями. (И чтобы больше 5-и не было видно, и чтобы нельзя было бы ввести. )
d1agnoz
00.00.0000 00:00+1Хмм, в случае с четырьмя точками при определённых конфигурациях результат похож на проекцию трехмерного треугольника Серпинского (пирамида Серпинского или тетраэдр, в общем случае).
Гипотеза: что если с увеличением количества точек n, получается проекция (n-1)-мерной фигуры Серпинского? Это простое наблюдение, я глубоко в математике этого не разбирался, но мне показалось может кому-то будет интересно это дальше поизучать в таком ключе
knstqq
> Наращивая дальше количество углов ничего особо интересного я уже не нашёл. Думал, может с октагоном будет что-то интересное, но нет.
Возможно нужно простое количество вершин. 3, 5 — да, 4 и 8 — нет. Попробуйте 7 или 11?
к тому же 8 имеет параллельные стороны
vesper-bot
Скорее просто нечетное, тот же пятиугольник слегка похож на "пятиугольник Серпинского". Вот только похоже, что математика строго соответствует треугольнику, и увеличение углов её ломает.
Deosis
Можно слегка изменить правила при большем количестве вершин.
Например, для 4-угольника запретить выбирать одну у ту же вершину дважды подряд.
Либо ставить точку не в середину отрезка.
Видео