Создаём сложный лабиринт в фоне веб-страницы

в 11:17, , рубрики: css, php, принцип цикады, метки: , ,

Создаём сложный лабиринт в фоне веб страницы
Находясь под приятным впечатлением от кратенькой, но весьма остроумной и, не побоюсь этого слова, «культовой» программы, задался вопросом: «А можно ли сгенерировать подобную структуру в фоновом изображении сайта?». Захотелось создать бесконечный лабиринт, не повторяющийся в любом направлении. Вспомнил, где-то уже встречал метод, который и поможет мне любому стать Дедалом веб-дизайна.

html {background: url('fon.gif') repeat;}

Создаём сложный лабиринт в фоне веб страницы
Первое, что приходит на ум: нарисовать кусок лабиринта и просто размножить его. Лабиринт выйдет «ненастоящий» – повторение рисунка при «паркетной укладке» моментально бросится в глаза.

Усложним подход. Можно создать два фоновых изображения разного размера. В каждом из них в шахматном порядке будем чередовать прозрачные области и стенки лабиринта. И затем одно подложим под другое. Разноразмерность и случайная генерация стенок позволит создавать раличные комбинации ходов при наложении:

html {
	background-image: url('fon1.gif');
	background-repeat: repeat;
}
		
body {
	background-image: url('fon2.gif');
	background-repeat: repeat;
}	

Создаём сложный лабиринт в фоне веб страницы
Уже теплее, но если неудачно выбрать размеры, то это не даст принципиального выигрыша по сравнению с background-repeat одного изображения. Пусть и не сразу, но структура лабиринта снова начнёт повторяться.

Кто ещё помнит математику за 7-й класс, сразу сообразит, что коэффициент «неповторения» будет равен частному от деления наименьшего общего кратного (НОК) на наибольший общий делитель (НОД) от длин сторон изображений. То есть, если одно изображение 3х3 элемента, а второе 6х6 то уже через 2 итерации лабиринт «начинается сначала».

Из этого следует печальный вывод, что бесконечно неповторяющегося узора достичь нельзя. Во всяком случае методами CSS. Можно рисовать Ява-скриптом, но… Вы понимаете…

Если уж бесконечный лабиринт воздвигнуть не судьба, то хотя бы сделаем фон как можно дольше неповторяющимся. Для этого нужно чтобы стороны обоих изображений представляли собой взаимно простые числа. В этом случае НОК равно произведению сторон, НОД — единице. А количество итераций «неповторения» в этом случае уже будет равно НОК, что весьма немало даже при небольших значениях. Если, например, взять 3х3 и 4х4, то только через 12 наложений мы обнаружим в затейливом узоре знакомые очертания. А если взять 13х23 и 17х19, то уникальность замысловатых маршрутов обеспечена для страницы любого размера.

Ободрившись подобными арифметическими выкладками, может показаться, что пора праздновать победу. Но коварная математика ставит ещё одну подножку.

Создаём сложный лабиринт в фоне веб страницы
Шахматные поля удобно накладывать друг на друга в случае чётности сторон. Поскольку мы хотим чтобы соотношение сторон у двух картинок были взаимно простым, то как минимум одна из них должна быть «нечётной». Эта нечётность и преподносит неприятный сюрприз в виде нерегулярного наложения не «теми» квадратиками. Уже при втором прогоне пустые квадратики ложатся на пустые, зарисованные — на зарисованные.

Смещение «нечётной» картинки на один ряд вправо/вниз ничего не решает. Покрутив-повертев варианты с различными комбинациями сторон я не придумал ничего лучшего, как делать нижнюю картинку без прозрачных ячеек. В этом случае 100% гарантия, что в фоне не будет зияющих пустот. Но php-скрипт частично работает вхолостую, отрисовывая стенки, которые всё равно будут не видны. Если есть идеи, как обойтись без «ненужной работы» — предлагайте. Помните, соотношение сторон разных изображений должно быть взаимно простым.

Собственно, всё. Демку смотрите здесь. Если дадут вожделенный инвайт на случай хабраэффекта я отключил генерацию каждый раз заново при загрузке страницы нового лабиринта. Но для интересующихся прилагаю полный листинг кода с php-скриптом, генерирующий фоновые пинги для логова Минотавра.

index.php

<?php include_once "generate_fon.php"; ?>
<html>
	<title>10 PRINT CHR$(205.5+RND(1));: GOTO 10</title>
	<style type='text/css'>
		html, body {
			padding: 0px; margin: 0px;
			width: 100%; height: 100%;
		}
		
		html {
			background-image: url('fon1.png');
			background-repeat: repeat;
		}
		
		body {
			background-image: url('fon2.png');
			background-repeat: repeat;
		}	

		#outer {
			height: 300px;
			line-height: 300px;
			text-align: center;			
		}
		
		#inner {
			outline: solid #99c medium;
			padding: 50px;			
			background: #336;
			color: #99c;
			font-weight: bold;
			font-size: 16pt;
		}
	</style>
