Код Гольф: ваш собственный горизонтальный змей ASCII

29

Очень вдохновленный этим испытанием Code Golf: Ваша собственная домашняя змея ASCII - я подумал, что если сделать это горизонтально, это добавит дополнительный уровень сложности.

Пример горизонтальной змеи:

            0 0               
  0        0 0 000            
00 0     00       000 0      0
    000 0            0 0   00 
       0                000   

И правила таковы:

  1. Ровно 5 строк символов напечатано
  2. Каждая строка ровно 30 символов, состоящая из комбинации пробелов и символа, который вы выбираете, чтобы нарисовать свою змею
  3. Ваша змея начинается на линии 3
  4. Следующая строка, которая будет использоваться для рисования вашей змеи, должна быть случайным образом выбрана из текущей строки, на одну строку выше (если вы еще не в строке 1) или на одну строку ниже (если вы еще не в строке 5).
    • Эти выборы должны быть одинаково взвешены. Поэтому, если вы находитесь на линии 1, у вас есть 50% шанс остаться на линии 1 и 50% с вероятностью перейти на линию 2. Если вы на линии 2, у вас есть 33% шанс перейти на линию 1, а 33% шанс остаться на линии 2 или 33% шанс перейти на линию 3
  5. Ваша змея не должна посещать каждую строку.
бежит стремглав
источник
5
Добро пожаловать в PPCG! Это хороший первый вызов.
Джузеппе
Для пояснения, если мы на грани, должны ли мы равномерно выбирать (оставаться на одной линии) и (переходить на другую линию) или у нас могут быть неравномерные веса?
Джузеппе
И по краям, мы должны равномерно подобрать / вниз / ту же линию?
Джузеппе
2
Ммм ... по крайней мере, ограничение в 5 строк не дает людям красть ответы другого с добавлением транспонирования.
Волшебная Урна Осьминога
9
Физическое вращение монитора на 90 ° считается байтом? : D
Эрик Думинил

Ответы:

11

JavaScript (ES6), 98 байт

Сохранено 7 байтов благодаря @KevinCruijssen

Возвращает массив из 5 строк.

f=(y=2,a=[...'  0  '])=>a[0][29]?a:f(y+=(Math.random()*(y%4?3:2)|0)-!!y,a.map((v,i)=>v+=i-y&&' '))

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

комментарии

f = (                       // given:
  y = 2,                    //   y = current line (0-indexed)
  a = [...'  0  ']          //   a[] = array of 5 lines
) =>                        //
  a[0][29] ?                // if all columns have been processed:
    a                       //   stop recursion and return a[]
  :                         // else:
    f(                      //   do a recursive call with:
      y += (                //     the updated value of y, to which we add -1, 0 or 1:
        Math.random() *     //       pick a random value in [0,1)
        (y % 4 ?            //         if y is neither 0 or 4:
          3                 //             multiply it by 3
        :                   //           else:
          2                 //             multiply it by 2
        ) | 0               //       force an integer value
      ) - !!y,              //     subtract either 0 or 1
      a.map((v, i) =>       //     for each value v at position i in a[]:
        v += i - y && ' '   //       append either '0' if i = y or a space otherwise
      )                     //     end of map()
    )                       //   end of recursive call
Arnauld
источник
Вы можете отбросить dи использовать ((y%4?3:2)|0)-(y>0)для -6 ​​байтов. Попробуйте онлайн.
Кевин Круйссен
Исправление: -7 байт. 1В new Random(...)подразумевается по умолчанию, конечно .. Попробуйте его в Интернете.
Кевин Круйссен
@KevinCruijssen Спасибо! ( !!yвместо того, чтобы (y>0)сохранять еще 2 байта.)
Арно
7

Древесный уголь , 28 байт

P|   F³⁰«0≡ⅉ²M‽²↑±²M‽²↓M⊖‽³↓

Попробуйте онлайн! Ссылка на подробную версию кода. Объяснение:

P|   

Напечатайте некоторые отступы, чтобы форсировать 5 строк вывода.

F³⁰«

Повторите 30 раз.

0

Напечатайте ноль (и двигайтесь горизонтально).

≡ⅉ²M‽²↑

Если Y-координата равна 2, двигайтесь вверх случайным образом на 0 или 1.

