Сантехника случайных путей


23

Напишите программу или функцию, которая принимает три целых числа: ширину w, высоту hи количество шагов s. Вы будете рисовать не-самопересекающиеся случайные блуждание s шагов долго на 5*wпо 5*hпиксельным изображениям , где каждая 5 на 5 пиксели клетки является либо пустым (чистой бежевой) или один из этих двенадцати простых «трубы»:

увеличенные трубы

Изображение выше увеличено, чтобы показать детали. Вот трубы в реальном размере:

трубы

(Серые линии просто для разделения типов труб.)

Случайный обход будет представлять собой один непрерывный путь по трубе, который начинается в одной конечной точке трубы (один из четырех нижних типов труб) и заканчивается в другой конечной точке трубы.

Начните с пустой wпо hсетке и случайным образом выберите одну ячейку в качестве отправной точки. Затем случайным образом выберите одно из четырех направлений для начала и нарисуйте соответствующую конечную точку трубы. Эта начальная ячейка отмечает первый шаг в вашей прогулке, и каждый раз, когда вы рисуете новую ячейку или перезаписываете существующую, она считается еще одним предпринятым шагом.

Теперь, многократно, произвольно выбирайте движение вправо, влево или по прямой, рисуя соответствующую ячейку трубы, если выбранное направление действительно. Вернитесь назад и повторно выберите, если направление недействительно, пока не будет сформирован полный sпуть шага. Путь должен заканчиваться конечной точкой трубы, которая может находиться в любом месте сетки, в зависимости от пути, по которому проходил путь.

Очень важно отметить, что только две ячейки прямой трубы могут быть перезаписаны, и только ячейкой прямой трубы противоположной ориентации, в результате получается ячейка пересечения. В противном случае все трубы должны быть размещены в пустых ячейках.

Когда нарисовано пересечение, часть пути, которая находится дальше от начальной ячейки, должна быть нарисована сверху.

Это зависит от вас, имеет ли сетка периодические граничные условия (PBC), т. Е. Выйдет ли труба, выходящая из одной стороны сетки, с другой стороны. Без PBC граница сетки считается барьером, с которым вы можете столкнуться, как и другие трубы.

Особые случаи

  • Когда sравен 0, трубы не должны быть нарисованы, и результат должен быть пустым 5*wпо 5*hизображению (т.е. все бежевое).
  • Когда s1 1 заглушка

    увеличенная заглушка трубы(Фактический размер: заглушка)

    должен быть нарисован в случайно выбранной начальной ячейке.

Другие детали

  • Вы можете предположить, что sэто самое большее, w*hпоэтому путь всегда будет возможен. (Хотя более длинные пути возможны из-за пересечений.)
  • wи hвсегда будет позитивным.
  • Все случайные выборы должны быть равномерно случайными. Например, вы не должны избегать пересечений, когда это возможно, даже если это облегчает проблему. Допускаются генераторы псевдослучайных чисел.
  • Любые три визуально отличных цвета могут использоваться вместо черного, синего и бежевого.
  • Ваши выходные изображения могут быть увеличены таким образом , что они на самом деле 5*w*kот 5*h*kточек , где kявляется положительным целым числом. (Рекомендуется увеличивать любые примеры, которые вы публикуете, даже если ваш k1.)
  • Можно использовать любой общий формат файла изображения без потерь, и изображение может быть сохранено в файл, отображено или выброшено в исходном виде на стандартный вывод.

Самый короткий код в байтах побеждает.

Примеры

(Все увеличено на 500%.)

Если вход - w=2, h=1, s=0то выход всегда будет:

Если на входе w=2, h=1, s=1выводится одно из этих изображений с равной вероятностью:

Если на входе, w=2, h=1, s=2то выход будет

или возможно

если предполагается, что сетка имеет PBC.

(Обратите внимание, что запуск пути как будто сделает второй шаг невозможным.)


Вот некоторые возможные результаты для w=3, h=2, s=6предположения PBC:


Вот возможный вывод для w=3, h=3, s=9предположения PBC:

