| Bytes | Lang | Time | Link |
|---|---|---|---|
| 077 | ☾ | 250426T174448Z | noodle p |
| 195 | JavaScript Node.js | 250411T054025Z | l4m2 |
| 045 | Uiua | 250418T144046Z | noodle p |
| 254 | Perl 5 | 250415T185642Z | Kjetil S |
| nan | Google Sheets | 250412T054110Z | z.. |
| 189 | Maple | 250413T021358Z | dharr |
| 163 | Ruby | 250412T011144Z | Level Ri |
| 341 | Julia | 250411T191638Z | Sort of |
| 027 | 05AB1E | 250411T081752Z | Kevin Cr |
| 018 | Charcoal | 250411T084516Z | Neil |
☾, 83 77 chars
ſ²y∈⟝⭜xᖘᴙᣆʸᐸᐸ⭝x+ₓϜ+→ᴙ₁﹕≕c⍉ᴍ⟷ꟿ≺⊞ᴍ²cᔨx≕i≡□⭜𝘀⭝⟞∖⟝→ᴙᵢᴍ⨁ᴍ☾ᐘ‹/\›
The first part of this solution is constructing an array of coordinates corresponding to each character of the string. First, the string is reduced, starting with an initial value of [[0,1]].In each iteration, if the character is one of /\, the last item is reversed, and if it is / it is also negated. If the character wasn't one of those, the last item of the list is duplicated. This reduction gives a direction to each character, and taking the cumulative summation gives the intended array of coordinates.
The second part is going from this list of coordinates to a 2-dimensional array with each character at the right position. The idea is to make a table of all coordinates in the range, and map each to the last index of that coordinate in the list. If the coordinate isn't there, then a space is put there, otherwise the corresponding character from the original string with all slashes removed is used.
After all that, it's a simple process of joining each line to a string and printing them.
JavaScript (Node.js), 195 bytes
f=(s,x=X=W=H='',y=Y=0,d=1,D=q=0,o=[...H].map(_=>[...W]))=>s.some(c=>([d,D]=c=='\\'?[-D,-d]:c=='/'?[D,d]:[d,D,q&&(x-=d,y-=D),y<0?++Y:H[y]?x>0?--X:W[-x]?![q=o[y][-x]=c]:W+=' ':H+=0])[3])?f(s,X,Y):o
Lots of work on exacting boundary
Note that x is negated, as it shortens 1 bytes for d, and all use of x need explicit convert into number
// Somehow outdated
/// followed by manual comment, // by AI comment, // <s> AI's incorrect comment
f = (
s, // `s` is the input string or array to process.
x = X = W = H = '', // `x` and `X` track horizontal positions, initialized as empty strings.
/// which is treated as zero in `x` and `X`, string for counter in `W` and `H`
y = Y = 0, // `y` and `Y` track vertical positions, while `H` acts as the first "row" with a default 0.
d = 1, // `d` represents horizontal direction (1 for right, -1 for left).
D = 0, // `D` represents vertical direction (1 for down, -1 for up).
o = [...H] // `o` is a 2D array derived from `H`. Mapping the string `H` into an array with sub-arrays.
.map(_ => [...W]) // For every element `H`, create rows initialized with the current width `W`.
/// `W` would contain only spaces, so `o` is full of spaces, as empty canvas.
) =>
s.some((c, i) => // Begin processing the input array `s` via `.some` for iteration with conditions.
( // For each character `c` in `s`, compute its movement based on the character and update variables.
[d, D] = // Update direction or positions based on the character.
c == '\\' ? [-D, -d] // A backslash `\` inverts directions.
/// also swaps, so it works as mirror. Same below.
: c == '/' ? [D, d] // A forward slash `/` swaps directions.
: [d, D, // Otherwise, maintain position and attempt movement.
i && (x -= d, y -= D) // For all iterations (except the first), decrement by `d` and `D`.
/// Use `-=` to handle empty string(initial value) well
],
// Handle boundaries and updates based on row and column positions.
y < 0 ? ++Y // If beyond the top, <s> extend a new row at the top.
/// then would restart but initial Y increases
: H[y] /// If inside
? x > 0 // If within a row:
? --X // <s> Shift left in the current row.
/// then would restart but initial X increases
: W[-x] // <s> If at/near a boundary:
/// If inside
? ![o[y][-x] = c] // Place character `c` into the 2D grid `o`.
/// and return false (other operations modifying initial condition return true)
: W += ' ' // Otherwise, grow the row's width by one.
: H += 0 // If beyond the existing rows, <s> add a new "0" row.
/// add a row, content irrelevant
)[3] // Process the last element of the computed array.
) /// aka. is it a restart request
? f(s, X, Y) // If `.some` returns `true` (i.e., a condition matches), recurse with updated values.
: o // When all input has been processed, return the final 2D array `o`.
Uiua, 50 46 45 bytes
⬚@ ⌝⊡∩⌞▽⊸⍜⇌◰-¤⊸/↧\+˜⊏⍜↘₂⇌A₂°⋯∩⌞▽¬⊙\≠⊸⊃∊=⌞$ \/
Try it here!
Consider the input boa/co\ns/t\rictor.
The first step is to take sections of the input between corresponding slashes and backslashes.
# compare each character to \/
⍉ =⌞$ \/
╭─
╷ 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0
╯
# scan by ≠ so areas between ones are all 1
⍉ \≠ =⌞$ /\
╭─
╷ 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0
╯
# remove all /\ from both the input and this array
⍉ ∩⌞▽¬ ⊙\≠⊸⊃∊=⌞$ /\
"boaconstrictor"
╭─
╷ 0 0 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 1 1 1 1 0 0 0 0 0 0 0
╯
# read each vector of 2 elements as binary
°⋯ ▽¬⊙\≠⊃∊=⌞$ \/
[0 0 0 2 2 3 3 1 0 0 0 0 0 0]
Now we have assigned a number to each of the four directions -- 0 for right, 1 for down, 2 for up, 3 for left. We can't use this format to easily get coordinate pairs, though; we need right to be represented as [0 1], down as [¯1 0], etc. Fortunately, Uiua has a certain built-in constant which comes in very handy: A₂, the 2-dimensional adjacent neighbor offsets:
A₂
╭─
╷ 0 1
1 0
0 ¯1
¯1 0
╯
The only problem is that this isn't in quite the right order, but swapping the last two rows with ⍜↘₂⇌ solves that. ˜⊏ uses the original numbers as indices into this list:
⍉ ˜⊏⍜↘₂⇌A₂ °⋯▽¬⊙\≠⊃∊=⌞$ \/
╭─
╷ 0 0 0 ¯1 ¯1 0 0 1 0 0 0 0 0 0
1 1 1 0 0 ¯1 ¯1 0 1 1 1 1 1 1
╯
# cumulative sums
⍉ \+ ˜⊏⍜↘₂⇌A₂°⋯▽¬⊙\≠⊃∊=⌞$ \/
╭─
╷ 0 0 0 ¯1 ¯2 ¯2 ¯2 ¯1 ¯1 ¯1 ¯1 ¯1 ¯1 ¯1
1 2 3 3 3 2 1 1 2 3 4 5 6 7
╯
Now we have an array of coordinates, and we can use inverse of ⊡ pick to make an array with corresponding values at those coordinates, but first we need to make all coordinates positive and remove duplicate positions.
# subtract from each the minimum of all the coordinates
⍉ -¤⊸/↧ \+˜⊏⍜↘₂⇌A₂°⋯▽¬⊙\≠⊃∊=⌞$ \/
╭─
╷ 2 2 2 1 0 0 0 1 1 1 1 1 1 1
0 1 2 2 2 1 0 0 1 2 3 4 5 6
╯
# remove duplicate coordinates from the string, counting from the back
∩⌞▽⊸⍜⇌◰ -¤⊸/↧\+˜⊏⍜↘₂⇌A₂°⋯∩⌞▽¬⊙\≠⊸⊃∊=⌞$ \/
"boaonstrictor"
╭─
╷ 2 2 2 0 0 0 1 1 1 1 1 1 1
0 1 2 2 1 0 0 1 2 3 4 5 6
╯
# put characters at these coordinates, filling with spaces
⬚@ ⌝⊡ ∩⌞▽⊸⍜⇌◰-¤⊸/↧\+˜⊏⍜↘₂⇌A₂°⋯∩⌞▽¬⊙\≠⊸⊃∊=⌞$ \/
╭─
╷ "sno "
"trictor"
"boa "
╯
Perl 5, 254 bytes
eval'sub{(X,Y,I,J,%g)=(1,0,-1,0);/\w|-/?($g{I+=X,J+=Y}=$_):(S=1-2*/\//,(X,Y)=(X?0:S*Y,Y?0:S*X))for pop=~/./g;(I,X,J,Y)=map{R=$_;(sort{$a-$b}map s/R//r,keys%g)[0,-1]}"$;.+",".+$;";join"",map{/.+/;join("",map$g{$_,$&}//$",I..X)."\n"}J..Y}'=~s/[A-Z]/\$$&/gr
Google Sheets, 391 382 bytes
-9 bytes thanks to @doubleunary
=INDEX(LET(y,MID("/"&A1,ROW(1:999),1),q,FILTER({REDUCE({1,"i"},QUERY(y,"offset 1"),LAMBDA(a,c,LET(l,CHOOSEROWS(a,-1),w,INDEX(l,1),e,INDEX(l,2),{a;IF(c="/",{w,IMDIV("-i",e)},IF(c="\",{w,IMDIV("i",e)},{IMSUM(w,e),e}))}))),y},REGEXMATCH(y,"[^\\/]")),d,INDEX(q,,1),F,LAMBDA(a,SEQUENCE(MAX(a)-MIN(a)+1,1,MIN(a))),XLOOKUP(COMPLEX(F(IMREAL(d)),TOROW(F(IMAGINARY(d)))),d,INDEX(q,,3),,,-1)))
Expects input in A1.
It works by keeping track of the current position and the current direction as complex numbers.
| Number | Direction |
|---|---|
| \$+i\$ | right |
| \$-i\$ | left |
| \$+1\$ | down |
| \$-1\$ | up |
The direction is initialized to \$+i\$ (right).
When we encounter \, we get the new direction by swapping the real and imaginary parts of the previous direction.
| Prev direction | New direction |
|---|---|
| \$+i\$ | \$+1\$ |
| \$-i\$ | \$-1\$ |
| \$+1\$ | \$+i\$ |
| \$-1\$ | \$-i\$ |
When we encounter /, we get the new direction by swapping the real and imaginary parts of the previous direction and changing the sign.
| Prev direction | New direction |
|---|---|
| \$+i\$ | \$-1\$ |
| \$-i\$ | \$+1\$ |
| \$+1\$ | \$-i\$ |
| \$-1\$ | \$+i\$ |
If the current character is not / or \, the new position is the sum of the current position and the current direction, otherwise it's the current position (it remains unchanged).
Once we have all the positions, we place the characters on the grid with a simple lookup.
Maple, 189 bytes
proc(s)c:=0,0;d:=0,1;seq(`if`(i="/",(d:=-d[2],-d[1]),`if`(i="\\",(d:=d[2],d[1]),[(c+=d),(T[c]=i)])),i=s);printf("%{s}s",Array(seq(`..`(min,max)(op~(i,[indices(T)])),i=1..2),T,fill=" "))end;
Input string needs \ doubled or it is interpreted as a control character; otherwise the task is not possible in Maple. Coordinates (y,x); directions (0,1) is +x direction etc.. Golfed version condenses the for loop to a seq, and if-then-else statement to nested if expressions.
Ungolfed version:
proc(s)
c:=0,0;d:=0,1; # initial coords and direction
for i in s do # for each character
if i="/" then
d:=-d[2],-d[1] # change direction
elif i="\\" then
d:=d[2],d[1] # change direction
else
c+=d; # update coords
T[c]:=i # record character at these coords
fi
od;
printf("%{s}s", # print string, newlines are automatic at end of each row
# {s} means no spaces between chars
Array( # next line calcs x and y ranges for array
seq(`..`(min,max)(op~(i,[indices(T)])),i=1..2),
T,fill=" ")) # use table T to initialize; " " if no assigned value
end;
Ruby, 173 163 bytes
->s{u=1;m=v=0
a=(0..w=n=3*x=y=s.size).map{Q=' '*w}
s.chars{|i|(j='\ /'.index i)?(u,v=v*k=1-j,u*k):(a[y+=v][x+=u]=i
m=x>m ?x:m;n=x<n ?x:n)}
(a-[Q]).map{|h|h[n..m]}}
Commented code
->s{u=1;m=v=0 #Setup u,v as a direction vector 1,0. m=max value of x position.
a=(0..w=n=3*x=y=s.size #w=width of board, 3*input length. n=min value of x position.
).map{Q=' '*w} #Make board a of w strings Q of w spaces. Move to x,y both equal input length.
s.chars{|i| #iterate through characters in input
(j='\ /'.index i)? #j=index of \ or / (either 0 or 2, true) or false if other character.
(u,v=v*k=1-j,u*k): #If true, k=1 or -1. swap u and v, and negate with k if /.
(a[y+=v][x+=u]=i #If false, update x,y by moving by u,v. Edit the character into a and...
m=x>m ?x:m;n=x<n ?x:n)#...if x outside the bounds n..m, update n or m
} #(conditional 1 byte shorter than min/max.) Close loop.
(a-[Q]).map{|h|h[n..m]}#delete blank rows Q from a. Cut section h[n..m] from each remaining string.
} #return from function with result of last calculation.
Julia, 341 bytes
f(s)=begin
a,b,c,d=1,1,1,1
D=[]
x,y=1,0
i,j=0,1
L()=i,j=j,-i
R()=i,j=-j,i
F(z)=begin x+=i;y+=j;push!(D,(x,y,z));a=min(a,x);b=max(b,x);c=min(c,y);d=max(d,y) end
g(z)=(z=='/') ? (i!=0 ? L() : R()) : (z=='\\' ? (i!=0 ? R() : L()) : F(z))
g.(collect(s))
M=fill(' ',b-a+1,d-c+1)
map(z->M[z[1]-a+1,z[2]-c+1]=z[3],D)
println.(prod.(eachrow(M)))
end
Julia isn't really a golf language but its built-in matrix type is lovely for working with grids of chars like this. The ternary statements could be more compact but Julia syntax requires whitespace around the ?s and :s.
This is my first golf submission, so I'm sure there's lots more small optimizations that could be done, too.
05AB1E, 30 27 bytes
εY…/ \yk©di®>·^Võëˆ]Jā≠>s¯Λ
-3 bytes thanks to @Neil.
Try it online. (No test suite with all test cases at once, because the .Λ will overlap previous drawings and there isn't a way to reset it.)
Explanation:
ε # Map over each character `y` of the (implicit) input:
# (implicitly push the current character `y`)
Y # Push variable `Y` (which starts at 2)
…/ \yk # Get the (0-based) index of character `y` in "/ \",
# or -1 if it's not present in this string
© # Store this index in variable `®` (without popping)
di # Pop and if this index is non-negative (aka `y` is "/" or "\"):
® # Push index `®` (0 for "/" or 2 for "\")
> # Increase it by 1 (1 for "/" or 3 for "\")
· # Double it (2 for "/" or 6 for "\")
^ # Bitwise-XOR Y by this
V # Pop and store this value as new `Y`
õ # Push an empty string ""
ë # Else (aka `y` is a letter, "_", or "-"):
ˆ # Pop and add the current `Y` to the global array
] # Close both the outer if-else statement and map
J # Join the characters (and empty strings) together,
# which will be the input-string without the "\" and "/"
ā # Push a list in the range [1,length] (without popping)
≠ # Check for each integer that it's NOT 1: [0,1,1,1,...]
> # Increase each by 1: [1,2,2,2,...]
s # Swap so the string is at the top of the stack again
¯ # Push the global array
Λ # Use the Canvas builtin with these three arguments
# (after which the result is implicitly output immediately)
Additional explanation of the Canvas builtin Λ/.Λ:
It takes 3 arguments to draw an ASCII shape:
- Length of the lines we want to draw
- Character/string to draw
- The direction to draw in, where each digit represents a certain direction:
7 0 1
↖ ↑ ↗
6 ← X → 2
↙ ↓ ↘
5 4 3
εY…/ \yk©di®>·^Võëˆ]Jā≠>s¯ with example input boa/co\ns/t\rictor creates the following three Canvas arguments:
- Lengths:
[1,2,2,2,2,2,2,2,2,2,2,2,2,2] - Chars to draw:
[b,o,a,c,o,n,s,t,r,i,c,t,o,r] - Directions:
[2,2,2,0,0,6,6,4,2,2,2,2,2,2]
So it'll draw b of length 1 in direction 2/→:
b
Then o of length 2-1 still in direction 2/→:
bo
Likewise for a:
boa
Then for c it changes direction to 0/↑:
c
boa
Then o of length 2-1 still in direction 0/↑:
o
c
boa
Then for n it changes directions again, this time to 6/←:
no
c
boa
Etc.
See this 05AB1E tip of mine to learn more about the Canvas builtin.
As for how I change directions based on the / or \:
- For
/I do a bitwise-XOR with 2, changing the directions as: 0⇒2; 2⇒0; 4⇒6; 6⇒4 - try it online; - For
\I do a bitwise-XOR with 6, changing the directions as: 0⇒6; 2⇒4; 4⇒2; 6⇒0 - try it online; - For letters,
-, or_, the direction remains the same.
Charcoal, 18 bytes
F⮌S≡ι\‖↗/‖↘←∨⁻KKψι
Try it online! Link is to verbose version of code. Explanation: Charcoal really wants to know the direction to print before printing the character, so having the \/ after the character is really bad for it. Furthermore, although Charcoal has a function to rotate the pivot, it doesn't have one to reflect the pivot, so a separate variable would be needed to track the direction. All in all it turns out to be easier to print the snake tail first.
F⮌S≡ι
Switch over each input character in reverse order.
\‖↗
For a \ reflect the output so far along the main diagonal.
/‖↘
For a / reflect the output so far along the antidiagonal.
←∨⁻KKψι
Otherwise, output the current character, but keeping any character previously printed (as that one is later in the string and later characters have priority), then move left.
Would be 16 bytes if the turns were marked before the turning letter:
F²Fθ≡κ\‖↗/‖↘¿¬ικ
Try it online! Link is to verbose version of code. Explanation:
F²
Repeat twice. The second pass is necessary to reflect the canvas back into the original direction.
Fθ≡κ\‖↗/‖↘
Handle turns as above.
¿¬ικ
Only print the characters on the first pass.

