| Bytes | Lang | Time | Link |
|---|---|---|---|
| 042 | Uiua | 241123T212401Z | ErikDaPa |
| 092 | JavaScript ES6 | 180221T170807Z | Arnauld |
| 024 | Japt | 180221T190332Z | Shaggy |
| 176 | AWK | 241127T144643Z | xrs |
| 048 | CASIO BASIC CASIO fx9750giii | 241120T155140Z | madeforl |
| 025 | 05AB1E | 180227T141959Z | Emigna |
| 101 | Perl | 180221T182132Z | Kjetil S |
| 130 | C gcc | 180224T143055Z | MaSi |
| 026 | Japt | 180224T004011Z | ETHprodu |
| 095 | R | 180224T002018Z | Robert H |
| 071 | C gcc | 180223T152806Z | vazt |
| 170 | Java 8 | 180222T085445Z | Kevin Cr |
| nan | Python3 +numpy | 180223T040353Z | user2699 |
| 207 | Scala | 180221T215213Z | user unk |
| 085 | Perl 6 | 180222T234230Z | Sean |
| 077 | Ruby | 180222T000129Z | benj2240 |
| 089 | SmileBASIC | 180221T183803Z | 12Me21 |
| 028 | Japt | 180222T153803Z | Oliver |
| 123 | Clojure | 180222T150410Z | Joshua |
| 133 | PowerShell | 180222T143452Z | AdmBorkB |
| 144 | Python 3 | 180221T173759Z | linemade |
| 114 | R | 180222T081353Z | plannapu |
| 138 | R | 180221T165627Z | Giuseppe |
| 028 | Charcoal | 180221T175422Z | Neil |
| 123 | Python 3 | 180222T001821Z | Bubbler |
| 024 | Jelly | 180221T175137Z | Mr. Xcod |
| 099 | Octave with Statistics Package | 180221T221153Z | Luis Men |
| 068 | Perl | 180221T213301Z | Ton Hosp |
| 127 | Python 2 | 180221T191854Z | Rod |
| 021 | SOGL V0.12 | 180221T182231Z | dzaima |
Uiua, 42 bytes
≡&p⊏:" 0"⍉∵(⬚0↥⊚5°⊚)⇌[⍥(↥0↧4+-1⌊×⚂3.)29 2]
Explanation:
≡&p⊏:" 0"⍉∵(⬚0↥⊚5°⊚)⇌[⍥(↥0↧4+-1⌊×⚂3.)29 2]
2 => starting at the middle
-1⌊×⚂3. => randint (-1, 1]
+ => add to prev number
↥0↧4 => keep in range between 0 to 4
⍥( )29 => repeat 29 times
⇌[ ] => reverse list
∵( °⊚) => convert indices back into a mask
⬚0↥⊚5 => make it length-5 if not
⍉ => transpose
≡&p⊏:" 0" => convert into string and print
JavaScript (ES6), 92 bytes
Saved 7 bytes thanks to @KevinCruijssen
Saved 4 bytes thanks to @l4m2
Returns an array of 5 strings.
f=(y=2,a=[..." 0 "])=>a[0][29]?a:f(y+=(Math.random()*(2|3/y)|0)-!!y,a.map(v=>v+=y--&&" "))
Commented
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)
(2 | 3 / y) // multiply it by 3 if y is neither 0 or 4
// or 2 otherwise
| 0 // force an integer value
) - !!y, // subtract either 0 or 1
a.map(v => // for each value v in a[]:
v += y-- && ' ' // append either '0' if y=0 or a space otherwise
// decrement y afterwards
) // end of map()
) // end of recursive call
Japt, 31 29 26 25 24 bytes
Uses s for the snake.
30çÅyÈùU=5õ ö@?2>XaU:X¶3
30çÅyÈùU=5õ ö@?2>XaU:X¶3
30ç :30 times repeat
Å : "s"
y :Transpose
È :Pass each row through the following function and transpose back
ù : Left pad with spaces to length
U= : Assign to variable U (initially 0)
5õ : Range [1,5]
ö : Random element
@ : That return true when passed through the following function as X
? : If U is truthy (not 0) then
2> : 2 is greater than
XaU : Absolute difference between X & U
: : Else
X¶3 : X equals 3
Original, 25 bytes, with -R flag
Uses " for the snake. The 30 can be removed to allow the length of the snake to be taken as input.
30ÆQùV±g4ÆJõÃoÅi2 ËöÃi3ÃÕ
30ÆQùV±g4ÆJõÃoÅi2 ËöÃi3ÃÕ
30Æ :Map the range [0,30)
Q : Quotation mark
ù : Left pad with spaces to length
V± : Increment V (initially 0) by
g : Index V into (0-based and modular)
4Æ : Map the range [0,4)
J : -1
õ : Range [1,J]
à : End map
o : Modify last element
Å : Slice off first element
i2 : Prepend 2
Ë : Map each D
ö : Random element (from the range [0,D) if D is an integer)
à : End map
i3 : Prepend 3
à :End map
Õ :Transpose
:Implicit output joined with newlines
AWK, 176 bytes
func f(x){y=rand();return x?y>.5:y>.3?y>.7?1:0:-1}END{srand();for(a[i=1][x=3]=1;i++<30;a[i][x+=1~x?f(1):5~x?-f(1):f()]=1);for(;k++<5;print)for(l=0;l++<30;)printf a[l][k]?0:" "}
Well, it feels clunky as the random function and print section take most of the bytes.
func f(x){y=rand(); # random movement
return x?y>.5:y>.3?y>.7?1:0:-1} # up/down/straight
END{srand(); # gotta seed or else...
for(a[i=1][x=3]=1;i++<30; # go thirty steps
a[i][x+=1~x?f(1):5~x?-f(1):f()]=1); # set next 0
for(;k++<5;print) # out rows
for(l=0;l++<30;) # out columns
printf a[l][k]?0:" "} # print 0 or space
CASIO BASIC (CASIO fx-9750giii), 48 bytes
this one prints in graph mode, gets cleared immediately when program is finished due to how the calculator works but it does work
3→Q
For 1→R To 120 Step 4
Text 8Q,R,0
Q+RanInt#(-1(Q>1),1(Q<5→Q
Next
44 bytes
this one prints in text mode
3→Q
For 1→R To 21
Locate R,Q,0
Q+RanInt#(-1(Q>1),1(Q<6→Q
Next
Prints 21 columns (due to the size limitation of the calculator)
when the program is done, the first row gets cleared due to how the calculator works
40 bytes
this one prints in text mode, exits in an error.
3→Q
While 1
Isz R
Locate R,Q,0
Q+RanInt#(-1(Q>1),1(Q<6→Q
WhileEnd
05AB1E, 25 bytes
Y30F©ð5×0®ǝs<DÌŸ4ÝÃΩ}\)ζ»
Explanation
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
Perl, 83 101 bytes
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'
New: Without probability issue at the borders:
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
C (gcc), 134 130 bytes
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();}
R, 95 bytes
x=3;l=1:5
write(t(replicate(30,{y=ifelse(x-l,' ',0);x<<-sample(l[abs(x-l)<2],1);y})),'',30,,'')
Next line x is always chosen from lines that are no more than 1 away from current line (l[abs(x-l)<2]). Using replicate instead of a for cycle saves some bytes needed for matrix initialization and manipulation and requires the use of the <<- operator when assigning to the global variable x.
C (gcc), 80 76 72 71 bytes
a[5][30],i,r;f(){for(r=2;i<30;r+=rand()%3-1)a[r=r>4?4:r<0?0:r][i++]=1;}
Java 8, 177 170 bytes
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 bytes thanks to @OlivierGrégoire.
Explanation:
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
Python3 +numpy, 137 132 bytes
Not the shortest python submission, not the longest, and definitely not the fastest.
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 Using numpy's diff command saved 5 bytes for testing if the snake is a valid pattern, compared to calculating the difference manually with j[1:]-j[:-1].
Scala, 207 Bytes
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)
sample:
...................$$$...$.$$.
.$$$..............$...$.$.$...
$...$$$..$...$$.$$.....$......
.......$$.$.$..$..............
...........$..................
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)
My unique invention - well, I haven't read the other solutions so far, is, to generate a Random (6) which is implicitly two Randoms, (2*3). If away from the border, I use the values of r/2 (0,1,2) and → (-1,0,1) tell me, to go up or down. If at the border, I can avoid the character costly call of another random, and just take the modulo(2), to decide, should I stay or should I go.
Let's see the other solutions. :)
Perl 6, 85 bytes
.join.say for [Z] ((' ',' ',0,' ',' '),{.rotate(set(0,+?.[0],-?.[4]).pick)}...*)[^30]
The long parenthesized expression is a lazy sequence generated from the initial element (' ', ' ', 0, ' ', ' '), the first vertical strip of the output. Each successive strip/list is generated from the preceding one by calling its rotate method, with the offset randomly chosen from a set containing 0, 1 (if the first element is nonzero), and -1 (if the fifth element is nonzero).
The matrix of horizontal strips is transposed with the [Z] operator, turning it into a list of vertical strips, each of which is then joined into a single string and output with say.
Ruby, 98 77 bytes
->{a=(0..4).map{" "*30}
x=2
30.times{|i|a[x][i]=?@
x+=rand(3-17[x])-30[x]}
a}
A lambda returning an array of strings.
My initial impulse was to generate the columns and transpose them, but it's much easier to just avoid that step.
I would have liked to initialize a with [" "*30]*5, but that would make shallow copies of the strings, resulting in a very fat, non-slithery snake.
I could have used a constant like D as the increment (for the same byte count), but Ruby would have complained every time I assigned it. I decided I prefer decreasing readability by reusing i mid-loop to having a bunch of Debug warnings to ignore.
I also would have liked to save a few bytes with loop{x+=rand(3)-1;(0..4)===x&&break}, but that would have caused a bias on the edges: 1/3 chance to turn back inward, 1/3 chance to stay, and 1/3 chance to go out of bounds for a while before eventually random-walking back in (that is, "stay").
-20 bytes: Use Ruby's Integer#[] to create tiny conditionals, ensuring correct movement weightings for all 5 positions. This replaces a loop-break pattern (with a nonzero chance of failing to halt) for a huge savings. Thanks, Eric Duminil!
-1 byte: Initialize a with (0..4).map instead of 5.times, thanks again to Eric Duminil.
->{
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
}
SmileBASIC, 107 105 103 89 bytes
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
This answer is more interesting than the vertical one because of the (literal) edge cases.
64 bytes, without printing spaces:
FOR I=0TO 29LOCATE,Y+2?0;
Y=Y+RND(3)-1D=Y/3>>0Y=Y-D-D*RND(2)NEXT
I also found a few variations of line 2 with the same length:
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
The integer division of Y/3 is used to check if Y is outside the valid range, as well as getting the sign.
Clojure, 123 bytes
Here come the parens:
(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)))
Ungolfed version:
(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)))
Builds a list of the different heights of the snake body, then iterates from 0 to 4. Whenever a height matches the current row it prints a 0, otherwise a blank.
Not letting the heights exceed the boundary really costs bytes. Also recognizing when a new line is in order is more byte-intensive as it should be. One could easily write a single doseq, making a cartesian product of the x's and y's but then one does not know when to print a new line.
PowerShell, 133 bytes
$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$_}
Constructs a 2D array of 30 spaces wide by 5 lines tall. (NB - if someone can come up with a better effective way to initialize this array, I'll <3 you forever.) Sets helper variable $l to 2 (this is used for what line the previous snake segment was on). Then loops from 0 to 29.
Each iteration, we set our snake element to 0. Then we index into a complicated array with Get-Random that selects out whether we go up or down or stay the same. That's added back into $l.
Finally, we loop through the five elements of $a and -join their inner elements into a single string each. Those five strings are left on the pipeline, and the implicit Write-Output gives us newlines for free.
Python 3, 144 bytes
@Ruts, @Turksarama, and @mypetlion have been very helpful in reducing bytes
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)
Will try and improve on this. Fun challenge!
R, 120 114 bytes
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,,"")
Thanks to @Giuseppe for the additional 6 bytes!
Uses a table of probabilities as follows:
> 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]
where each columns corresponds to a case, i. e. column 1 is picked if the snake is in row 1, giving probabilities 0, 1/2 and 1/2 to pick respectively -1 [go down], 0 [stay still] and 1 [go up] (sample automatically normalize the probabilities to 1), column 2 for row 2 gives probabilities 1/3, 1/3 and 1/3, etc...
R, 138 bytes
m=matrix(" ",30,5)
m[1,3]=0
x=3
s=sample
for(i in 2:30)m[i,x<-x+(-1)^(x==5)*s(0:1,1)*x%in%c(1,5)+(s(3,1)-2)*x%in%2:4]=0
write(m,"",30,,"")
Handily outgolfed by plannapus
Charcoal, 28 bytes
P| F³⁰«0≡ⅉ²M‽²↑±²M‽²↓M⊖‽³↓
Try it online! Link is to verbose version of code. Explanation:
P|
Print some padding to force 5 lines of output.
F³⁰«
Repeat 30 times.
0
Print a zero (and move horizontally).
≡ⅉ²M‽²↑
If the Y-coordinate is 2, move up randomly by 0 or 1.
±²M‽²↓
If it's -2, move down randomly by 0 or 1.
M⊖‽³↓
Otherwise move down randomly by -1, 0 or 1.
Python 3, 123 bytes
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))
Generate an array of integers, then convert it to each row.
Python 2, 120 bytes
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)
For Py2, redundant parens for exec and print can be removed, but the syntax in the 2nd line is invalid.
Outgolfing both Py2 submission by Rod and Py3 submission by linemade.
Jelly, 24 bytes
3µ’o1r‘«5¥$Xµ30СṬ€o⁶z⁶Y
Explanation
3µ’o1r‘«5¥$Xµ30СṬ€o⁶z⁶Y || Niladic full program.
||
3 || Starting from 3...
µ µ30 || ... Execute 30 times...
С || ... And collect the results in a list.
’o1r‘«5¥$X ||--| Monadic "Helper" function.
’o1 ||--| The current integer, decremented OR 1.
r X ||--| Grab a random item from the range from ^ to...
‘«5 ||--| ... The number incremented, capped to 5 (uses maximum).
¥$ ||--| Syntax elements. Used for grouping links.
Ṭ€ || Untruth each.
o⁶ || Logical OR with a single space.
z⁶ || Transpose with filler spaces.
Y || Join by newlines.
Octave with Statistics Package, 99 bytes
It also works in MATLAB with the Statistics Toolbox.
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])
Perl, 68 bytes
perl -E '$%=2;s:$:$n++%5-$%&&$":emg,$%-=!!$%+rand!($%%4)-3for($_=$/x4)x30;say'
This doesn't feel optimal at all.
Python 2, 127 bytes
from random import*
s=['']*5
n=3
r=range(5)
exec"for i in r:s[i]+=' 0'[i==n]\nn=choice(r[n and~-n:n+2])\n"*30
print'\n'.join(s)
SOGL V0.12, 22 21 bytes
3ā'∑∫⁵╗ž⁴H1ΧGI5χ⁴-ψ+;
Explanation:
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