Ураган Мэтью и Молнии

27

Вызов

Вдохновленные этим испытанием и неприятным ураганом Мэтью , мы будем динамически генерировать молнии.

n = 15:

   \
   /\
  /  \
 /   /
/\  /\
 /  \ \
/   / /\
   /\ \
  / /  \
 /\ \  /\
  /  \ \
 /\  /  
   \
    \
    /\

вход

Положительное целое число nопределяет глубину молнии.

Правила и ограничения

  • /и \должен быть использован
  • Вероятность, определяющая направление молнии, следующая:
    • 25% расщепляется на 2 дорожки
    • 25% Путь доходит до тупика
    • 25% уходит влево
    • 25% идет правильно
    • Есть несколько исключений относительно перекрытия и тупика ниже:
  • Код не должен быть детерминированным, каждый раз должен генерироваться новый разряд молнии
  • Болты не должны пересекаться: например, если болт находится слева от текущего болта, текущий болт должен либо заканчиваться, либо идти направо, но не идти влево или делиться (вероятность все еще применима, в этом случае она становится 50% -ной / 50% справа)
  • Если не существует другого доступного пути разделения, путь не должен заканчиваться: например, в начале, когда существует только 1 путь, путь не должен заканчиваться, пока он не разделится, также применяется, когда существует несколько путей, но все, кроме одного пути, мертвы , (вероятность делится на 33% / 33% влево / 33% вправо) Ваша цель - достичь дна
  • Пробелы могут быть добавлены слева (все, что вам нужно, это только высота-1)
  • Тем не менее, вы хотите создать болт на ваше усмотрение, вы можете идти снизу вверх, слева направо и т. Д., Пока все вышеприведенные правила выполнены

Другой пример

n = 10

 \
 /
 \
 /\
  /\
 / /
/\ \
 / /\
 \   \
 /

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

Будьте в безопасности и получайте удовольствие от игры в гольф! Пожалуйста, играйте в гольф ответственно, только когда вы находитесь в безопасном месте!

Zukaberg
источник
7
Stay safe and have fun golfing!Возможно, также укажите, что если EAS ударит, откажитесь от всего и выполняйте приказы! Гольф-код не является вашим приоритетом в такой ситуации.
Эрик Outgolfer
17
@EriktheGolfer ты не настоящий гольфист тогда.
Blue
4
Я не верю, что «самый центральный путь должен быть тем, который достигает земли», согласуется с остальной частью описания случайного поколения. Например, случайным образом можно расколоть оригинальный болт дважды, а затем закончить два средних болта; как можно переопределить эту возможность, сохраняя указанные вероятности?
Грег Мартин
Кроме того, что произойдет, если (например) оба первых шага будут разделены? Тогда два средних болта соприкасаются друг с другом, что кажется проблематичным, но также не исключено особыми случаями.
Грег Мартин
@GregMartin Хорошая точка в центральной части, изначально я надеялся, что это создаст сбалансированный заряд, но теперь, когда я думаю об этом, даже без этого ограничения, примерно в 50% случаев он должен оказаться где-то посередине, на глубине из 15 будет иметь только 1-2% вероятности, где правый или левый большинство пути приземляется. Я удалю это правило. И для части разделения на 2 шага, единственное, что нужно предотвратить, это то, что никакие 2 пути не должны соединяться 2 путями: \/в любой точке.
Зукаберг

Ответы:

6

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/

Проверьте правильность новой строки

Тон Хоспел
источник
+1 аккуратно! Вы должны включить этот онлайн-тестер perl -M5.010 main.pl <<< 25 , я получил хорошие результаты!
Зукаберг
Не могли бы вы объяснить, как это работает? Я получаю слишком много удовольствия, создавая их, ха-ха, честно говоря, я не ожидал таких хороших результатов.
Зукаберг
К сожалению, вам нужно добавить 3 байта для-n , потому что пробел и тире тоже. Это же правило для аргументов командной строки. См. «Специальные вызовы», второй пункт: я считаю их как разницу в количестве символов для самого короткого эквивалентного вызова без них.
Эрик Outgolfer
1
@EriktheGolfer Нет, +1 в порядке, потому что эта программа отлично работает из командной строки, используя -nEтолько на 1 символ больше -E(см. Статью, на которую вы ссылались. Это также избавляет от необходимости -M5.010) Я всегда представляю свой код в виде файлов, потому что это это более удобно, но я всегда считаю параметры, например так: если это можно запустить из командной строки, я не считаю пробел и тире. Если он должен быть в файле (например , потому что он использует do$0) я сделать сосчитать пространство и тире
Ton Hospel
@TonHospel О, я не знал, что ты использовал -E. Если так, то ты хороший.
Эрик Outgolfer
0

JavaScript (ES6), 154 байта

f=(n,r=[],s=" ".repeat(n)+"/",t=s.replace(/ \/|\\ |\\$/g,_=>"  /  \\/\\".substr(Math.random()*8&6,2)))=>n?/^ +$|\\\//.test(t)?f(n,r,s):f(n-1,[...r,t],t):r
<input type="number" min=1 oninput=o.textContent=f(this.value).join`\n`><pre id=o>

Я боролся с реализацией, пока не увидел ответ @ TonHospel, после чего он просто превратился в порт. Образец вывода:

         /\
        / /\
       /\   \
        /\   \
         /\  /
          / /\
         / / /\
            / /\
            \   \
             \
Нил
источник