# Manhattan Directions Code Golf

This code golf challenge is to show directions through numbers.

When the user enters a number, then that means a direction change as follows:

0 means stay still
1 means forward (initially from left to right and initially start with :)
2 means turn right
3 means turn left
4 means go backward


I will show you an example: 122123333114

1 means 1 step forward

:═>


2 means 1 step to the right

   :═╗
‖
V


2 means 1 step to the right

    :═╗
‖
<═╝


1 means 1 step forward

    :═╗
‖
<══╝


2 means 1 step to the right

   ^:═╗
‖  ‖
╚══╝


3 means 1 step to the left

 <═╗:═╗
‖  ‖
╚══╝


3 means 1 step to the left

 ╔═╗:═╗
‖ ‖  ‖
V ╚══╝


3 means 1 step to the left

 ╔═╗:═╗
‖ ‖  ‖
╚═>══╝


3 means 1 step to the left

 ╔═^:═╗
‖ ‖  ‖
╚═╝══╝


1 means 1 step forward

   ^
╔═‖:═╗
‖ ‖  ‖
╚═╝══╝


1 means 1 step forward

   ^
‖
╔═‖:═╗
‖ ‖  ‖
╚═╝══╝


4 means 1 step backward

   ‖
╔═V:═╗
‖ ‖  ‖
╚═╝══╝


These are the rules:

• Start with : and the initial direction will be from left to right

If starting with 0, then start with:

:


If starting with 1, then start with:

:=>


If starting with 2 then start with:

:╗
‖
V


If starting with 3, then start with:

 ^
‖
:╝


If starting with 4, then start with:

<=:

• Any other numbers or letters in the input will be ignored

T6@1 92J;{4 will mean 124

• If two arrows came on top of each other, the new arrow should overwrite the old one

An example of this:

 ╔═╗:═╗
‖ ‖  ‖
V ╚══╝


3 means 1 step to the left

 ╔═╗:═╗
‖ ‖  ‖
╚═>══╝

• Arrow head should be > for left to right direction
• Arrow head should be < for right to left direction
• Arrow head should be V for top to bottom direction
• Arrow head should be ^ for bottom to top direction

Do not forget the joint if you turn.

:╗
‖
V

:
<═╝

^
‖
╚:

╔═>
:


I hope I did not miss anything.
If you have any questions or if I missed anything, I will be editing this post.

• Any other numbers or letters will be ignored This is rather annoying. There's enough challenge in the question itself without also having to add filtering the input string – Jo King Jun 5 at 23:43
• Why does the second 2 in your first example make two "steps" forward after turning instead of just one? – Value Ink Jun 6 at 3:26
• @ValueInk mistake, got fixed – asmgx Jun 6 at 3:53
• Some examples use ═ while others use =. Which one should we use? – Grimy Jun 6 at 11:31
• In addition to @Grimy's question, wouldn't using ║ (unicode value 9553) instead of ‖ (unicode value 8214) make more sense? The unicode values of the corners are [9559,9565,9562,9556], so the ═ (unicode value 9552) and ║ (unicode value 9553) would align a lot better. See the current output in my 05AB1E answer in comparison to the previous 120 bytes version. – Kevin Cruijssen Jun 6 at 12:13

# Ruby, 302306322 327 bytes

• +4 bytes to fix the edge case with the $$\-i\$$ direction (its angle is negative so we need to mod 4)
• +16 bytes for even more edge case fixes in the stepping algorithm...
• +5 bytes to fix the edge case where no inputs from 1-4 are present.
P=Math::PI/2
b=0i;f=d=p
c={b=>?:}
gsub(/[1-4]/){x=$&.to_i;d||=1 c[b+=d]="╗╝╚╔╗"[d.arg/P%4+x%2]if x[1]>0 d*=[0,1,1i,-1i,-1][x] c[b+=d]="═║"[d.imag.abs]if x<4||!f f=1} c[b+=d]=">V<^"[d.arg/P]if d q=c.keys.map &:rect q=q.pop.zip *q i,j=q[0].minmax k,l=q[1].minmax puts (k..l).map{|y|(i..j).map{|x|c[x+y*1i]||' '}*''}  Try it online! ### Explanation We initiate the grid as a hash table where the keys are complex numbers (real is the X-axis, imaginary is the Y-axis, lower numbers are closer to the top-left corner). This is convenient because we can initialize the direction variable as $$\1\$$, multiply by $$\i\$$ to turn right, and multiply by $$\-i\$$ to turn left. Also, we can quickly determine which way we're facing by dividing the direction's angle by $$\\pi/2\$$ and use that in our lookup tables. Our algorithm, then, is roughly as follows: 1. Get the next number from the input in the range 1-4. 2. If the number is 2-3, step once and add the correct corner piece. 3. Look up the corresponding direction change and multiply. 4. Step once and add the correct straight piece. (Don't need to step if we turn around.) 5. Repeat until done. 6. Step and add the arrow piece. 7. Print the grid. Code explanation (out of date, will fix later) P=Math::PI/2 # Save PI/2 b=0i;d=1 # Set initial coordinates and direction c={b=>?:} # Create grid with starting : gsub(/[1-4]/){x=$&.to_i                 # For each number 1-4
c[b+=d]="╗╝╚╔╗"[d.arg/P+x%2]if x[1]>0   # If 2-3 (second bit is a 1), step and write the corner piece
# If turning left (3), +1 to the index
d*=[0,1,1i,-1i,-1][x]                   # Multiply direction to turn accordingly
c[b+=d]="═‖"[d.imag.abs]                # Step and write the straight piece
}                                       # (end the loop)
c[b]=">V<^"[d.arg/P]                    # Write the corresponding arrow piece
q=c.keys.map &:rect                     # Get the filled-in grid spaces as X,Y coordinates
i,*_,j=q.map(&:first).sort              # Find the min and max X coordinate
k,*_,l=q.map(&:last).sort               # Find the min and max Y coordinate
puts (k..l).map{|y|                     # For each Y coordinate in range
(i..j).map{|x|                    # For each X coordinate in range
c[x+y*1i]||' '      # Get the character, or space if not present
}*''                    # Join characters on that Y coordinate and print
}

