![](http://habrastorage.org/files/d6d/909/a7e/d6d909a7e98e4fac8b56beba427dfac9.gif)
![](http://habrastorage.org/files/92a/e10/924/92ae10924f474805aabffaa41032195b.gif)
Собственно, задача — сделать все клетки поля «выключенными». Под катом кое-что интереснее, чем просто решение.
Сам алгоритм решения довольно нудный и объяснять его здесь долго. Вкратце — для поля каждого размера существует бинарная матрица A всех возможных ходов. Если представить изначальное поле в виде бинарного вектора X, то решение поля b — это решение системы бинарных линейных уравнений Ab = X. Нетрудно догадаться, что можно обратить матрицу A, сохранить её в переменной и находить решение уже любого поля по формуле b = A-1X. Если кто-то хочет почитать подробнее, то здесь есть потрясающая статья, описывающая все нюансы. Мы двигаемся дальше.
К слову, решение существует не всегда для любой размерности. Размеры 5x5 или 17x17, например, решение имеют не всегда и в этой статье мы их не рассматриваем.
Генерация паттернов
Рассмотрим для примера следующее поле 20x20:
![](http://habrastorage.org/files/ef5/47a/4fd/ef547a4fd5604610968e34b9335b4dc0.png)
А теперь давайте посмотрим на его решение:
![](http://habrastorage.org/files/0ae/c76/130/0aec761303e0445ea222f2d53b189d33.png)
Красиво, правда? Давайте увеличим размер (и выключим границы, а то от них рябит в глазах). Возьмём, например, 75x75:
![](http://habrastorage.org/files/72b/408/14c/72b40814ce7a4b88b6a145523a117669.png)
И посмотрим на его решение:
![](http://habrastorage.org/files/f9b/12c/e1a/f9b12ce1ac8d490eb01dd5c3b5523d3a.png)
Довольно красиво. Но давайте не мелочиться, а сразу возьмём 150x150:
![](http://habrastorage.org/files/10f/c4c/247/10fc4c24723b42d88dce97924cc477a5.png)
И его решением будет… Ух ты.
![](http://habrastorage.org/files/bfd/e29/752/bfde297520ba4036bc4f7dc862f5db5c.png)
Завораживает. Издалека похоже на план города. Или на древнегреческую мозаику. Или на туркменский ковёр. Только почему-то зелёный.
А что будет, если попробовать получить решение для решения? Получим ещё один узор, производный. А потом можно сделать так ещё раз и получить ещё один производный узор.
![](http://habrastorage.org/files/da7/97d/49e/da797d49ebd941de9674a4cedce310f7.png)
![](http://habrastorage.org/files/cf2/4ee/840/cf24ee84024c4bfaa434a3d00f2c6251.png)
![](http://habrastorage.org/files/57f/064/495/57f0644958d44a8baff448824856b71e.png)
При этом рано или поздно узоры зацикливаются. Для разных размеров разные периоды, при этом для чётных полей период больше, чем для нечётных (6x6 и 7x7, на больших размерах период уже в несколько сотен минимум):
![](http://habrastorage.org/files/37c/8b9/74b/37c8b974b5104b02bf524585025a420c.gif)
![](http://habrastorage.org/files/b24/94a/fe7/b2494afe720c438096e11f03ea7637a5.gif)
При этом любой производный узор сохраняет любую осевую отражательную симметрию (анимации не зациклены, в зацикленной версии должно быть 2045 кадров):
![](http://habrastorage.org/files/1e2/898/82e/1e289882e9b5415ab826e1519b4249d3.gif)
![](http://habrastorage.org/files/113/1a7/b14/1131a7b14e6c4bbaae13786a7e7065fd.gif)
![](http://habrastorage.org/files/8d3/057/144/8d305714407449c89c2997f3a19125d5.gif)
Помимо отражательной, производный паттерн также способен сохранять и вращательную симметрию:
![](http://habrastorage.org/files/1f8/2c7/298/1f82c72987a641049e76598b52c5caa7.gif)
Хэши
Помимо паттернов, Lights Out можно использовать как медленную, криптографически нестойкую (из-за детерминистичности), но экзотическую хэш-функцию.
Как именно её считать? Ну, например, если считать всё поле начальным значением, то можно использовать в качестве хэша первые два столбца второго производного поля. Главную задачу хэш-функции они сохраняют — при небольшом изменении в начальных данных хэш меняется заметно. Вот, посмотрите сами:
![](http://habrastorage.org/files/bf9/c85/35a/bf9c8535a05948a4b910ee68f20c5460.gif)
![](http://habrastorage.org/files/5d0/bf3/f75/5d0bf3f75cca47ffaae8fe7590f67130.gif)
И только хэш:
![](http://habrastorage.org/files/47b/f24/4f8/47bf244f895947c89176b285e5dd4be5.gif)
![](http://habrastorage.org/files/0e0/2e5/bb5/0e02e5bb58ea432f8c5a786e27c7c184.gif)
Без анимации, чтобы заметить различие:
![](http://habrastorage.org/files/89f/bfd/4ae/89fbfd4ae96b4c098f31a310990ca574.png)
![](http://habrastorage.org/files/776/406/145/776406145a0249cbb40f274b8cb4b70b.png)
Где это можно применять? Ну, наверное, нигде. Для контрольных сумм он слишком медленный. В криптографии тоже не применить, потому что очень легко подобрать начальные данные, дающие данный хэш. Зато необычно.
Скрытие данных
Последнее применение — это скрытие данных внутри поля. Можно нарисовать на поле что-нибудь, затем несколько раз вычислить производный узор и выложить куда-нибудь. А благодаря цикличности изначально зашифрованное поле рано или поздно покажет себя. Вот пример (осторожно, гифка в 252 кадра). Если что, данные на 9-м кадре:
![](http://habrastorage.org/files/b72/7c4/046/b727c40462ea4de1933653ecec142577.gif)
Приложение с исходниками на codeplex. К сожалению, пока есть версия только для Windows.
Комментарии (24)
Jeffry_Choser
10.04.2015 13:59Еще, было бы, любопытно взглянуть на алгоритм решения.
Sixshaman Автор
10.04.2015 14:40+3Да, собственно, ничего особенного. Поле предоставляется в виде 1-мерного бинарного вектора X длины n x n. Задача — получить те клетки поля, которые при ходе в них сделают его нулевым.
Далее, рассмотрим для примера поле 3x3. У нас есть изначальная конфигурация X и 9 возможных ходов.
Как можно записать ход в клетку (1, 1), например? Он выглядит так:
А как одномерный вектор он будет записан так:
[1]
[1]
[0]
[1]
[0]
[0]
[0]
[0]
[0]
Аналогично можно представить ходы во все остальные клетки. Обозначим их через a11...a33
Теперь о решении. Если, например, решением являются клетки (1, 2) и (3, 2), то математически решение запишется в виде:
a12 + a32 = X.
Более развёрнуто:
0*a11 + 1*a12 + 0*a13 + 0*a21 + 0*a22 + 0*a23 + 0*a31 + 1*a32 + 0*a33 = X.
Или в матричном виде:
[ a11 a12 a13 a21 a22 a23 a31 a32 a33]*b = X
Покороче:
Ab = X.
Наше искомое решение — это b. Решив эту систему бинарных линейных уравнений, мы получим вектор, состоящий из единиц и нулей. Если в эту клетку нужно сделать ход, то на её месте в векторе будет 1, если нет — то 0.
Для больших размерностей всё аналогично. Вот тут всё описывается на примере 5x5.
Ну и да, для некоторых размерностей у матрицы A ранг меньше, чем её размер, т.е. решение существует не всегда.Jeffry_Choser
10.04.2015 21:55А как решая матрицу, получить координаты решения?
Или это итерационный процесс и из шага итерации получим конкретную клетку?Sixshaman Автор
11.04.2015 00:09Ну, допустим, мы решили систему линейных уравнений и получили вектор b. Допустим, что у нас размер 3x3. Тогда
[ b11 ]
[ b12 ]
[ b13 ]
[ b21 ]
b = [ b22 ]
[ b23 ]
[ b31 ]
[ b32 ]
[ b33 ]
Ну вот, если bij = 1, то ход в клетку (i, j) содержится в решении. Если bij = 0, то нет.
Lerg
10.04.2015 14:18+1Красиво. Нужно сделать online реализацию на JavaScript.
Sixshaman Автор
10.04.2015 14:50Я думал об этом, кстати. Но руки так и не дошли. Зато непрерывную версию я писал уже на JS(всё равно без решалки, ни один человек из тех, что я спрашивал, не знает в принципе о возможности решения).
SHVV
10.04.2015 15:30+1Получился клёвый генератор ковров.
Только цвета добавить по кадрам и как-то смешивать их.Jeffry_Choser
10.04.2015 21:57Цвет должен зависеть от кол-ва инверсий клетки. Клетка 2 раза зажглась — цвет поменялся и т.д.
NeoNN
10.04.2015 16:37А если сделать модицикацию, которая зажигает различные фигуры, как в тетрисе, в случайном порядке, то математически решение уже навряд ли можно будет найти и головоломка становится гораздо интереснее.
bromzh
10.04.2015 18:12+2В емаксе есть эта игра, правда на ограниченном поле (M-x 5x5). И присутствует также возможность рассчитать решение:
СкринКружками отмечены поля, которые нужно активировать, чтобы выиграть
Mingun
10.04.2015 20:51Когда играл еще только в демку Myst IV, в камине был дощечка, на которой квадраты переключались таким образом. Уж не помню, сколько времени потратил, но таки смог «перекрасить ее».
Настоящее решение, если не играли, не читайтеИ так обидно было —на всякий случай :)такая изящная загадка была,ну все, это последний рубеж, пеняйте на себяа всего-то нужно было включить светильники…dobriykot
10.04.2015 21:56Странно, что никто не вспомнил про это: i.imgur.com/ffH82gF.jpg
Jeffry_Choser
10.04.2015 21:58Колобки! :)
dobriykot
10.04.2015 22:01Да, это Братья Пилоты. :)
www.ag.ru/games/pilot-brothers-po-sledam-polosatogo-slonaJeffry_Choser
10.04.2015 22:08У меня с детства комикс сохранился — приключения колобков, называется! :)
dtestyk
11.04.2015 10:57В криптографии тоже не применить, потому что очень легко подобрать начальные данные, дающие данный хэш
а если брать случайную матрицу А(случаи когда нет обратной можно использовать как одностороннюю функцию)
GarryC
Что то есть напоминающее Конвеевскую жизнь? НЕТ?
Sixshaman Автор
Да, есть такое. Только правила расчёта производного поля другие.
bask
И то и другое — клеточные автоматы
Jeffry_Choser
Или ожившие QR-коды :)