4-way intersection generator

26

1

Here is an ASCII-art of a 4-way intersection:

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

(Note how the horizontal roads are 3 rows tall, while the vertical roads are 5 columns wide. This is for aesthetic reasons, because of the rectangular font.)

Your challenge is to produce this ASCII art. However, as I'm sure you all know, not every intersection has a road travelling off in every single direction. This particular intersection goes NESW, but some intersections might go, for example, NW:

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

Or it might go SWE:

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

Or it may even go E, just a single direction (although you can hardly call this an intersection, but try to avoid being overly pedantic):

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

You need to write a program or function that can easily generate any of these combinations. More specifically, your challenge is to write a program or function that takes a string of directions, consisting of NESW, as input, and outputs or returns this ASCII art of an intersection with roads pointing in those directions. These directions may appear in any order, but the input will not contain any characters except for N, E, S, or W. If you like, you may request inputs to be lowercase instead, but you must specify this in your answer. You may also assume that all inputs will contain at least one direction.

The last example had leading spaces on each line, because there is no road going west. If you do not have a road going west, these leading spaces are optional. This:

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

Would also be an acceptable output. Similarly, if N or S is gone, empty lines in there place are optional. One trailing newline is allowed, and trailing spaces are allowed as long as the output is visually the same.

You may take input and output in any reasonable format, such as STDIN/STDOUT, command line args, files, function arguments/return values, etc.

As usual, this is , so try to get the shortest possible answer in whatever language you happen to use!

Sample IO:

NESW:

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


NS:

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

S:

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

EW:

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

SE:
+-----+-----
|     |     
|     |- - -
|     |     
+-----+-----
|  |  |
|     |
|  |  |
|     |
|  |  |

James

Posted 2016-09-06T14:51:07.743

Reputation: 54 537