<body>
<div id='outer'><span id='inner'>10 PRINT CHR$(205.5+RND(1));: GOTO 10</span></div>
</body>
</html>

generate_fon.php

<?php 
	function create_background_image ($w, $h, $quadro, $is_chess, $numder) {
		//w, h - кратность ширины/высоты фонового изображения
		//$quadro - длина стороны одного квадратного элемента "стены лабиринта", px
		//$is_chess - true/false, в шахматном ли порядке заполнять фон
		//$numder - номер фонового файла для его названия (их нужно 2)
		
		$img = imageCreate($w*$quadro, $h*$quadro);//Заготовка изображения, размеры
		$color_transparent = imagecolorallocate ($img, 0, 0, 0);//Чёрный цвет будет выполнять роль прозрачного
		$color_background =  imagecolorallocate ($img, 51, 51, 102);//Цвет фона		
		$color_line =  imagecolorallocate ($img, 153, 153, 204);//Цвет линий
		imagesetthickness($img, 4);//Толщина "стенок"
		
		//Рисуем "стенки лабиринта"
		for ($i = 0; $i < $w; $i++) {
			for ($j = 0; $j < $h; $j++) {				
				$sparseness = mt_rand(0, 8);//"Разреженность" лабиринта. 1 шанс из 9-ти что не станем рисовать "стенку"
				if ($sparseness) {
					//Не забываем про "шахматный порядок"
					if (!($is_chess && ($i % 2 ==  $j % 2))) {
						//Заливаем очередной квадратик фоновым цветом
						imagefilledrectangle (
							$img, 
							$i * $quadro, $j * $quadro, //Верхний левый угол
							($i + 1) * $quadro, ($j + 1) * $quadro, //Нижний правый угол
							$color_background //Цвет фона
						);					
						//"Кидаем монетку", чтобы решить направление "стенки"
						$direction = mt_rand(0, 1);
						//Рисуем линию (случайно выбираем:  или /)
						if ($direction) {
							imageline (
								$img, 
								$i * $quadro, $j * $quadro, //Из левого верхнего угла...
								($i + 1) * $quadro, ($j + 1) * $quadro, //... в правый нижний угол
								$color_line //Цвет линий
							);				
						} else {
							imageline (
								$img, 
								($i + 1) * $quadro, $j * $quadro, //Из правого верхнего угла...
								$i * $quadro, ($j + 1) * $quadro, //... в левый нижний угол
								$color_line //Цвет линий
							);						
						}
					} else {
						//Этот квадратик должен быть прозрачным					
						imagefilledrectangle (
							$img, 
							$i * $quadro, $j * $quadro, //Верхний левый угол
							($i + 1) * $quadro, ($j + 1) * $quadro, //Нижний правый угол
							$color_transparent //Цвет фона - прозрачный
						);				
					}
				} else {
					//А вот и "разреженность" лабиринта проявилась
					//"Стенку" не рисуем, но фон заливаем
					imagefilledrectangle (
						$img, 
						$i * $quadro, $j * $quadro, //Верхний левый угол
						($i + 1) * $quadro, ($j + 1) * $quadro, //Нижний правый угол
						$color_background //Цвет фона
					);					
				}
			}
		}
		imagecolortransparent ($img, $color_transparent);//Прозрачный цвет фона
		imagepng ($img, "fon$numder.png");//Сохраняем фон в файл
		imageDestroy($img);//Для очистки памяти "уничтожаем" переменную-картинку		
	}
	
	$w1 = 17; $h1 = 19;//Кратность сторон первого изображения
	$w2 = 23; $h2 = 13;//Кратность сторон второго изображения
	$wall = 30; //Длина стороны одного квадратного элемента "стены лабиринта", px

	$img1 = create_background_image($w1, $h1, $wall, false, 1);//Создаём нижнее фоновое изображение
	$img2 = create_background_image($w2, $h2, $wall, true, 2);//Создаём верхнее фоновое изображение 
?>

В скрипте я «проредил» генерацию стенок. В оригинальном алгоритме получается слишком много «слепых ходов», в которые невозможно попасть. Пробовал также развернуть на 45 градусов к зрителю, но вертикальные и горизонтальные линии стандартными средствами php рисуются как-то неказисто. В общем, для желающих внести в лабиринтостроительство инновации и улучшения – работы непочатый край.

Автор: valemak

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js