±²M‽²↓

Если это -2, двигайтесь вниз случайным образом на 0 или 1.

M⊖‽³↓

В противном случае двигайтесь вниз случайным образом на -1, 0 или 1.

Нил
источник
6

Perl, 68 байт

perl -E '$%=2;s:$:$n++%5-$%&&$":emg,$%-=!!$%+rand!($%%4)-3for($_=$/x4)x30;say'

Это не чувствует себя оптимальным на всех.

Тон Хоспел
источник
5

Желе , 24 байта

3µ’o1r‘«5¥$Xµ30СṬ€o⁶z⁶Y

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

объяснение

3µ'o1r '«5 ¥ $ Xµ30СṬ € o⁶z⁶Y || Niladic полная программа.
                         ||
3 || Начиная с 3 ...
 µ µ30 || ... выполнить 30 раз ...
               С || ... и собрать результаты в виде списка.
  'o1r' «5 ¥ $ X || - | Монадическая функция "Помощник".
  'o1 || - | Текущее целое число, уменьшенное ИЛИ 1.
     r X || - | Возьмите случайный предмет из диапазона от ^ до ...
      «« 5 || - | ... Число увеличивается, ограничено до 5 (использует максимум).
         ¥ $ || - | Синтаксические элементы. Используется для группировки ссылок.
                 Ṭ € || Неправда каждого.
                   о⁶ || Логическое ИЛИ с одним пробелом.
                     z⁶ || Транспонировать с пробелами.
                       Y || Присоединяйтесь по новым строкам.
Мистер Xcoder
источник
5

Python 3, 144 байта

@Ruts, @Turksarama и @mypetlion очень помогли уменьшить байты

import random
m=[list(' '*30)for y in range(5)]
l=2
for i in range(1,30):
 m[l][i]=0
 l+=random.randint(~-(l<1),l<4)
for j in m:
  print(*j)

Постараюсь улучшить это. Веселый вызов!

linemade
источник
3
Изменить, l+=random.randint(-1,1) l=0 if l<0 else l l=4 if l>4 else lчтобы l+=random.randint(~-(l<1),l<4)сохранить 31 байт.
mypetlion
1
Вы должны быть в состоянии удалить много пробелов и новых строк.
г-н Xcoder
1
Изменить, m=[[' 'for x in R(w)]for y in R(h)]чтобы m=[list(' '*w)for y in R(h)]сохранить 7 байтов.
Mypetlion
2
В Python booleanподкласс int. Так что Falseможно использовать вместо 0и Trueможно заменить 1. Это ~унарный оператор для побитового оператора, notи -оператор переворачивает знак (умножить на -1). Так что ~-(False)оценивает -1и ~-(True)оценивает до 0.
mypetlion
1
Присвойте начальный 0 внутри вашего цикла и установите l после назначения. Это экономит одну целую строку ( m[2][0]=0ушел) и 2 байта цикла for ( for i in R(1,30):становится for i in R(30):). Вам также нужно будет пересчитать l после того, как вы установите 0. Это должно привести к 144 байтам.
Турксарама
4

R , 120 114 байтов

m=matrix
r=m(" ",30,5)
x=3
for(i in 1:30){r[i,x]=0;x=x+sample(-1:1,1,,m(c(0,rep(1,13)),3)[,x])}
write(r,"",30,,"")

Спасибо @Giuseppe за дополнительные 6 байтов!

Использует таблицу вероятностей следующим образом:

> matrix(c(0,rep(1,13)),3)
     [,1] [,2] [,3] [,4] [,5]
[1,]    0    1    1    1    1
[2,]    1    1    1    1    1
[3,]    1    1    1    1    0
Warning message:
In m(c(0, rep(1, 13)), 3) :
  data length [14] is not a sub-multiple or multiple of the number of rows [3]

где каждый столбец соответствует случаю, то есть столбец 1 выбирается, если змея находится в строке 1, давая вероятности 0, 1/2 и 1/2 для выбора соответственно -1 [понижаться], 0 [оставаться неподвижным] и 1 [ идти вверх] ( sampleавтоматически нормализует вероятности до 1), столбец 2 для строки 2 дает вероятности 1/3, 1/3 и 1/3 и т. д.

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