Are trailing spaces also allowed (if there's no E, for instance)? Are leading and trailing blank lines allowed if there's no N or S? – Greg Martin – 2016-09-06T17:42:25.380

@GregMartin Yes, those are allowed. See my edit. – James – 2016-09-06T17:46:17.673

vaguely related, you reminded me of this code I mostly wrote, for road intersections in a roguelike game: https://github.com/CleverRaven/Cataclysm-DDA/blob/master/src/mapgen_functions.cpp#L1080-L1347

– Sparr – 2016-09-06T22:58:13.257

Answers

10

Javascript (ES6), 190 187 185 bytes

This is an attempt to build this ASCII art character per character by iterating on a 17x15 matrix. Therefore, the output is always made of 15 rows of 17 columns with the intersection of the roads centered in the middle.

p=>eval("for(y=15,s='';y--;s+=`\n`)for(x=17;x--;)s+=' |-+'[+[a=y>4,b=y<10,c=x>4,d=x<12].every((c,i)=>c|p.search('SNEW'[i])+1)&&!((z=x-8||y&1|a&b)&&z*z-9)+2*!((z=y-7||x&1|c&d)&&z*z-4)]")

Ungolfed and commented

for(y = 15, s = ''; y--; s += `\n`)   // iterate on y, from 14 to 0 / append line feeds
  for(x = 17; x--;)                   // iterate on x, from 16 to 0
    s += ' |-+' [                     // append next character to string
      +[ a = y > 4,                   // a = outside South area?
         b = y < 10,                  // b = outside North area?
         c = x > 4,                   // c = outside East area?
         d = x < 12 ]                 // d = outside West area?
      .every((c, i) =>                // for each area, see if either:
        c |                           //   - we're currently outside it
        p.search('SNEW' [i]) + 1      //   - or it's an allowed area (p = function param.)
      )                               // if all tests pass, add a:
      &&                              //   - vertical bar (encoded as 1) if:
      !((z = x - 8 || y & 1 | a & b)  //     - x=8, y is even and we're not in the middle
      && z * z - 9)                   //     - OR x=5 OR x=11 (<=> (x-8)*(x-8) = 9)
      + 2 *                           //   - horizontal bar (encoded as 2) if:
      !((z = y - 7 || x & 1 | c & d)  //     - y=7, x is even and we're not in the middle
      && z * z - 4)                   //     - OR y=5 OR y=9 (<=> (y-7)*(y-7) = 4)
    ]                                 // (vertical + horizontal = 3, which leads to '+')

Matrix

Below is the matrix with the coordinates used in the code.

matrix

Demo

The following snippet allows to try any road configuration.

let f =
p=>eval("for(y=15,s='';y--;s+=`\n`)for(x=17;x--;)s+=' |-+'[+[a=y>4,b=y<10,c=x>4,d=x<12].every((c,i)=>c|p.search('SNEW'[i])+1)&&!((z=x-8||y&1|a&b)&&z*z-9)+2*!((z=y-7||x&1|c&d)&&z*z-4)]")

function update() {
  document.getElementById("o").innerHTML = f(document.getElementById("s").value);
}
update();
<input id="s" size=4 value="NSEW" oninput="update()">
<pre id="o" style="font-size:9px"></pre>

Arnauld

Posted 2016-09-06T14:51:07.743

Reputation: 111 334

8

PowerShell v3+, 226 204 192 191 bytes

param([char[]]$a)($n=0..4|%{($x=' '*5*($b=87-in$a))+('|  |  |',($w='|     |'))[$_%2]})*(78-in$a)
($z=($y='-'*5)*$b+"+$y+"+$y*($c=69-in$a))
$x+$w
'- - -'*$b+$w+'- - -'*$c
$x+$w
$z
$n*(83-in$a)

Takes input as a string of capital letters, explicitly casts it as a char array. Constructs the "North" segment via looping from 0 to 4. Each loop, constructs a string of 5 spaces (if W/87 is present in the input), stores that in $x, then either | | (stored in $w) or | | |, depending upon whether we're currently even or odd. That array of strings is stored into $n, and multiplied by whether N/78 is -in the input. That will determine if $n is placed on the pipeline or not.

Then, we construct the middle portion. The first line, $z is the "top" of the east-west route, using the same logic for W and E/69, and surrounded in parens to also place a copy on the pipeline. We use helper variable $y to save a byte on the ----- sections.

The next line is just the appropriate number of spaces (i.e., $x) string-concatenated with the correct-width pipes (i.e., $w). Then, the middle striped line, again with W and E logic and $w filling in the middle. Then $x+$w and $z again.

Finally, since the South road is the same as the north, put $n on the pipeline if S/83 is -in $a.

All of those resultant strings are gathered from the pipeline and output is implicit at the end of program execution. Abuses the default Write-Output delimiter to insert a newline between elements.


Examples

PS C:\Tools\Scripts\golfing> .\4-way-intersection.ps1 'EN'
|  |  |
|     |
|  |  |
|     |
|  |  |
+-----+-----
|     |
|     |- - -
|     |
+-----+-----

PS C:\Tools\Scripts\golfing> .\4-way-intersection.ps1 'SNW'
     |  |  |
     |     |
     |  |  |
     |     |
     |  |  |
-----+-----+
     |     |
- - -|     |
     |     |
-----+-----+
     |  |  |
     |     |
     |  |  |
     |     |
     |  |  |

PS C:\Tools\Scripts\golfing> .\4-way-intersection.ps1 'WE'
-----+-----+-----
     |     |
- - -|     |- - -
     |     |
-----+-----+-----

AdmBorkBork

Posted 2016-09-06T14:51:07.743

Reputation: 41 581

4

C++ 317 280 276 bytes

int i(char*j){for(int y=0;y<15;++y)for(int x=0;x<18;++x)putchar(x-17?y<5&!strchr(j,'N')|y>9&!strchr(j,'S')|x<5&!strchr(j,'W')|x>11&!strchr(j,'E')?' ' :x==5|x==11?y==5|y==9?'+':'|':y==5|y==9?x==5|x==11?'+':'-':x==8&y%2|y==7&x%2?' ':x==8&(y/5-1)?'|':y==7&(x/6-1)?'-':' ':'\n');}

Ungolfed:

int i (char* j)
{
  for (int y=0; y<15; ++y)
    for (int x=0; x<18; ++x)
      putchar(
        x-17 ? 
        y<5 & !strchr(j,'N') |
        y>9 & !strchr(j,'S') |
        x<5 & !strchr(j,'W') |
        x>11 & !strchr(j,'E') ? ' ' :
        x==5 | x==11 ? y==5 | y==9 ? '+' : '|' : 
        y==5 | y==9 ? x==5 | x==11 ? '+' : '-' : 
        x==8 & y%2 | y==7 & x%2 ? ' ' : 
        x==8 & (y / 5 - 1) ? '|' :
        y==7 & (x / 6 - 1) ? '-' :
        ' ' : '\n');
}

David Schwartz

Posted 2016-09-06T14:51:07.743

Reputation: 141

1Holy nested ternary operators, Batman! – None – 2016-09-07T00:37:39.933

We always knew they'd be good for something. – David Schwartz – 2016-09-07T04:26:57.353

Replacing strchr with index will shave off few more. Define x and y together outside for loops. – Wojciech Migda – 2017-03-11T18:13:48.820

2

Batch, 351 344 341 bytes

@echo off
set/pi=
set t=     
if not "%i:n=%"=="%i%" call:l
set l=-----
set r=%l%
if "%i:w=%"=="%i%" set l=%t%
if "%i:e=%"=="%i%" set r= 
for %%s in (%l%+-----+%r% "%t%|%t%|" "%l:--=- %|%t%|%r:--=- %" "%t%|%t%|" %l%+-----+%r%) do echo %%~s
if "%i:s=%"=="%i%" exit/b
:l
call :m
call :n
:n
echo %t%^|%t%^|
:m
echo %t%^|  ^|  ^|

Note: The line set t= ends in five spaces, and the line if "%i:e=%"=="%i%" set r= ends in a space. Takes case-insensitive input from STDIN. Edit: Saved 7 bytes by eliminating the d variable. Saved 3 bytes by using a for loop to print the middle section. If I'm allowed separate command-line parameters instead, then for 326 319 316 bytes:

@echo off
set t=%*
set/an=s=e=w=5,%t: ==%=0
set t=     
call:%n%
set r=-----%t%
call set l=%%r:~%w%,5%%
call set r=%%r:~%e%%%
for %%s in (%l%+-----+%r% "%t%|%t%|" "%l:--=- %|%t%|%r:--=- %" "%t%|%t%|" %l%+-----+%r%) do echo %%~s
goto %s%
:0
call :1
call :2
:2
echo %t%^|%t%^|
:1
echo %t%^|  ^|  ^|
:5

Neil

Posted 2016-09-06T14:51:07.743

Reputation: 95 035

2

Python 3, 186 bytes

S=' -- -  -- -  --'
lambda d:'\n'.join(S[r//4:15*('W'in d):3]+'||+  -  -| -  -  -||+'[r%4::3]+S[r//4:15*('E'in d):3]for r in[0,1,0,1,0,6,1,9,1,6,0,1,0,1,0][5-5*('N'in d):10+5*('S'in d)])

An anonymous lambda called with a string of directions, e.g. 'NWS'

Explanation to follow

RootTwo

Posted 2016-09-06T14:51:07.743

Reputation: 1 749

2

sed 234

s,$,@+-----+@|     |@!     !@|     |@+-----+@,
:l;tl
/N/s,^,#,;t
:r
/S/s,@$,#,;t
/E/{s,!@,|- - -@,;s,+@,+-----@,g}
/W/{s,@!,@- - -|,;s,@+,@-----+,g;s,@|,@     |,g}
y,@!NSEW,\n|    ,
q
:
s,#,@|  |  |@|     |@|  |  |@|     |@|  |  |,
tr

It just builds the different parts if the proper character is on the line.
Uses @ instead of \n and subs \n back in at the end.
The north and south parts are identical, so I use what's basically a function to insert them.

Riley

Posted 2016-09-06T14:51:07.743

Reputation: 11 345

1

Python 2, 290 bytes

t,s,r,i=[],[],range(5),raw_input()
for n in r:t+=[" "*5*("W"in i)+"|  "+("|"," ")[n%2]+"  |"]
exec"s+=['-'*5];s[:1]+=' '*5,;"*2;s[:2]+="- - -",
if"N"in i:print'\n'.join(t)
print'\n'.join([s[n]*("W"in i)+("|     |","+-----+")[`n`in"04"]+s[n]*("E"in i)for n in r])
if"S"in i:print'\n'.join(t)

Daniel

Posted 2016-09-06T14:51:07.743

Reputation: 6 425

m,t,s=[],[],[] could be m=t=s=[]. – Yytsi – 2016-09-07T06:13:22.430

range(5) could be saved into a variable and used twice, instead of typing range(5) twice. – Yytsi – 2016-09-07T06:15:51.883

What is m for? – Oliver Ni – 2016-09-07T14:18:10.983

@TuukkaX, for some reason having t=s=[] messes everything up – Daniel – 2016-09-07T14:37:07.410

@OliverNi, oh nothing I forgot to remove it :p – Daniel – 2016-09-07T14:37:41.920

1I'm now certain that by doing m=t=s=[], they all point to the same reference. – Yytsi – 2016-09-08T03:54:57.797

Wow, thats useful reference information. No pun intended. – Magic Octopus Urn – 2016-09-12T23:16:33.910

1

GolfScript, 154 bytes

{a?1+}:x;'-'5*:e;' '5*:b;"+"e+"+"+:f;{b'|'b'|'b n}:k;{'W'x{e}{b}if\'E'x{e}{}if n}:y;{x{b"|  |  |
"+:c k c k c}{}if}:z;1/:a;'N'z f y k'|'b+'|'+ y k f y'S'z

Try it online!

FedeWar

Posted 2016-09-06T14:51:07.743

Reputation: 271

Impressive, no idea how this has no votes. – Magic Octopus Urn – 2016-09-12T23:14:31.950

1

Pyth (385 380 373 353 bytes)

Golfed:

K"     |  |  |\n     |     |\n"?}\Nz++KKPKk?}\Wz?}\Ez+++*5\-*2+\+*5\-"\n     |     |\n- - -|     |- - -\n     |     |\n"+*5\-*2+\+*5\-++*2+*5\-\+"\n     |     |\n- - -|     |\n     |     |\n"*2+*5\-\+?}\Ez+"     "+*2+\+*5\-"\n     |     |\n     |     |- - -\n     |     |\n     +-----+-----"++"     +-----+\n"*3"     |     |\n""     +-----+"?}\Sz++KKPKk