• I have to say wow.. you did amazing job, but need to fix this case 11113121 – asmgx Jun 6 at 6:07
• @asmgx fixed... – Value Ink Jun 6 at 17:32
• The 0 case is wrong, it should output :, not :>. – Grimy Jun 6 at 20:24
• @Grimy ok, done. – Value Ink Jun 6 at 20:37
• You can save a handful of bytes by changing the two minmax lines to (i,j),(k,l)=q.map &:minmax – Jordan Jul 2 at 19:52

# 05AB1E, 129126120 118 bytes

Žb_3Ý3*+ΣŽBÙNè}U4LÃ23SD1«‡©D4Å?Vε¾ˆ3%iŽb[D>‚¾èy≠i¼¼}ëy<iX¾è¼ëXÀ¾è.¼]¾ˆç':š®õQië">V<^"¾èªDgÅ2¯¥2Q1Ý«-ćY+šsŽ9¦¯èYi¦6š}Λ


Sigh.. what a mess. Almost don't want to post it, but took too much time to not post it now. The challenge has quite a bit of edge cases I wasn't expecting when I started with it.. Can definitely be golfed (by a lot), though.

-3 bytes thanks to @Grimy.
-2 bytes by using ║ (unicode value 9553) instead of ‖ (unicode value 8214). If this is not allowed, 2 bytes has to be added again.

Try it online. (No test suite for all test cases at once, because there is no way to reset the Canvas, so outputs would overlap..)

Explanation:

Žb_              # Push the compressed integer 9556
3Ý            # Push the list [0,1,2,3]
3*          # Multiplied by 3: [0,3,6,9]
+         # Added to the integer: [9556,9559,9562,9565]
Σ     }  # Sort it:
ŽBÙNè   #  Based on the order in the compressed integer 3021
# (so it's now in the order [9559,9565,9562,9556] ("╗╝╚╔"))
U # Then pop and store it in variable X
4L               # Push a list [1,2,3,4]
Ã              # And only keep those digits from the (implicit) input-string
23S           # Push [2,3]
D1«        # Duplicate it, and append a 1 to each: [21,31]
‡       # Replace all "2" with "21" and all "3" with "31"
©                # Store the string in variable r (without popping) to use later on
D4Å?             # Check if it starts with a 4 (without popping by duplicating first)
V            # Pop and store it in variable Y to use later on
ε                # Map over each digit:
¾ˆ              #  Add counter c to the global array
#  (counter c is 0 by default)
3%i             #  If the current digit is a 1 or 4:
Žb[          #   Push compressed integer 9552
D>‚       #   Pair it with it's increment: [9552,9553] ("═║")
¾è     #   And index the counter c into it
y≠i  }       #   If the current digit is NOT 1 (so it's a 4):
¼¼        #    Increase counter c twice to reverse the direction
ëy<i            #  Else-if the current digit is a 2:
X¾è         #   Index the counter c into the list of variable X
¼           #   And increase the counter c by 1
ë               #  Else (the current digit is a 3):
X              #   Push the list of variable X
À             #   Rotated it once toward the left: [9565,9562,9556,9559] ("╝╚╔╗")
¾è           #   Index the counter c into it again
.¼             #   And decrease counter c by 1
]                # Close all if-else statements and the map
¾ˆ              # And also add the current counter c to the global array after the map
ç             # Now convert all integers to ASCII characters with these unicode values
':š         '# Prepend a ":" to this list
®õQi             # If the input we saved in variable r was empty:
#  Push (and implicitly output) this single ":" as result
ë                # Else:
">V<^"¾è        #  Index the counter c in the string ">V<^"
ª       #  And append it to the list
Dg              #  Get the length of the list (without popping by duplicating first)
Å2            #  Create a list with that many 2s
¯¥          #  Push the deltas/forward differences of the global array
2Q        #  Check if a delta is equal to 2 (which means we reversed direction)
#  (1 if truthy; 0 if falsey)
1Ý«     #  Append a trailing [0,1]
-    #  Subtract them from the list of 2s
Y              #  If the input started with a 4:
ć +š            #   Increase the very first integer by 1 (from 1 to a 2)
s               #  Swap this integer list for the lengths and string list on the stack
Ž9¦             #  Push compressed integer 2460
¯è           #  Index each value of the global array into it
Yi   }     #  If the input started with a 4:
¦6š      #   Replace the first integer with a 6
Λ               # Use the Canvas builtin (which is output immediately implicitly)


