# Render an ASCII maze

look! It's an ASCII maze! Soo coolzors, amazeballs and stuff.

+-+-----+---+
| |     |   |
| |  ++   | |
| |  ++ +-+ |
|       |   |
+-------+ | |
|         | |
+---------+-+


But, but, but... it's a pain to work out which direction all the parts of the maze are going. I just want to draw the layout and the maze make itself sooper kul without loads of time.

What if I could just draw this in...

#############
# #     #   #
# #  ##   # #
# #  ## ### #
#       #   #
######### # #
#         # #
#############


That would be soo sweet!

The rules (Because rules is cools):

• Write code to convert a string into an ascii maze and output the result.
• Any non-whitespace character will be read as a wall.
• Each char of wall will decide which character to be based on it's neighbours (only in North, South, East and West directions).
• If a char has no non-whitespace neighbours, it will be a plus sign (+).
• If a char has neighbours in both vertical (North-South) and horizontal (East-West) directions, it will be a plus sign (+).
• If a char has neighbours only in a vertical (North-South) direction, it will be a pipe symbol (|).
• If a char has neighbours only in a horizontal (East-West) direction, it will be a minus sign (-).
• The Input can be a single string (with lines separated by newline characters, or an array of strings).
• All input characters will be printable ASCII characters, you don't need to deal with extended charsets.
• Use any old language you please.
• If there is white space before a line, it should be the same amount on each line. Any white space after each line of output is fine.
• Attempt to solve it with the smallest number of bytes.

# Test cases:

## 1: Frame

Input:

##########
#        #
#        #
#        #
##########


Output:

+--------+
|        |
|        |
|        |
+--------+


## 2: Classic maze

Input:

#################
#       #
# ##### # ##### #
#   # # #     # #
# # # # ##### # #
#   # #       # #
### # ####### # #
#   # #    #  # #
# ### # ## # ##
#     # ##    #
#################


Output:

--------+-------+
|       |
| --+-+ | ----+ |
|   | | |     | |
| + | | +---- | |
|   | |       | |
+-- | +----+- | |
|   | |    |  | |
| --+ | ++ | -+
|     | ++    |
+-----+-++----+--


## 3: Green eggs, man.

Input:

I do not like green eggs and ham.
I do not like them, sam I am.
Would you like them here or there?
I would not like them anywhere!


Output:

| ++ +++ ++++ +++++ +++- -++ ----
| ++ +++ ++++ +++++ +++ + +++
+-+++ +++ ++++ ++++ ++++ ++ +++---
| +++-+ +++ ++++ ++-+ +++++++++


## 4: Icicles

Input:

Word Icicle!
Word Icicle
Word  cicle
ord  cicle
ord   icle
ord   i le
or    i le
or    i l
or      l
or
r


Output:

++++ ++++++-
++++ ++++++
++++  +++++
+++  +++++
+++   ++++
+++   | ++
++    | ++
++    | |
++      |
++
|

• Shouldn't the third line of green eggs and ham end with ---? – LiefdeWen Apr 16 '18 at 12:53
• Results for mixed neighbours still unclear; not sure why icicles would have any -s at all or why classic maze doesn't have four +s on the bottom row. – Neil Apr 16 '18 at 13:06
• are we allowed to take the input as a square padded with spaces (i.e. matrix)? Is the output allowed to have extra whitespace around it? Also, do you really mean smallest number of characters, not bytes? – dzaima Apr 16 '18 at 13:39
• I think that 1) the classic maze should have a + in the middle of the 1st row 2) the ! of Icicles should be replaced with a -. Could you please double-check these ones? – Arnauld Apr 16 '18 at 13:44
• By whitespace, do you just mean just space? I don't want to have to support tabs and you probably don't want me to transform newlines either – Jo King Apr 16 '18 at 23:49

# APL (Dyalog Unicode), 57 35 bytesSBCS

–22 thanks to a novel solution by ngn.

Anonymous tacit function taking a character matrix as argument.

{⊃'+-|+'↓⍨2⊥5 4 2⊃¨⊂⍱∘⌽⍨' '≠,⍵}⌺3 3


Try it online!

{}⌺3 3 on each 3-by-3 neighbourhood, apply the following function:

,⍵ ravel (flatten)

' '≠ Boolean where non-space

⍱∘⌽⍨ that NOR it's reverse (incl. neither top NOR bottom, neither left NOR right)

5 4 2⊃¨⊂ pick 5th, 4th, and 2nd element from that entire list
i.e. empty self, no vertical, no horizontal

2⊥ evaluate in base-2 (binary)
i.e. ≥4:empty self; 3:no neighbours; 2:no horizontal neighbours; 1:no vertical; 0: has both

'+-|+'↓⍨ drop that many elements from this string
i.e. empty self:; alone:+; vertical neighbour(s) only:|+; horizontal:-|+; both:+-|+

⊃ pick the first element (pad with space if non are available)
i.e. empty self: ; alone:+; vertical neighbour(s) only:|; horizontal:-; both:+

# Old solution

Anonymous tacit function taking a character matrix as argument.

{' +-|+'⊃⍨1⍳⍨(' '=5⊃,⍵),(∧/,⊢)∨/2 2⍴1⌽' '≠(9⍴0 1)/,⍵}⌺3 3


Try it online!

{}⌺3 3 on each 3-by-3 neighbourhood, apply the following function:

,⍵ ravel (flatten)

()/ filter using the following mask:

