In the United States, the two opposing directions of traffic on a road are separated by a dashed yellow line if passing is allowed and two solid yellow lines if passing is not allowed.
road line rules graphic
(Just one side can be dashed to allow passing on that side, and yellow lines can mean other things like center or reversible lanes, but we aren't concerned with any of those cases.)
Write a program that takes in a run-length encoded string of P for passing and N for no passing, and prints an ASCII version of the corresponding road. Except for the center line, the road always has the same pattern, which can be easily inferred from the examples below.
There will be a positive decimal number before each P and N in the input string. This number defines the length of the passing or no passing region of the current part of the road.
Examples
An input of 12N would produce 12 columns of no passing road (center line all =):
____________
============
____________
An input of 12P would produce 12 columns of passing road (center line - repeating):
____________
- - - - - -
____________
Passing and no passing can then be combined, e.g. 4N4P9N7P1N1P2N2P would produce:
______________________________
====- - =========- - - -=-==-
______________________________
These are 4 no passing columns, then 4 passing, then 9 no passing, etc.
Note that a passing zone always starts with a dash (-) on the leftmost side, not a space (). This is required.
Details
- The input will never have two
Nzones or twoPzones in a row. e.g.4P5Pwill never occur. - You don't need to support letters without a leading positive number. Plain
Pwill always be1P, plainNwill always be1N. - There may be trailing spaces as long as they do not extend beyond the final column of the road. There may be one optional trailing newline.
- Instead of a program, you may write a function that takes in the run-length encoded string and prints or returns the ASCII road.
- Takes input in any standard way (stdin, command line, function arg).
The shortest code in bytes wins. Tiebreaker is earlier post.
-
\$\begingroup\$ Does the road have to be asymmetrical, or is it allowed to print 4 spaces of road on each side of the line? \$\endgroup\$orlp– orlp2015年04月27日 13:09:45 +00:00Commented Apr 27, 2015 at 13:09
-
\$\begingroup\$ @orlp If you're asking if the road can be wider than 5 rows, then no. If you're asking if space characters can be put in the empty lines above or below the center line, then yes as long as they hold with detail bullet 3. \$\endgroup\$Calvin's Hobbies– Calvin's Hobbies2015年04月27日 14:36:10 +00:00Commented Apr 27, 2015 at 14:36
-
\$\begingroup\$ Let me ask by example, is either of these a valid output? gist.github.com/orlp/0e0eae16d6e1fcda5e9b \$\endgroup\$orlp– orlp2015年04月27日 14:43:40 +00:00Commented Apr 27, 2015 at 14:43
-
\$\begingroup\$ @orlp Neither is. \$\endgroup\$Calvin's Hobbies– Calvin's Hobbies2015年04月27日 14:47:38 +00:00Commented Apr 27, 2015 at 14:47
26 Answers 26
JavaScript (ES6), 114
Using template strings, the 5 linefeeds are significant and thus must be counted.
f=s=>(b=(s=s.replace(/(\d+)(.)/g,(x,n,b)=>(b<'P'?'=':'- ').repeat(n).slice(0,n))).replace(/./g,'_'))+`
${s}
`+b
rs, 252 chars
Although this might not count because I added the convergence operator as a ripoff of Martin Büttner's Retina an hour ago...I'm not really here to compete anyway. It's just fun making a regex-based solution for this.
(\d+\D)/#1円
+(\d*)#(?:(((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|0)(?=\d*\D)/1円1円1円1円1円1円1円1円1円1円2円3円4円5円6円7円8円9円10円#
\d(?=\d*#N)/=
(^|(?<=\D))\d(?=\d*#P)/-
+(?<=-)\d\d(?=\d*#P)/ -
(?<=-)\d(?=\d*#P)/
#\D/
((?:(=|-| ))+)/A1円\n\n\n1円\n\nA1円\n
+(A_*)(.)/1円_
A/
I got line 2 from Martin's Retina answer for Programming Languages Through the Years.
Explanation
(\d+\D)/#1円
+(\d*)#(?:(((((((((9)|8)|7)|6)|5)|4)|3)|2)|1)|0)(?=\d*\D)/1円1円1円1円1円1円1円1円1円1円2円3円4円5円6円7円8円9円10円#
This does lots of magic. See the answer I linked above for more info.
Basically, with the input 4N4P9N7P1N1P2N2P, this will be the result:
4444#N4444#P999999999#N7777777#P1#N1#P22#N22#P
Next:
\d(?=\d*#N)/=
This replaces the numbers preceding the no-passing symbol (N) with the equal signs. The result with the previous input:
====#N4444#P=========#N7777777#P=#N1#P==#N22#P
This:
(^|(?<=\D))\d(?=\d*#P)/-
replaces the first number preceding a passing symbol (P) with the first dash. The result:
====#N-444#P=========#N-777777#P=#N-#P==#N-2#P
The next two lines continue the same pattern:
+(?<=-)\d\d(?=\d*#P)/ -
(?<=-)\d(?=\d*#P)/
The first line replaces the rest of the line with the dash-space pattern. The second one handles an odd number; it replaces the last dash followed by a single integer (such as -5) with a dash-space (-). Now, the output is:
====#N- - #P=========#N- - - -#P=#N-#P==#N- #P
Now things are starting to fall into place. The next line:
#\D/
just removes the #N and #P.
((?:(=|-| ))+)/A1円\n\n\n1円\n\nA1円\n
+(A_*)(.)/1円_
set up the underscores on the top and bottom to give:
A______________________________
====- - =========- - - -=-==-
A______________________________
Lastly, we remove the A:
A/
K (ngn/k), 46 bytes
Created on the APL Farm with lots of input from chrispsn.
{++(,/(.x@y)#'"-="x_y#="PNP";"_")@3466円}`c$!58
k9 2021年03月27日, (削除) 53 (削除ここまで) 52 bytes
-1 byte thanks to chrispsn!
++"_ ",|"_ ",,,/{.[x]#*"-="y#="PNP"}/'-2^(~=':64>)^
Try it online on kparc.io!
-
\$\begingroup\$ Nice! Possible -1 byte:
(="PNP")y=>y#="PNP"\$\endgroup\$chrispsn– chrispsn2023年04月12日 23:25:28 +00:00Commented Apr 12, 2023 at 23:25
CJam, 38 bytes
"_ - _":N3'=t:P;q~]2/e~z'
*"--"/"- "*
How it works
We first assign the correct road column to variables N and P and then simply evaluate the input string. This leaves a pair of the length and the column on stack. We group them up, run an RLD on it to get the full columns, transpose to join them and then finally, convert the continuous -- to - .
:_ - _":N e# This is the no passing column. We assign it to N
3'=t:P e# Replace the '-' in N with '=" and assign it to P
q~]2/ e# Read the input, evaluate it and then group it in pairs
e~ e# Run a run-length-decoder on the pairs
z'
* e# Transpose and join with new lines.
"--"/ e# Split on two continuous occurrence of -
"- "* e# Join by an alternate "- "
Python 2, 136 bytes
Surprisingly, importing re seems to be actually worthwhile here.
import re
s=""
for x,y in re.findall("(\d+)(.)",input()):s+=(("- ","==")[y=="N"]*int(x))[:int(x)]
t="_"*len(s);print t+"\n"*3+s+"\n"*2+t
k9 2021年03月27日, 72 bytes
" -=_"{++(3;0;0;mod[x]+2*~x;0;3)}@{y*x+y}\&?`P=!/`i`n$+-2^{9<a|-a:-':x}^
K (ngn/k), (削除) 71 (削除ここまで) (削除) 69 (削除ここまで) (削除) 68 (削除ここまで) (削除) 64 (削除ここまで) (削除) 69 (削除ここまで) (削除) 68 (削除ここまで) 65 bytes
{++"_ ",|"_ ",+" =-"@+/1(~<2円=)\-78+*'&.'!/|+0N 2#(&~=':58<x)_x}
-2 superfluous parens
-1 shuffling
-4 borrowing a parsing idea from ovs
+5 I actually prefer using "-" for the embankment, but what evs.
-1 woo hoo!
-4 bye bye beloved Bubbler train...
J ((削除) 69 (削除ここまで) (削除) 59 (削除ここまで) (削除) 55 (削除ここまで) 52 bytes)
-14 bytes thanks to Raul Miller and ovs on The APL Farm Discord.
-3 bytes by removing noun assigments
6$'_',4$'','',:'\d+.'(".@}:$'-= '#~'PNP'={:)rxapply]
Explanation
'\d.+'(...)rxapply]: For every match of pattern \d+, apply the function...
".@}:$'-= '#~'PNP'={:, a Fork/3-Train.
'-= '#~'PNP'={:: The right tine of the Fork.{:takes the last element ('N'or'P'), and checks it's equality against'PNP', then uses the resulting boolean mask to select from'-= '.'P'gets1 0 1so it selects'- ', and N gets0 1 0and selects'='.".@}:": The left tine of the Fork.}:drops the last element, keeping the digit(s) as a sting. The string is converted to a integer with"., the Execute operator.$: The Reshape operator reshapes the right arg by the left arg
The expression so far has produced the mid line, eg. ====- - =========- - - -=-==- , which I will refer to as m below.
,: Itemize m (ie. Puts it in an array, changing the shape from 30 to 1 30)
4$'','' Prepend 2 blank rows (arrays are rectangular, so the 2 chars get padded to the width of m) and then reshape by 4. Since there are 3 rows, reshape cycles to reuse the first row, adding another blank line.
6$'_', Prepends a _ char (which again gets padded to the width of m) then reshapes to 6. Again, since there's 5 rows, reshaping cycles back to the first item in the array (ie. the top line) which is appended to the array, producing the final result.
Python 3, (削除) 169 (削除ここまで) 168 bytes. (167 with Python 2)
p,s='',str.split
for _ in s('N '.join(s('P '.join(s(input(),'P')),'N'))):
v=int(_[:-1]);p+=['='*v,('- '*v)[:v]][_[-1]=='P']
l=len(p)
u='_'*l
print(u+'\n'*3+p+'\n\n'+u)
Fairly ungolfed:
p=''
for i in'N '.join('P '.join(input().split('P')).split('N')).split():
v=int(i[:-1]) # Get the number from the input section
if i[-1]=='N': # Check the letter (last char) from the input section
p+=('='*v) # Repeat `=` the number from input (v)
else:
p+=('- '*v)[:v] #Repeat `- ` v times, then take first v chars (half)
l=len(p) #Get the length of the final line markings
print('_'*l+'\n\n\n'+p+'\n\n'+'_'*l)
print('_'*l # Print _ repeated the length of p
+'\n\n\n' # 3 new lines
+p+ # print out p (the markings)
'\n\n' # 2 new lines
+'_'*l) # Print _ repeated the length of p
for i in
'N '.join(
'P '.join(
input().split('P'))
.split('N'))
.split():
# Split the input into items of list at P
# Join together with P and ' '
# Split at N...
# Join with N and ' '
# Split at space
# Loop through produced list
Try it online here.
-
\$\begingroup\$ You forgot to update your byte count. \$\endgroup\$mbomb007– mbomb0072015年04月27日 20:15:28 +00:00Commented Apr 27, 2015 at 20:15
-
\$\begingroup\$ @mbomb007 It didn't change the count :/ I can't get it below 169 atm \$\endgroup\$Tim– Tim2015年04月27日 20:16:19 +00:00Commented Apr 27, 2015 at 20:16
-
\$\begingroup\$ Putting
p+=['='*v,('- '*v)[:v]][_[-1]=='P']at the end of the previous line with a preceding semicolon saves one byte. \$\endgroup\$mbomb007– mbomb0072015年04月27日 20:18:05 +00:00Commented Apr 27, 2015 at 20:18 -
\$\begingroup\$ Also, using Python 2 instead saves 1 byte on the
print. \$\endgroup\$mbomb007– mbomb0072015年04月27日 20:25:09 +00:00Commented Apr 27, 2015 at 20:25 -
\$\begingroup\$ @mbomb007 added them in :) I have a feeling python 2 it may be even shorter... But I'm not sure. \$\endgroup\$Tim– Tim2015年04月27日 20:26:47 +00:00Commented Apr 27, 2015 at 20:26
05AB1E, (削除) 35 (削除ここまで) 34 bytes
.γa}2ôε`„PN...- =2ä‡s∍}J©¶ĆìĆ'_®∍DŠ»
Try it online or verify all test cases.
Explanation:
.γ # Consecutive group the (implicit) input by:
a # Check if the character is a letter
}2ô # After the group by: split it into parts of size 2
ε # Map each pair of integer + letter to:
` # Pop and push them separated to the stack
„PN # Push string "PN"
...- = # Push string "- ="
2ä # Split it into 2 parts: ["- ","="]
‡ # Transliterate the "P" to "- " and "N" to "="
s # Swap to take the integer value
∍ # Extend (or shorten) the string to that length
}J # After the map: join all parts together to a single string
© # And store it in variable `®` (without popping)
¶ # Push a newline character "\n"
Ć # Double it "\n\n"
ì # Prepend it in front of the string
Ć # Enclose the string, appending it's own first character
'_ '# Push string "_"
®∍ # Extend it to a size equal to the length of string `®`
D # Duplicate it
Š # Triple swap the three values on the stack from a,b,c to c,a,b
» # Join the values on the stack with newline delimiter
# (after which the result is output implicitly)
Haskell, 165 bytes
k 'N'="="
k _="- "
d c=c>'/'&&c<':'
p[]=[]
p s=take(read$takeWhile d s)(cycle$k a)++p r where(a:r)=dropWhile d s
f s=unlines[q,"\n",p s,"",q]where q=map(\x->'_')$p s
Example run (f returns a string, so for better display print it):
*Main> putStr $ f "4N4P9N7P1N1P2N2P"
______________________________
====- - =========- - - -=-==-
______________________________
How it works: p returns the middle line by recursively parsing the input string and concatenating the given number of symbols found by the lookup function k. The main function f joins a five element list with newlines, consisting of the top line (every char of the middle line replaced by _), a newline, the middle line, an empty line and the bottom line (same as top).
PHP, 187 bytes
preg_match_all('/(\d+)(\w)/',$argv[1],$m,2);
$o='';
foreach($m as $p)
$o.=str_replace('--','- ',str_repeat($p[2]<'P'?'=':'-',$p[1]));
$a=preg_replace('/./','_',$o);
echo("$a\n\n\n$o\n\n$a\n");
The code can stay on a single line; it is displayed here on multiple lines to be more readable (the whitespaces and newlines used for formatting were not counted).
Two bytes can be saved by not printing the trailing newline. Five more bytes can be saved by using real newline characters on the echo():
echo("$a
$o
$a");
Six additional bytes can be saved by omitting the initialization of $o ($o='';) but this will trigger a notice. The notice can be suppressed by running the script using the command line:
$ php -d error_reporting=0 <script_name> 4N4P9N7P1N1P2N2P
These brings it to 174 bytes.
Ruby, (削除) 137 (削除ここまで) 135 bytes
Not the shortest I could come up with, but close to the nicest. Partly borrowed from Optimizer's answer.
require'scanf'
N='_ = _'
P='_ - _'
a=[]
scanf('%d%c'){|l,t|a+=[eval(t).chars]*l}
puts (a.shift.zip(*a).map(&:join)*?\n).gsub'--','- '
Ungolfed:
require 'scanf'
N = '_ = _'
P = '_ - _'
columns = [] # array of columns
# scan stdin for a number followed by a single char
scanf('%d%c') do |length, type|
columns += [eval(type).chars] * length
done
# Convert to an array of rows, and join into a string
rows = columns.shift.zip(*columns).map(&:join)
str = rows * "\n" # join lines
# Replace '--' by '- ' and print
puts str.gsub(/--/, '- ')
-
\$\begingroup\$ You should be able to improve this by 2 bytes (and beat the python 2 answer) by changing the last line to
(a.shift.zip(*a).map(&:join)*?\n).gsub'--','- '. \$\endgroup\$blutorange– blutorange2015年05月02日 22:26:20 +00:00Commented May 2, 2015 at 22:26
Vyxal L, 180 bitsv1 , 22.5 bytes
(aḊyC1⁄2`- =`1⁄2$İ$⌊Ẏ∑ƛ4↳Ǔ\_pǏ
Ḋ # Group by...
(a # Is it an uppercase letter?
y # Uninterleave - split into [numbers, chars]
C1⁄2 # Charcodes / 2 - N -> 39, P -> 40
$İ # Index into...
`- =`1⁄2 # ["- ", "="]
Ẏ # Extend to length
$⌊ # numbers
∑ # Concatenate into a single string
ƛ # For each character
4↳ # Prepend three spaces
Ǔ # Move a space to the end
\_p # Prepend a _
Ǐ # Append the _
# L flag transposes and joins the whole thing
-
\$\begingroup\$ Since when did we start scoring in bits (presumably or the charcodes)? Does this mean I can claim my solution is 205 bits, or 25.625 bytes? \$\endgroup\$Shaggy– Shaggy2023年05月11日 00:00:16 +00:00Commented May 11, 2023 at 0:00
-
\$\begingroup\$ @Shaggy Vyxal can use a custom range coding encoding (see the link in the header) \$\endgroup\$emanresu A– emanresu A2023年05月11日 00:14:25 +00:00Commented May 11, 2023 at 0:14
-
\$\begingroup\$ @Shaggy since the start of may - that's when vyncode was added (a fractional byte encoding/compression system). \$\endgroup\$2023年05月11日 00:14:44 +00:00Commented May 11, 2023 at 0:14
Pip, (削除) 46 (削除ここまで) 40 bytes
-6 bytes thanks in part to emanresu A
a^:CXUYP'_X$+aPnP{bHa}MPaR'N'=R'P"- "n.y
Explanation
a^:CXU
a ; Command-line argument
^: ; Split by this separator and assign back to a:
XU ; Built-in regex `[A-Z]` (uppercase letters)
C ; Wrapped in capturing group
; Splitting by a regex wrapped in a capturing group has the effect of keeping
; the matches of the regex in the result list, so this gives a list of
; alternating numbers and letters (with a stray empty string at the end)
YP'_X$+a
a ; The new value of a, calculated above
$+ ; Fold on addition (sum, treating letters as 0)
'_X ; String of underscores of that length
YP ; Print, with trailing newline, and also yank into y variable
Pn ; Print newline, with trailing newline
P{bHa}MPaR'N'=R'P"- "
a ; In the list a,
R'N'= ; Replace "N" with "="
R'P"- " ; Replace "P" with "- "
MP ; Map this function to each pair of consecutive values in
; the list (either number & string or string & number):
{bHa} ; Take (a) characters from the start of (b)
; If (a) is a string, it is treated as 0
; If (a) is longer than the length of (b), (b) is repeated
; till it is long enough
; We end up with a list of strings that make up the correct
; center line, interspersed with a bunch of empty strings
P ; Print that list, joined together
n.y ; Print a newline concatenated with y (the underscore string from earlier)
-
1\$\begingroup\$ here's a 44 \$\endgroup\$emanresu A– emanresu A2024年03月29日 09:28:01 +00:00Commented Mar 29, 2024 at 9:28
-
\$\begingroup\$ @emanresuA Ooh, great idea with
MP! Combining it with a thought I had about cyclical indexing this morning, I got it down to 40. \$\endgroup\$DLosc– DLosc2024年03月29日 16:33:03 +00:00Commented Mar 29, 2024 at 16:33
Ruby, 94 bytes
Borrows the gsub'--','- ' idea from 14mRh4X0r's answer. I think that answer is more interesting, though, although this is shorter.
f=->x{n=?_*x.gsub!(/(\d+)(.)/){(2ドル==?P??-:?=)*1ドル.to_i}.size
"#{n}
#{x.gsub'--','- '}
#{n}"}
Testing:
f=->x{n=?_*x.gsub!(/(\d+)(.)/){(2ドル==?P??-:?=)*1ドル.to_i}.size
"#{n}
#{x.gsub'--','- '}
#{n}"}
puts f['4N4P9N7P1N1P2N2P']
Produces:
______________________________
====- - =========- - - -=-==-
______________________________
let me include my matlab version
MATLAB (267 b)
function d=p(V,a),j=numel(V)-1;if (a==0),d=0;return; end,d=(V(a)-48+10*p(V,a-1))*(V(a)<64);fprintf('%c%.*s%c%.*s',(a>=j)*10,(a==j|a==1)*eval(strcat(regexprep(V,'[NP]','+'),48)),ones(99)*'_',(a<3)*10,(V(a+1)>64)*d,repmat((V(a+1)==78)*'=='+(V(a+1)==80)*'- ',[1 99]));end
input
An ascii-formatted string tailed by a space (since there is no end of chain '0円' in matlab
example V='12N13P '
output
pattern representation of the road
_________________________
============- - - - - - -
_________________________
function
the function must be called from its tail-1 (the empty character is removed)
example : p(V,numel(V)-1)
Simulation
try it online here
R, 132 bytes
Not greatly happy with this, but it was a bit of fun to do:) Tried to get rid of the multiple gsubs, but my efforts were in vain. I suspect there's a much better way to do this.
cat(rbind(nchar(a<-scan(,'',t=gsub('PN','P N',gsub('NP','N P',chartr('- =','PPN',scan(,'',sep='|')[4]))))),substring(a,1,1)),sep='')
scangets the strings from STDIN and grabs the 4th one. Note that the empty lines require a space (or something) in them for scan to carry on getting the input."====- - =========- - - -=-==- "
- It replaces the
=s withNs, the-and withPs."NNNNPPPPNNNNNNNNNPPPPPPPNPNNPP"
- Then it inserts a space between each
NPandPN"NNNN PPPP NNNNNNNNN PPPPPPP N P NN PP"
- The scan splits the string on spaces
"NNNN" "PPPP" "NNNNNNNNN" "PPPPPPP" "N" "P" "NN" "PP"
- The string length is then bound(
rbind) with the first character of each string4 4 9 7 1 1 2 2
"N" "P" "N" "P" "N" "P" "N" "P" - The array is then output using
cat.
Test run
cat(rbind(nchar(a<-scan(,'',t=gsub('PN','P N',gsub('NP','N P',chartr('- =','PPN',scan(,'',sep='|')[4]))))),substring(a,1,1)),sep='')
1: ____________
2:
3:
4: ============
5:
6: ____________
7:
Read 6 items
Read 1 item
12N
>
> cat(rbind(nchar(a<-scan(,'',t=gsub('PN','P N',gsub('NP','N P',chartr('- =','PPN',scan(,'',sep='|')[4]))))),substring(a,1,1)),sep='')
1: ____________
2:
3:
4: - - - - - -
5:
6: ____________
7:
Read 6 items
Read 1 item
12P
> cat(rbind(nchar(a<-scan(,'',t=gsub('PN','P N',gsub('NP','N P',chartr('- =','PPN',scan(,'',sep='|')[4]))))),substring(a,1,1)),sep='')
1: ______________________________
2:
3:
4: ====- - =========- - - -=-==-
5:
6: ______________________________
7:
Read 6 items
Read 8 items
4N4P9N7P1N1P2N2P
C, (削除) 155 (削除ここまで) 153 bytes
−2 bytes thanks to ceilingcat
l=6;main(k,v,n,x,s,c)char*s,**v,c;{for(;l--;puts(s))for(s=v[1];*s;s+=k)for(x=sscanf(s,"%d%c%n",&n,&c,&k);n--;)putchar(" -=_"[l%5?l^2?0:c^78?++x&1:2:3]);}
More readable:
main(l,v,k,n,x,s,c)
char*s,**v,c;
{
for(l=6;l--;puts(s))
for(s=v[1];*s;s+=k)
for(x=sscanf(s,"%d%c%n",&n,&c,&k);n--;)
putchar(l%5?l^2?32:c^78?++x&1?45:32:61:95);
}
The outer loop counts lines from 5 to 0.
The middle loop iterates over parts of the encoded string:
4N4P9N7P1N1P2N2P
4P9N7P1N1P2N2P
9N7P1N1P2N2P
7P1N1P2N2P
1N1P2N2P
1P2N2P
2N2P
2P
string is empty - exit
The inner loop decodes a part, like, 7P, and iterates the needed number of times (e.g. 7).
Each iteration prints one char. The value of the char is described by the code " -=_"[l%5?l^2?0:c^78?++x&1:2:3]:
- If line number is 5 or 0, print
_ - Otherwise, if line number is not equal to 2, print a space
- Otherwise, if the symbol is 'N', print
= - Otherwise, increase
xby 1 (it was initialized to 2 bysscanf) - If odd, print
-, else print a space
Japt v2.0a0, (削除) 30 (削除ここまで) (削除) 29 (削除ここまで) (削除) 28 (削除ここまで) 29 bytes
Takes input in lowercase, prepend v<space> for +2 bytes if that's not allowed. Had to sacrifice a byte to fix a bug with inputs that contained a 0 :\
ò!Í®n îZèÍg"- ="òìyÈû4 Ôû6'_
ò!Í®n îZèÍg"- ="òìyÈû4 Ôû6'_ :Implicit input of string
ò!Í :Partition into the run length groups we need (See more detailed explanation below)
® :Map each Z
n : Convert to integer (the letter at the end is ignored)
î : Repeat and slice to that length
Zè : Count the occurrences in Z of
Í : "n" (see below for the why)
g : Index into
"- ="ò : Partitions of "- =" of length 2
à :End map
¬ :Join
y :Transpose
È :Pass each row through the following function and transpose back
û4 : Centre pad with spaces to length 4
Ô : Reverse ('cause centre padding is right-biased)
û6'_ : Centre pad with "_" to length 6
OK, I finally (think I) figured out how the partitioning is working! First the basics: The ò method partitions string between pairs of characters (X & Y) that return a truthy value when run through the method that's passed as an argument. We're using Í here, which is the shortcut for n2<space>. The space is used to close the ò method and the n and the 2 being split into two separate arguments, with the second being ignored as ò only expects one argument. That means that we're currently testing XnY but, by adding the !, the elements get flipped giving us YnX.
And now for the trickery: The possible combinations we can have (where L=[np] & D=[0-9]) are DnL, LnD & DnD and, in all cases, both elements are strings, which is important. The n attempts to convert Y to an integer, run X on it as a method and convert it back to a string, with the following possible outcomes:
Dnpsquares the integer resulting in a non-empty string, which is truthy, creating a partition.Dnnnegates the integer resulting in a non-empty string, which is truthy, creating a partition.DnD&LnD, for some reason that I can't figure out, both result in0, which is falsey, so no partition is created.
Hopefully, that all made some sort of sense but, if it helps, here's a handy table.
And, as a final note: the Í works exactly the same way as above when passed to the è method, which only expects a single string argument.
-
\$\begingroup\$ +1 for not understanding what your code is doing at all. \$\endgroup\$Razetime– Razetime2020年10月30日 12:56:38 +00:00Commented Oct 30, 2020 at 12:56
-
1\$\begingroup\$ Figured it out, @Razetime; see updated explanation. My confusion was coming from the
!causing thenmethod to behave differently when passed to theòmethod, barring just flipping the arguments. I eventually had to build a huge truth table of all the things that could possibly be happening to help me figure it out! \$\endgroup\$Shaggy– Shaggy2020年10月30日 16:45:59 +00:00Commented Oct 30, 2020 at 16:45
PowerShell, 158 bytes
$f='';($_|sls "\d*\w"-a|% m*).value|%{$n=($_|sls "\d+"-a|% m*).value;if($n-eq$null){$n=1};switch($_[-1]){N{$f+='='*$n}P{$f+=-join(1..$n|%{(' ','-')[$_%2]})}}}
Ungolfed
$args|%{
# empty string for adding road later
$finalString=''
# breaks every pair apart and selects the value (N4, P4, etc.)
($_|sls "\d*\w"-a|% m*).value|%{
# selects just the number
$num = ($_|sls "\d+"-a|% m*).value
# for those pairs that don't have a number associated
if($num -eq $null){$num = 1}
# switch depending on the char
switch($_[-1]){
# nothing to do with N so append to finalString var
N{
$finalString += '=' * $num
}
# for loop to determine the alternating of the road pattern
P{
$finalString += -join (1..$num | %{(' ','-')[$_%2]})
}
}
}
# formats string for desired output
"{0}`n`n`n{1}`n`n{0}" -f $("_"*$finalString.length),$finalString
}
Lua, (削除) 123 (削除ここまで) 122 bytes
p=print s=(...):gsub('(%d+)(.)',load'a,b=...return({N="=",P="- "})[b]:rep(a):sub(1,a)')r=('_'):rep(#s)p(r)p'\n'p(s)p()p(r)
Ungolfed Version:
p=print
s=(...):gsub('(%d+)(.)', --For each number/letter pair
function(a,b) --Number in a, letter in b
return({N="=",P="- "})[b]:rep(a):sub(1,a) --Replace each number/letter pair
--with respective pattern
end)
r=('_'):rep(#s) --Create edges of road
p(r)p'\n'p(s)p()p(r) --Print road
Retina 0.8.2, 46 bytes
\d+N
$*=
\d+P
$*-
--
-
.+
$.0$*_¶¶¶0ドル¶¶$.0$*_
Explanation
\d+N
$*=
Match digits followed by N; treating the digits as a number, replace the match with that many =.
\d+P
$*-
Same, but with P and -.
--
-
Replace any two consecutive dashes with dash-space.
.+
$.0$*_¶¶¶0ドル¶¶$.0$*_
Replace the whole string with:
- Get the length of the whole match (
$.0) and make a string of that many underscores ($*_) - Three newlines (
¶¶¶) - The original match (
0ドル) - Two more newlines (
¶¶) - The same underscores code again
Scala, 163 bytes
(s:String)=>{val r=(("\\d+(P|N)"r) findAllIn(s) map(r=>{val l=r.init.toInt;if(r.last=='N')"="*l else ("- "*l).take(l)})).mkString;val k="_"*r.length;s"$k\n\n\n$r\n\n$k"}
First try, might be golfed some more.
APL (Dyalog Extended), 89 bytes
{,⌿{⍪(⌽,2∘↓∘⊢)⍵,' _'} ̈⍪⍎ ̄1↓('\d+'⎕R{'(',⍵.Match})('[P]' '[N]'⎕R'⍴''- ''),' '⍴''=''),')⍵}
A huge, clunky solution with a lot of regex and ⍎.
Explanation
('[P]' '[N]'⎕R'⍴''- ''),' '⍴''=''),')⍵ Replace N with code for producing '=' and P for producing '- ' with a closing bracket
('\d+'⎕R{'(',⍵.Match}) prepend an opening bracket to each digit
('\d+'⎕R{'(',⍵.Match})
⍎ ̄1↓ drop the last character, and execute (gives the road markings)
⍪ table it
⍵,' _'} ̈ add two spaces and underscore for each marking
⍪(⌽,2∘↓∘⊢) Palindromize that, table it
,⌿ join all the columns into a single road