plannapus
источник
114 байт
Джузеппе
@ Giuseppe Спасибо! На самом деле не было никаких причин для его псевдонима, и я забыл использовать переработку векторов для этих дополнительных 0.
plannapus
3

SOGL V0.12 , 22 21 байт

3ā'∑∫⁵╗ž⁴H1ΧGI5χ⁴-ψ+;

Попробуй здесь!

Объяснение:

3                      push 3
 ā                     push an empty array - the canvas
  '∑∫                  30 times do, pushing counter            | stack = 3, [], 1
     ⁵                   duplicate the Y coordinate            | stack = 3, [], 1, 3
      ╗ž                 at those coordinates insert "+"       | stack = 3, ["","","+"]
        ⁴                duplicate from below                  | stack = 3, ["","","+"], 3
         H               decrease                              | stack = 3, [...], 2
          1Χ             maximum of that and 1                 | stack = 3, [...], 2
            G            get the item 3rd from top             | stack = [...], 2, 3
             I           increase it                           | stack = [...], 2, 4
              5χ         minimum of that and 5                 | stack = [...], 2, 4
                ⁴-       subtract from the larger a copy of the smaller value | stack = [...], 2, 2
                  ψ      random number from 0 to pop inclusive | stack = [...], 2, 2
                   +     add those                             | stack = [...], 4
                    ;    and get the array back ontop          | stack = 4, ["","","+"]

                         implicitly output the top item - the array, joined on newlines
dzaima
источник
2

Октава с пакетом статистики, 99 байт

Он также работает в MATLAB с помощью панели инструментов статистики.