9⍴0 1 cyclically reshape [0,1] to length 9 (selects N, W, E, S)

' '≠ Boolean where non-space

1⌽ rotate one step left; [W,E,S,N]

2 2⍴ reshape to 2-by-2 matrix; [[W,E],[S,N]]

∨/ row-wise OR reduction: [horizontal,vertical]

() apply the following tacit function:

⊢ the identity; [horizontal,vertical]

∧/, preceded by its AND reduction; [both,horizontal,vertical]

(), prepend the following:

,⍵ ravel (flatten) the neighbourhood

5⊃ pick the 5th element (itself)

' '= Boolean if space (i.e. empty)

Now we have [empty,both,horizontal,vertical]

1⍳⍨ index of leftmost 1 (gives 5 if no neighbours at all)

' +-|+'⊃⍨ use that to pick symbol

# JavaScript (ES6), 110 bytes

I/O format: array of strings.

a=>a.map((s,y)=>s.replace(/\S/g,(_,x)=>'+|-+'[[-1,p=0,1,2].map(c=>p|=(a[y+c%2]||0)[x+~-c%2]>' '?c&1||2:0)|p]))


Try it online!

Or 108 bytes by using a matrix of characters instead.

# Python 2, 181 168 bytes

thanks to Leaky Nun for -13 bytes

m=input()
f=lambda x,y:(['']+m+[''])[y+1][x:x+1]>' '
print[[(c<'!')*' 'or'+-|+'[f(x+1,y)|f(x-1,y)|2*f(x,y+1)|2*f(x,y-1)]for x,c in enumerate(r)]for y,r in enumerate(m)]


Try it online!

# MATLAB, 113110 101 bytes

function F(A)
B=A>32
c=[1 1 1]
f=@(c)conv2(B,c,'s')>1
h=f(c)
v=f(c')
char((13*h+92*v-94*(h&v)).*B+32)


Converts input to logical, applies convolution in horizontal and vertical and combines the outputs to make the corresponding chars.

3 bytes saved by @Adriaan for telling me that you can clog the output in PPCG :P

9 bytes saved thanks to numerous @flawr comments!

# J, 49 47 bytes

Thanks to FrownyFrog for -2 bytes!

' +|-+'{~~:&' '*1+h&.|:+2*h=:g&.|.*g=:' '=#{.}.


Try it online!

# Retina 0.8.2, 92 bytes

\S
0
(?<=(.)*)0(?=(?>.*\n(?<-1>.)*)0)|0(?=(.)*)(?<=0(?>(?<-2>.)*\n.*))
1
Td+|\b.\b
Td-+


Try it online! Requires rectangular input. Link includes test cases. Explanation:

\S
0


Change all non-spaces to 0s.

(?<=(.)*)0(?=(?>.*\n(?<-1>.)*)0)|0(?=(.)*)(?<=0(?>(?<-2>.)*\n.*))
1


Look for all 0s with another 0 immediately above or below in the same column and change them to a 1. The 1s are now the places with vertical neighbours, while the 0s have no vertical neighbours.

Td+|\b.\b


Look for all digits with no horizontal neighbours. The 0s have no vertical neighbours either, so they become +s, while the 1s have vertical neighbours, so they become |s.

Td-+


The remaining digits have horizontal neighbours. The 1s also have vertical neighbours, so they become +s, while the 0s only have horizontal neighbours, so they become -s.

# Python 3, 336 bytes

def g(s):
h,j,s=' +|-+','',s.splitlines()
s+=['']
for n in range(len(s)):
s[n]+=' '
for i in range(len(s[n])-1):
l,r,k=s[n][i-1],s[n][i+1],0
try:u=s[n-1][i]
except:u=' '
try:d=s[n+1][i]
except:d=' '
if not s[n][i]==' ':
k+=1
if not u==d==' ':k+=1
if not l==r==' ':k+=2
j+=h[k]
j+='\n'
print(j)


Try it online!

I had to use a lot of code to deal with edge case errors.

# C (gcc), 143 bytes

char**y,*z,h,v;f(char**x){for(y=x;*y;++y)for(z=*y;*z;++z)if(*z-32){h=z[1]-32|z[-1]-32;v=y[1][z-*y]-32|y[-1][z-*y]-32;*z=h?v?43:45:(v?'|':43);}}


Try it online!

The function f modifies an array of strings in-place. The area around the array must be padded with spaces (a bit constrained). Even though this doesn't exactly meet the requirements most solutions are using, it does conform to the rules if we say that we represent a newline with two spaces (and take array of strings ending in newlines).

### Ungolfed

f(char**x){
char **y;
for (y = x; *y; ++y) {
char *z;
for (z = *y; *z; ++z) {
if (*z != ' ') {
if (z[1] != ' ' || z[-1] != ' ') {
// Horizontal exists
if (y[1][z-*y] != ' ' || y[-1][z-*y] != ' ')
// Vertical exists
*z = '+';
else
*z = '-';
} else {
// Horizontal doesn't exist
if (y[1][z-*y] != ' ' || y[-1][z-*y] != ' ')
// Vertical exists
*z = '|';
else
*z = '+';
}
}
}
}
}


This was a fun challenge of pointer arithmetic. Using C-style pointer iteration it is easy to get the horizontal neighbors, but the vertical ones were tougher. Luckily the y pointer is still around (which points to the initial value of z) so I can deduce my index from it and use that to access the same element on a different row. It felt very wrong writing y[-1][z-*y] as it flies in the face of any reasonable style!