Road-Length Encoding

JavaScript (ES6), 114

Using template strings, the 5 linefeeds are significant are 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

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 "- "

Try it online here


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/
((?:(=|-| ))+)/A\1\n\n\n\1\n\nA\1\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.

((?:(=|-| ))+)/A\1\n\n\n\1\n\nA\1\n
+(A_*)(.)/\1_

set up the underscores on the top and bottom to give:

A______________________________


====- - =========- - - -=-==- 

A______________________________

Lastly, we remove the A:

A/