p=3;for k=1:29
p=[p;p(k)+fix(randsample(setdiff([1 pi 5],p(k)),1)-3)/2];end
disp(['' (p==1:5)'+32])

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

Луис Мендо
источник
2

SmileBASIC, 107 105 103 89 байт

FOR I=0TO 29FOR J=0TO 5LOCATE I,J?" 0"[Y+2==J]NEXT
Y=Y+RND(3)-1D=Y/3>>0Y=Y-D-D*RND(2)NEXT
NEXT

Этот ответ более интересен, чем вертикальный, из-за (буквальных) краевых случаев.

64 байта без пробелов:

FOR I=0TO 29LOCATE,Y+2?0;
Y=Y+RND(3)-1D=Y/3>>0Y=Y-D-D*RND(2)NEXT

Я также нашел несколько вариантов строки 2 с одинаковой длиной:

Y=Y+RND(3)-1D=Y/3>>0Y=Y-D-D*RND(2)NEXT
Y=Y+RND(3)-1D%=Y/3Y=Y-D%-D%*RND(2)NEXT
Y=Y+RND(3)-1Y=Y-Y DIV 3*(RND(2)+1)NEXT
Y=Y+RND(3)-1Y=Y/3OR.Y=Y-D-D*RND(2)NEXT

Целочисленное деление Y / 3 используется для проверки, находится ли Y вне допустимого диапазона, а также для получения знака.

12Me21
источник
2

Java 8, 177 170 байт

v->{int a[][]=new int[5][30],c=0,r=2;for(;c<30;r+=Math.random()*(r%4>0?3:2)-(r>0?1:0))a[r][c++]=1;String R="";for(int[]y:a){for(int x:y)R+=x<1?" ":"~";R+="\n";}return R;}

-7 байт благодаря @ OlivierGrégoire .

Объяснение:

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

v->{                // Method with empty unused parameter and String return-type
  int a[][]=new int[5][30],
                    //  Integer-matrix of size 5x30
      c=0,          //  Column, starting at index 0
      r=2;          //  Row, starting at index 2
  for(;c<30;        //  Loop `c` 30 times
      r+=Math.random()*(r%4>0?3:2)-(r>0?1:0))
                    //    After every iteration: change `r` with -1,0,1 randomly
                    //     If `r` is 0: random [0;2)-0 → 0,1
                    //     If `r` is 4: random [0;2)-1 → -1,0
                    //     If `r` is 1,2,3: random [0:3)-1 → -1,0,1
    a[r][c++]=1;    //   Fill the cell at indices `r,c` from 0 to 1
  String R="";      //  Result-String, starting empty
  for(int[]y:a){    //  Loop over the rows of the matrix
    for(int x:y)    //   Inner loop over the individual column-cells of the matrix
      R+=x<1?       //    If the value of the cell is still 0:
          " "       //     Append a space
         :          //    Else (it's 1):
          "~";      //     Append the character
    R+="\n";}       //   After every row, Append a new-line
  return R;}        //  Return the result-String
Кевин Круйссен
источник
1
r+=Math.random()*(r%4>0?3:2)-(r>0?1:0)сохранить несколько байтов.
Оливье Грегуар
@ OlivierGrégoire Я думал, что уже сделал это, но, видимо, нет. Возможно я недавно сделал это в другом ответе ..: S Спасибо!
Кевин Круйссен
2

C (gcc) , 134 130 байтов

r,x,y=3,a[31],m;f(){for(x=0;x<31;x++){m?putchar(x==30?10:a[x]-m?32:48):(a[x]=y);r=rand();y+=y==1?r%2:y==5?-r%2:1-r%3;}++m<6&&f();}

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

мази
источник
Добро пожаловать в PPCG!
Мартин Эндер
Благодарность! Использование putchar вместо printf экономит 4 байта.
МаСи
1

Python 3 , 123 байта

from random import*
i,*a=2,
exec("a+=i,;i+=randint(-(i>0),i<4);"*30)
for x in range(5):print(''.join(' 0'[x==i]for i in a))

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

Создайте массив целых чисел, затем преобразуйте его в каждую строку.

Python 2 , 120 байт

from random import*
i=2;a=[]
exec"a+=i,;i+=randint(-(i>0),i<4);"*30
for x in range(5):print''.join(' 0'[x==i]for i in a)

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

Для Py2 избыточные парены для execи printмогут быть удалены, но синтаксис во 2-й строке недействителен.

Превышение подачи как Py2 от Rod, так и Py3 от linemade .

фонтанчик для питья
источник
1

Рубин , 98 77 байт

->{a=(0..4).map{" "*30}
x=2
30.times{|i|a[x][i]=?@
x+=rand(3-17[x])-30[x]}
a}

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

Лямбда, возвращающая массив строк.

Моим первоначальным импульсом было создание столбцов и их транспонирование, но гораздо проще избежать этого шага.

Я хотел бы инициализировать aс помощью [" "*30]*5, но это сделало бы мелкие копии строк, в результате чего получилась очень толстая, не скользкая змея.

Я мог бы использовать константу, например, Dв качестве приращения (для того же количества байтов), но Руби жаловался бы каждый раз, когда я назначал ее. Я решил, что предпочитаю снижение читабельности за счет повторного использования iсередины цикла, чтобы игнорировать кучу предупреждений отладки.

Я также хотел бы сэкономить несколько байтов с loop{x+=rand(3)-1;(0..4)===x&&break}, но это вызвало бы смещение по краям: 1/3 шанса повернуть назад внутрь, 1/3 шанса остаться, и 1/3 шанса выйти за пределы для какое-то время, прежде чем в конечном итоге вернуться в случайном порядке (то есть «остаться»).

-20 байт: используйте Ruby Integer#[]для создания крошечных условных выражений, обеспечивающих правильное взвешивание движения для всех 5 позиций. Это заменяет шаблон прерывания цикла (с ненулевым шансом сбоя остановки) для огромной экономии. Спасибо, Эрик Думинил !

-1 байт: инициализировать aс помощью (0..4).mapвместо 5.times, еще раз спасибо Эрику Думинилу .

->{
  a = (0..4).map{ " " * 30 }      # a is the return array: 5 strings of 30 spaces
  x = 2                           # x is the snake position
  30.times{ |i|                   # For i from 0 to 29
    a[x][i] = ?@                  #   The ith position of the xth row is modified
    x += rand(3 - 17[x]) - 30[x]  #   Using bit logic, add rand(2 or 3) - (0 or 1)
  }
  a                               # Return the array of strings
}
benj2240
источник
Хорошее начало. Нет необходимости во внутреннем loop. Вы можете рассчитать приращение с помощью rand(2+14[x])-30[x]или rand -(30[x])..15[x]. Там, вероятно, более короткая версия. Тем не менее, -20 байт не плохо! Попробуйте онлайн!
Эрик Думинил
На 1 байт меньше с x,a=2,(0..4).map{" "*30}. Попробуйте онлайн!
Эрик Думинил
1
Вау, 30[x]это отличный трюк! Благодарность!
benj2240
1

Perl 6 , 85 байт

.join.say for [Z] ((' ',' ',0,' ',' '),{.rotate(set(0,+?.[0],-?.[4]).pick)}...*)[^30]

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

Выражение с длинными скобками - это ленивая последовательность, сгенерированная из начального элемента (' ', ' ', 0, ' ', ' '), первой вертикальной полосы выходных данных. Каждая последующая полоса / список генерируется из предыдущего путем вызова rotateметода, причем смещение случайным образом выбирается из набора , содержащего 0, 1(если первый элемент не равен нулю), и-1 также (если пятый элемент не равен нулю).

Матрица горизонтальных полос переставляется [Z]оператором, превращая его в список вертикальных полос, каждая из которых затем joinобъединяется в одну строку и выводится с помощью say.

Шон
источник
1

Scala, 207 байт

val b=Array.fill(150)('.')
def s(y:Int,x:Int)={val r=Random.nextInt(6)
val z=y+(if(y>3)-r%2
else if(y<1)r%2
else r/2-1)
b(z*30+x)='$'
z}
(3/:(0 to 28))(s(_,_))
b.mkString("").sliding(30,30).foreach(println)

образец:

...................$$$...$.$$.
.$$$..............$...$.$.$...
$...$$$..$...$$.$$.....$......
.......$$.$.$..$..............
...........$..................

degolfed:

val buf = List.fill(150)('.').toBuffer
def setRowCol (y:Int, x:Int): Int = {
  val r = Random.nextInt(6)
  val z = y + (
    if (y>3) 
        -(r%2)
    else if (y<1) 
        (r%2)
    else 
        r/2-1
  )
  buf (z * 30 + x) = '$'
  z
}
(3 /: (0 to 28)(setRowCol (_, _))
println 
buf.mkString ("").sliding(30,30).foreach(println)

Мое уникальное изобретение - ну, я до сих пор не читал о других решениях, чтобы генерировать Random (6), который неявно является двумя Randoms, (2 * 3). Если вдали от границы, я использую значения r / 2 (0,1,2) и → (-1,0,1), скажи мне, чтобы идти вверх или вниз. Если на границе, я могу избежать дорогостоящего вызова персонажа другого случайного персонажа и просто взять по модулю (2), чтобы решить, остаться мне или мне идти.

Давайте посмотрим на другие решения. :)

неизвестный пользователь
источник
Да, неправильный образец изображения. Оно делает. :)
пользователь неизвестен
скала скалы! о ... код гольф .. неправильный вариант использования он появляется .. Как, черт возьми, он попал java?
Джавадба
@javadba: Вы нажали на try itссылку? Кевин Круйссен не включил в себя какой-то шаблон, необходимый для компиляции этого кода или для его запуска в JShell, но я думаю, что это в соответствии с руководящими принципами - возможно, существует мета обсуждение. Если хотите, вы можете попытаться уменьшить этот код, также используя двумерный массив. Вторая идея состоит в том, чтобы уменьшить скользящий код в конце. Какой-то метод карты? Печать скрыта Кевином. - Да, Array дает улучшение на 8.
Пользователь неизвестен
Пусть scala выведет тип возвращаемого значения int: Сохранено еще 4 символа.
пользователь неизвестен
так что теперь он выходит на стадион для Java
Javadba
1

Perl, 83 101 байт

perl -E '$l=3;map{map$s[$_-1].=/$l/?0:" ",1..5;$l-=1-int 3*rand;$l=~y/60/51/}1..30;say for@s'

Новое: без вероятности вопроса на границах:

perl -E '$l=3;map{map$s[$_-1].=/$l/?0:" ",1..5;$l=int($l<2?1+2*rand:$l>4?6-2*rand:$l-1+3*rand)}1..30;say for@s'

Ungolfed:

$l=3;                             #start line
map{
  map $s[$_-1].=/$l/?0:" ",1..5;  #0 at current char and line, space elsewhere
  $l-=1-int 3*rand;               #up, down or stay
  $l=int( $l<2 ? 1+2*rand
        : $l>4 ? 6-2*rand
        :        $l-1+3*rand )    #border patrol
}
1..30;                            #position
say for@s                         #output result strings/lines in @s
Кжетил С.
источник
2
Ваш пограничный патруль не дает 50% вероятности остаться на краю.
Тон Хоспель
0

PowerShell , 133 байта

$a=(,' '*30),(,' '*30),(,' '*30),(,' '*30),(,' '*30);$l=2;0..29|%{$a[$l][$_]=0;$l+=0,(1,($x=1,-1),$x,$x,-1)[$l]|Random};$a|%{-join$_}

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

Создает двумерный массив из 30 пространств шириной 5 строк. (NB - если кто-то может придумать более эффективный способ инициализации этого массива, я буду <3 навсегда.) Устанавливает вспомогательную переменную $lв 2(это используется для той строки, на которой был предыдущий сегмент змеи). Затем переходит от 0к 29.

Каждую итерацию мы устанавливаем для нашего элемента snake 0. Затем мы индексируем в сложный массив, Get-Randomкоторый выбирает, идти ли нам вверх или вниз или оставаться неизменным. Это добавлено обратно в $l.

Наконец, мы перебираем все пять элементов $aи -joinих внутренние элементы в одну строку каждый. Эти пять строк остаются в конвейере, и неявное Write-Outputдает нам новые строки бесплатно.

AdmBorkBork
источник
0

Clojure, 123 байта

А вот и парни:

(let[l(take 30(iterate #(max(min(+(-(rand-int 3)1)%)4)0)3))](doseq[y(range 5)](doseq[x l](print(if(= y x)0" ")))(println)))

Безголовая версия:

(let [l (take
       30
       (iterate
        #(max
          (min
           (+ (- (rand-int 3) 1) %)
           4)
          0)
        3))]
(doseq [y (range 5)]
  (doseq [x l]
    (print (if (= y x) 0 " ")))
  (println)))

Создает список различных высот тела змеи, затем выполняет итерацию от 0 до 4. Всякий раз, когда высота соответствует текущей строке, она печатает 0, в противном случае - пробел. Не позволяя высотам выходить за границы, стоит байт. Также распознавание, когда новая строка в порядке, является более интенсивным байтом, как это и должно быть. Можно легко написать одинdoseq , составив декартово произведение х и у, но тогда не знаешь, когда печатать новую строку.

Джошуа
источник
0

Python3 + NumPy, 137 132 байта

Не самая короткая подача Python, не самая длинная и, безусловно, не самая быстрая.

from pylab import*
j=r_[2,:29]
while any(abs(diff(j))>1):j[1:]=randint(0,5,29)
for i in r_[:5]:print(''.join(' #'[c] for c in j==i))

update Используя numpyкоманду diff, мы сохранили 5 байтов для проверки, является ли змея допустимым шаблоном, по сравнению с вычислением разницы вручную с помощью j[1:]-j[:-1].

user2699
источник
0

R , 95 байт

x=3;l=1:5
write(t(replicate(30,{y=ifelse(x-l,' ',0);x<<-sample(l[abs(x-l)<2],1);y})),'',30,,'')

Следующая строка xвсегда выбирается из строк, которые находятся на расстоянии не более 1 от текущей строки ( l[abs(x-l)<2]). Использование replicateвместо forцикла экономит некоторые байты, необходимые для инициализации матрицы и манипуляции с ней, и требует использования <<-оператора при присваивании глобальной переменной x.

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

Роберт Хакен
источник
0

05AB1E , 25 байтов

Y30F©ð5×0®ǝs<DÌŸ4ÝÃΩ}\)ζ»

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

объяснение

Y                           # push the initial value 2
 30F                        # 30 times do
    ©                       # store a copy of the current value in register
     ð5×                    # push 5 spaces: "     "
        0®ǝ                 # insert 0 at the position of the current value
           s<DÌŸ            # push the range [current-1 ... current-1+2]
                4ÝÃ         # keep only numbers in [0 ... 4]
                    Ω       # pick one at random
                     }\     # end loop and discard the final value
                       )ζ   # transpose the list
                         »  # join by newlines
Emigna
источник