Perl, 92 90 89 84 байта
Включает +1 для -n
Дайте рост на STDIN:
perl -M5.010 bolt.pl <<< 15
bolt.pl
:
#!/usr/bin/perl -n
map{$_=$;until$;=$_,s/.6|3.?/53|16*rand/eg,/3|6/>/36/;say y|3615|\\/ |r}(1x$_.6)x$_
объяснение
Если вы называете смещение начальной точки 0 (точка находится в углу поля символа), то в следующей строке вы можете перейти влево или вправо (или нет) и в конечном итоге получить точки со смещением -1,1
. В следующей строке -2,0,2
указываются возможные смещения и т. Д. Все они отличаются на 2. Если затем вы называете символ слева внизу от точки четным, а символ справа внизу нечетным, вы можете расширить его, назначив четное или нечетное каждой позиции символа. в ряду, который чередует четное и нечетное (фактически вся плоскость выложена плиткой в шахматном порядке). Четная позиция может иметь /
или
, нечетная позиция может иметь \
или
.
Символ непосредственно перед a /
находится в нечетной позиции, так что это может быть либо, \
либо
, но \/
запрещено, поэтому
возможно только . Точно так же символ после a \
должен быть a
(при условии, что строка дополняется достаточным количеством пробелов слева и справа, поэтому границы строк не имеют значения). Таким образом, молния продолжается в следующем ряду всегда непосредственно ниже \
или ниже a /
. В любом случае нижняя точка находится в середине , и следующая строка может иметь один из
, /
, \
или /\
непосредственно под верхние 2 символов. Таким образом, чтобы создать следующую строку, я могу просто заменить любой \
или/
любым из этих 4 расширений с равной вероятностью (вы также можете независимо заменить первый символ на
или, /
а второй символ на
или \
). В Perl вы можете сделать это с чем-то вроде:
s#\\ | /#(" "," \\","/ ","/\\")[rand 4]#eg
Если результирующая строка, однако, содержит \/
(запрещенное соединение) или отсутствует /
или \
вовсе (болт умирает и не достигает дна), результат недействителен. В этом случае я выбрасываю весь ряд и просто пытаюсь снова. Действительное продолжение всегда существует, и если вы попытаетесь достаточно часто, оно будет найдено (например, все умирает, кроме 1 потока). Это распределение немного отличается от предложенного алгоритма предотвращения перекрытия, но я думаю, что это на самом деле лучше, так как он не имеет направленного смещения. Валидность можно проверить по-гольфистски, используя
m#\\|/#>m#\\/#
Проблема здесь в том, что случайная замена слишком длинная, и все эти \
побеги также съедают байты. Так что я решил построить мои строки с помощью строки цифр и заменить соответствующие цифры от
, /
и как \
раз перед печатью. Основная случайная замена
53|16*rand
который дает один из 53
, 55
, 61
или 63
с равной вероятностью. Я тогда интерпретирую 5
и 1
как
, 3
как \
и 6
как /
. Это объясняет строку печати:
say y|3615|\\/ |r
В серьезных соревнованиях по гольфу я бы начал систематически изучать альтернативные формулы магии, но это должно быть довольно хорошо (в пределах 3 байтов от оптимального)
Остальные компоненты программы:
1x$_.6
Это инициализирует $_
(см. Следующую карту) пространство высоты, за которым следует символ /
. Это невидимая строка над первой печатаемой и гарантирует, что поле достаточно широкое, так что болт никогда не может выйти из пространства слева
map{ ... ; say ...}(1x$_.6)x$_
Я буду обрабатывать те же начальные значения высоты строки, каждый раз печатая новую строку
$_=$;until$;=$_,...
Сохранить текущую строку в $;
. Если замена оказывается недействительной, восстановить $_
из$;
s/.6|3.?/53|16*rand/eg
Делать фактическую замену. Мне не нужно проверять, что до /
или после, \
так как это должен быть пробел. Это удобно, поскольку пространство может быть представлено либо либо, 1
либо 5
. Поскольку я добавляю строку только слева, пробел после \
буквы все еще может отсутствовать, так что сделайте этот символ необязательным
/3|6/>/36/
Проверьте правильность новой строки
Stay safe and have fun golfing!
Возможно, также укажите, что если EAS ударит, откажитесь от всего и выполняйте приказы! Гольф-код не является вашим приоритетом в такой ситуации.