Ungolfed:

K"     |  |  |\n     |     |\n"  //sets K to first two lines of north
?}\Nz                            //if north in the input 
  ++KKPK                         //then: return K + K + K[:-1]
  k                              //else: return ""
?}\Wz                            //if West in input
  ?}\Ez                          //if East in input
    +++*5\-*2+\+*5\-"\n     |     |\n- - -|     |- - -\n     |     |\n"+*5\-*2+\+*5\-    //then: Return E+W string
    ++*2+*5\-\+"\n     |     |\n- - -|     |\n     |     |\n"*2+*5\-\+         //else: Return W string
  ?}\Ez                          //else: if east in input (and not W)
    +"     "+*2+\+*5\-"\n     |     |\n     |     |- - -\n     |     |\n     +-----+-----" //return East without West String
    ++"     +-----+\n"*3"     |     |\n""     +-----+" \\Return empty left and right intersection
?}\Sz                            //if south in input
  ++KKPK                         //return north string
  k                              //return ""

Of course, if there are any improvements please tell me.

Saved 5 bytes thanks to Maltysen

You can try it here

Nick the coder

Posted 2016-09-06T14:51:07.743

Reputation: 96

you can use K instead of N and then when assigning for the first time, you don't have to use an =, saving you a byte – Maltysen – 2016-09-12T01:15:33.690