Обратите внимание, что путь не должен покрывать все ячейки из-за пересечения, считающегося как два шага. Кроме того, мы можем сделать вывод, что угловая конечная точка была начальной ячейкой, поскольку путепровод пересечения должен был быть нарисован впоследствии. Таким образом, мы можем вывести последовательность случайных выборов, которые были сделаны:

start at top left, facing east
go straight
go right
go right
go right
go straight
go left
go right
end

Наконец, вот примеры w=4, h=5, s=20и w=4, h=5, s=16:


1
Вся идея - просто случайная прогулка, верно?
Akangka

Ряд 2: You will be drawing a non-self-intersecting random walk... это самопересекающийся или нет?
edc65

@ChristianIrwan Ну не совсем. Случайные прогулки обычно могут удвоиться или не пересекаться вообще. Это уникальный случай, поскольку пересечения сделаны, но они не считаются повторными. И да, это может быть в формате ascii-art или что-то в этом роде, но мне нравится идея создавать красивые картинки.
Увлечения Кэлвина

2
@ChristianIrwan Я уже ответил на это, когда сказал: «Да, это может быть в формате ascii-art или что-то в этом роде, но мне нравится идея делать красивые картинки». Я предпочитаю не привлекать ascii-art.
Увлечения Кэлвина

1
Разрешены ли "узлы"?
aditsu

Ответы:


4

CJam, 274