See this 05AB1E tip of mine (section How to compress large integers?) to understand why Žb_ is 9556; ŽBÙ is 3021; Žb[ is 9552; and Ž9¦ is 2460.

As for a brief explanation of the Canvas builtin Λ and its three arguments:

First argument: length(s): the sizes of the lines we want to draw. Since we have to keep in mind overlapping, we use size 2 for every character, except if we reverse the direction and we want to overlap or for the final character (one of >V<^), for which we'll use size 1 instead.
Second argument: string(s): the characters we want to display. Which are the characters in this case, with the prepended :, and if the input wasn't empty/0 the appended appended final character (one of >V<^).
Third argument: direction(s): the directions these character-lines of the given length should be drawn in. In general we have the directions [0,7] which map to these directions:

7   0   1
↖ ↑ ↗
6 ← X → 2
↙ ↓ ↘
5   4   3


Which is why we have the integer 2460 for the directions $$\[→,↓,←,↑]\$$ respectively.

See this 05AB1E tip of mine for a more detailed explanation about the Canvas builtin Λ.

• 0ª1ª => 1Ý«. Yić>š} => ćY+š. – Grimy Jun 6 at 10:49
• @Grimy Ah of course. I'm stupid for not using 1Ý.. Thought about using 01S«, but figured it wouldn't change the byte-count.. >.> I guess these are the easy golfs and you're now working on a ~75 bytes version yourself, haha? ;p – Kevin Cruijssen Jun 6 at 10:54
• Here's what I have so far. I know this fails when 4 is the first command; are you aware of other edge cases I have missed? – Grimy Jun 6 at 15:41
• Oh, thanks for the tip about the 0 edge case! Thankfully I can fix it with a single byte =D. – Grimy Jun 6 at 15:51
• @Grimy Haha, nice. That's even better than I thought. ;p Good luck fixing the leading 4 edge case. I'll make sure to upvote you when it's posted. ;) – Kevin Cruijssen Jun 6 at 15:54

# 05AB1E, 78 73 bytes

4LÃ3ÝÐ<T**‡D₁Í«S4Ê>ćVs.¥Ì8%•2ß1Í'£Jθ•14вsxs¦©;+èŽb[+ç':š"^>V<"®;θèª®₂YèšΛ


Try it online!

Explanation:

# The canvas built-in takes 3 arguments: lengths, strings to draw, and angles.
# First, we map the input to a list of angles, coded as multiples of 45°:
# Forward = 0, right = 2, U-turn = 4, left = 6.
# Conveniently, 4 already means U-turn in the input format.
# Since each turn is implicitly followed by a step in the new direction,
# we actually want to map 2 to [2, 0] and 3 to [6, 0].
4L                    # range 1..4
Ã                   # remove everything else from the input
3Ý                 # range 1..3
Ð                # triplicate
<  *            # multiply one copy by the other -1
T*             # multiply by 10
# stack is now [filtered input, [1, 2, 3], [0, 20, 60]]
‡           # transliterate: 1 => 0, 2 => 20, 3 => 60

# Now we compute the lengths. 05AB1E's canvas is a bit finnicky: to get the
# desired output, we need to use length 2 for each character, except right
# before U-turns and at the end, where we want length 1.
D                     # copy the list of angles
₁Í«                  # append 254
S4Ê               # != 4 over each digit
>              # increment each
ćV            # remove the first element, save it in Y
s           # swap so the list of angles is at the top again

# Cconvert relative angls to absolute angles.
# 05AB1E's 0 is up, but the default direction is right, so we start at 2.
.¥                    # undelta (eg [6, 0, 4] => [0, 6, 6, 10])
Ì                   # add 2 to each
8%                 # modulo 8

# Now, we find the character to print at each step using a lookup table.
# For each pair of directions, we compute the index = first / 2 + second * 2.
# This maps each pair to a unique integer in 0..15.
•2ß1Í'£Jθ•14в         # compressed list: [1,4,1,7,13,0,7,0,1,10,1,13,10,0,4,0]
s                     # swap
x                    # * 2 without popping
s                   # swap (yes we're doing that a lot...)
¦                  # remove the first element
©                 # save in variable r without popping
;                # / 2
+               # sum
è              # index into the lookup table
ç         # map codepoints to characters
':š                   # prepend a ":"
®;θ          # half of the last angle
"^>V<"   è         # nth character of "^>V<"
ª        # append

# If the first command is 4, the initial angle should be 6, otherwise 2.
®                    # push list of angles
₂Yè                 # Yth digit of 26 (we set Y earlier, remember)
š                # prepend

# Finally, call the canvas built-in:
Λ

• @asmgx How did you get this error? The code works just fine on TIO. – Grimy Jun 7 at 4:47