Let's see some action!
Labyrinth, 394 386 bytes
I proudly introduce...
<}74}}:23}29}59}}}}}}}:111_}}}}:::::::23_}:111
? @
:" }}_47}_95 3""""""""(
_ : } _ } {=}
2 23_}29_ _ ; : \
0 ; 3 +_( 3_" 60{ .{.{.
"-_95:}}"" 2 0 ) 2 " _ _ {
"" _ : 2 _ ."(; } 3 .{
;_92}_47} : _ 0 = : * ;
: "" 2 {.{{ . -""(
}}:59_}}:::: "";_ . { _ "
} " {.{.{. 32.
}}}_95:}}}}_20-
...my new two-dimensional esolang Labyrinth! The code above isn't incredibly well golfed (there are 161 spaces and 25 NOPs, so a better layout could shorten this a lot), but at least I managed to show that the language is usable for non-trivial tasks. :)
How it works
First, a quick overview of the language:
- Labyrinth operates on two stacks, main and auxiliary, which can hold arbitrary signed integers. At the bottom of both stacks there is an infinite amount of zeroes.
- Commands are individual characters on a 2D grid and they form a maze (that is unknown characters, particularly spaces, are walls).
"
is a NOP which is not a wall and can be helpful for padding certain paths in the code. As opposed to many other 2D languages, the edges do not wrap around. - The instruction pointer (IP) starts at the first non-wall character (in reading order) moving to the right.
@
terminates the program. - If possible, the IP follows corridors (also around bends). If the IP has multiple cells to move to, it will generally turn left if the top of the main stack is negative, move straight ahead if it's zero, or turn right if it's positive. When the IP hits a wall it reverses direction. (There are a few more subtleties, but they shouldn't matter for this code.) This is the only way to implement control flow.
- Apart from arithmetic and stack manipulation commands, the source code can be modified at runtime with the four commands
>v<^
which will shift a row or column of the source code cyclically by one cell. Which row or column is affected depends on the top of the stack. If the IP's own row or column is shifted, it will move with the shift. This makes it possible to jump from one edge of the source code to the other.
Now for this particular challenge, here is the general idea of the algorithm:
- Push the ends of the cars up to the bonnets (i.e.
/ \_o oo o
) onto the auxiliary stack. - Read the input and determine whether to push
__
or/\
next. - Push the remainder of the cars (i.e.
__ __ _/ \
and two leading spaces) onto the auxiliary stack. - Clamp the input to a maximum value of
20
, let's call this N. - Now do the following 3 times:
- Print N spaces.
- Print 6 stored characters.
- Print 60 - 3*N spaces.
- Print 6 stored characters.
- Print a newline.
Finally, let's look at some parts of the code. The IP starts in the top left corner, on a grid shifting command. The top of the main stack is 0
(which is used as a relative index), so the first row is shifted to the left, which also moves the IP to the right end of the grid. Now the first row is simply executed from right to left, which pushes the first set of fixed characters onto the auxiliary stack:
}74}}:23}29}59}}}}}}}:111_}}}}:::::::23_}:111<
This row shifting is useful for golfing when you want to start with a large amount of linear code.
Next we read the input and push the correct bonnets:
?
:"
_
2
0 ;
"-_95:}}""
"" _
;_92}_47}
The bit on the left with the three NOPs sends negative results along the top branch and non-negative results along the bottom branch. At the right they are joined back together.
Now follows another large linear section (which could probably be golfed a lot with another row-shifting trick):
}}_47}_95
: }
23_}29_ _
3
2
:
:
:
}}:59_}}::::
}
}}}_95:}}}}
This pushes the remainder of the cars onto the auxiliary stack.
Next, we compute min(20, input)
, which is similar to first branch:
;
+_(
0 )
2 _
_ 0
"" 2
"";_
"
_20-
Finally, we have the loop which runs three times to print the lines. Each iteration of the loop contains two small (3x3) loops to print the spaces, as well as two sections to print 6 characters from the auxiliary stack:
@
3""""""""(
_ } {=}
: \
3_" 60{ .{.{.
2 " _ _ {
."(; } 3 .{
= : * ;
{.{{ . -""(
. { _ "
{.{.{. 32.
One nifty trick I'd like to draw attention to is the .{.{.
at the right edge. This is a dead end, so apart from the .
at the end the code is executed twice, once forward and once backward. This gives a neat way to shorten palindromic code (the catch is that you need to make sure the IP takes the correct turn when exiting the dead end again).
CJam, 68 66 bytes
liKe<:M" __ _/ \_o o"6/f{\S*1$+60M3*-S*@N}:+MK={58'/t59'\t}&
Try it online
Anybody who sees the start of the code will be sure to liKe
it!
Explanation:
li Get input n and convert to integer.
Ke< Cap n at 20.
:M Save in variable M for multiple use later.
" __ _/ \_o o"
Car (18 characters).
6/ Split into 3 lines of 6 characters.
f{ Map lines with parameter.
\ Swap n to top.
S* Create string with n spaces for left margin.
1$ Copy one car line to top. Keep original for second car
+ Concatenate the spaces and car.
60M3*- Calculate 60-3*n, which is the amount of space between cars.
S* Create string with 60-3*n spaces.
N Add a newline.
} End of line mapping.
:+ Concatenate all output pieces into single string.
MK= Check if capped n is equal to 20.
{ If equal, replace hoods with crashed versions.
58'/t '/ at position 58.
59'\t '\ at position 59.
}& End of conditional block for crashed hoods.
Python 2.7, 167 164 159 Bytes
n=input();s,x=60-3*n,min(n,20)
for e in[' _',"_/ ","o "]:p=e+(e[::-1],(' \_',' \/')[s<1])['/'in e];print" "*x+p+" "*s+(p[-1]+p[1:-1]+p[0]).replace("//","\/")
This takes input from stdin.
Demo here
Testing this -
$ ./cars.py
0
__ __
_/ \_ _/ \_
o o o o
$ ./cars.py
11
__ __
_/ \_ _/ \_
o o o o
$ ./cars.py
20
__ __
_/ \/\/ \_
o oo o