q~:K;:B;:A;{0aA*aB*:M5*5f*:I;K{[Bmr:QAmr:P]5f*:R;3Ym*{R.+:)2{1$0=I=2$W=@tI@0=@t:I;}:F~}/R2f+1FK({MQ=P=:EY4mr:D#&1{{MQMQ=PE2D#+tt:M;}:G~7,1>[W0_1_0_W]2/D=:Off*{[QP]5f*2f+.+_:H1F_OW%.+2FOW%.m2F}/H2FO~P+:P;Q+:Q;MQ=P=:E_5YD2%-*=!JK2-=+*1{D2+4%:D;G}?}?}fJ]}0?}g'P2NA5*SI,N2NI:+N*

Попробуйте онлайн

Использует PBC, выводит в формате PGM. Вы можете удалить :+ближе к концу, чтобы получить более хороший визуальный вывод в браузере.

Это очень медленно для большего ввода, особенно если количество шагов близко к области.

Пример результата для ввода 4 3 10(масштабируется на 500%):

пример

Краткое объяснение:

Общий подход:

  • повторите все следующие шаги до успешного завершения:
  • инициализировать 2 матрицы: одну запись, какие стороны используются в каждой ячейке, и одну для изображения
  • если s = 0, мы закончили, иначе:
  • выберите случайную ячейку и нарисуйте квадрат, затем сделайте следующее s-1 раз:
  • выбрать случайное направление; если эта сторона уже используется, потерпите неудачу и начните сначала
  • пометьте сторону как использованную и нарисуйте фактическую трубу на изображении (начертите 3 соседние линии длиной 6, начиная справа «после» центрального пикселя текущей ячейки, затем добавив точку, чтобы закрыть конец трубы)
  • обновить текущую позицию (перейти к следующей ячейке)
  • проверьте, пуста ли ячейка или она является действительным пересечением; если нет, то не получится
  • отметьте сторону в противоположном направлении, как в этой ячейке, затем продолжите цикл

1

QBasic, 517 516 байт

RANDOMIZE TIMER
SCREEN 9
INPUT w,h,s
1CLS
IF s=0GOTO 9
x=5*INT(RND*w)
y=5*INT(RND*h)
GOSUB 7
FOR k=1TO s-1
r=INT(RND*4)+1
a=x+5*((r=2)-(r=4))
b=y+5*((r=1)-(r=3))
c=(POINT(a,b+2)*POINT(a+4,b+2)+POINT(a+2,b)*POINT(a+2,b+4))*(0=POINT((a+x)\2+2,(b+y)\2+2))
IF((0=POINT(a+2,b+2))+c)*(a>=0)*(b>=0)*(a<5*w)*(b<5*h)=0GOTO 1
x=a
y=b
GOSUB 7
o=1AND r
p=x-2+3*o-5*(r=2)
q=y+1-3*o-5*(r=1)
u=p+3-o
v=q+2+o
LINE(p,q)-(u,v),7,B
LINE(p+o,q+1-o)-(u-o,v-1+o),1
NEXT
9IF c GOTO 1
END
7LINE(x+1,y+1)-(x+3,y+3),7,B
PSET(x+2,y+2),1
RETURN
  • Принимает w, hи sиз пользовательского ввода, через запятую.
  • Вывод выводится на экран. Пока программа ищет решение, вы можете увидеть, что частичные решения мерцают в прошлом.
  • Не использует периодические граничные условия. Мне было легче рисовать и тестировать соединения, не беспокоясь о том, что половина трубы находится на одной стороне сетки, а половина - на другой.

Подход здесь заключается в том, чтобы на каждом шаге попробовать случайное направление и начать все сначала, если это приведет к неверному движению. Мы рисуем трубы по мере определения направлений и используем их POINTдля проверки точек на экране в соответствии с нашими условиями действия. Ход действителен, если он не выходит за пределы сетки и:

  1. Перемещенная ячейка пуста; или
  2. И то и другое
    1. Перемещаемая ячейка содержит трубу, проходящую прямо через горизонтально или вертикально, и
    2. Новая секция трубы не удваивает существующую секцию трубы

Как и в ответе CJam от aditsu , этот код очень медленный и может быть ошеломляющим, если он sсоставляет значительную часть w*h. На моей настройке QB64 он дает ответ 5,5,19довольно быстро, но занимает больше времени, чем я готов был ждать 5,5,20.

Если вы хотите запускать большие / более плотно упакованные примеры, вот мой оригинальный подход с использованием поиска в глубину . Это гораздо более эффективно, за счет колоссальных 300 дополнительных байтов.

RANDOMIZE TIMER
SCREEN 9
INPUT w,h,s
DIM t(s),m(s)
0
FOR z=1TO s
t(z)=-1
NEXT
i=5*INT(RND*w)
j=5*INT(RND*h)
k=1
1CLS
IF s=0GOTO 9
x=i
y=j
GOSUB 7
FOR z=1TO k-1
r=m(z)
GOSUB 6
x=a
y=b
GOSUB 7
o=1AND r
p=x-2+3*o-5*(r=2)
q=y+1-3*o-5*(r=1)
u=p+3-o
v=q+2+o
LINE(p,q)-(u,v),7,B
LINE(p+o,q+1-o)-(u-o,v-1+o),1
NEXT
IF c*(k=s)THEN k=k-1:GOTO 1 ELSE IF k=s GOTO 9
IF k<1GOTO 0
IF t(k)>=0GOTO 4
t(k)=0
f=30
WHILE f
r=INT(RND*4)+1
IF f AND 2^r THEN t(k)=t(k)*5+r:f=f-2^r
WEND
4r=t(k)MOD 5
m(k)=r
t(k)=t(k)\5
GOSUB 6
c=(POINT(a,b+2)*POINT(a+4,b+2)+POINT(a+2,b)*POINT(a+2,b+4))*(0=POINT((a+x)\2+2,(b+y)\2+2))
IF((0=POINT(a+2,b+2))+c)*(a>=0)*(b>=0)*(a<5*w)*(b<5*h)THEN k=k+1 ELSE IF t(k)>0GOTO 4 ELSE t(k)=-1:k=k-1
GOTO 1
6a=x+5*((r=2)-(r=4))
b=y+5*((r=1)-(r=3))
RETURN
7LINE(x+1,y+1)-(x+3,y+3),7,B
PSET(x+2,y+2),1
RETURN
9

Пример вывода для входных данных 10, 10, 100, фактический размер:10х10 случайная сантехника

Еще более причудливая версия может быть найдена в этой сути . Помимо того, что его не разгуливают и тщательно комментируют, он увеличивает постоянный коэффициент на выходе и допускает заданную задержку между шагами, позволяя вам наблюдать за алгоритмом DFS в работе. Вот пример запуска:

делюкс сантехника.баз в действии

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.