also, N[:-1] is P – Maltysen – 2016-09-12T01:17:13.387

0

Groovy (274 Bytes)

Ungolfed

r{
    l->
    t='+-----+'
    s='     ';
    m='|     |'
    x='-----'
    v=(1..5).collect{s}
    nsR=(1..5).collect{[s,((it%2)?'|  |  |':m),s]}
    ewR=[x,s,'- - -',s,x]
    c=[l[3]?ewR:v,[t,m,m,m,t],l[1]?ewR:v]
    (l[0]?nsR.collect{it}:[])+((0..4).collect{x->((0..2).collect{y->c[y][x]})}​)​+​(l[2]?nsR.collect{it}:[])
}

Golfed

def i(l) {t='+-----+';s='     ';m='|     |';x='-----';v=(1..5).collect{s};n=(1..5).collect{[s,((it%2)?'|  |  |':m),s]};e=[x,s,'- - -',s,x];c=[l[3]?e:v,[t,m,m,m,t],l[1]?e:v];(l[0]?n.collect{it}:[])+((0..4).collect{x->((0..2).collect{y->c[y][x]})}​)​+​(l[2]?n.collect{it}:[])}

Try it: https://groovyconsole.appspot.com/script/5082600544665600

Magic Octopus Urn

Posted 2016-09-06T14:51:07.743

Reputation: 19 422