text:
Chaos is an ASCII ladder
You know nothing The things I do for "Chaos is a ladder" is a memorable line from the television series Game of Thrones.
The purpose of this challenge is to build a ladder from chaos, in ASCII art.
The challenge
Input

Ladder width, W >= 3 (integer)
Step height, H >= 2 (integer)
Number of rungs, N >= 2 (integer).

Output
A ladder with horizontal rungs and vertical rails, all 1 character wide. Ladder width (W) includes the two rails, and step height (H) includes the corresponding rung.
All rungs, including the uppermost and the lowermost, will have a piece of vertical rail of length H-1 directly above and below. The example will make this clearer.
The ladder will be made of printable, non-whitespace ASCII characters, that is, the inclusive range from ! (code point 33) to ~ (code point 126).The actual characters will be chosen randomly. Given the inputs, each of the random choices of characters must have nonzero probability. Other than that, the probability distribution is arbitrary.
Leading or trailing whitespace, either horizontal or vertical, is allowed.
Example
Given W=5, H=3, N=2, one possible output is as follows.
x   :
g   h
q$UO{
t   T
6   <
bUZXP
8   T
5   g

Note that total height is H*(N+1)-1, as there are N rungs and N+1 vertical sections.
Aditional rules

Input means and format are flexible as usual. For example, you can input the three numbers in any order, or an array containing them.

Output may be through STDOUT or an argument returned by a function. In this case it may be a string with newlines, a 2D character array or an array of strings.

A program or a function can be provided.

Standard loopholes are forbidden.

Shortest code in bytes wins.

Test cases
For each W, H, N a possible output is shown.
W=5, H=3, N=2:

\   ~
:   K
ke:[E
5   u
0   _
8Fr.D
#   r
7   X

W=3, H=2, N=2:

$ X
Mb)
0 ]
(T}
j 9

W=12, H=4, N=5:

d          Y
P          `
5          3
p$t$Ow7~kcNX
D          x
`          O
*          H
LB|QX1'.[:[F
p          p
x          (
2          ^
ic%KL^z:KI"^
C          p
(          7
7          h
TSj^E!tI&TN8
|          [
<          >
=          Q
ffl`^,tBHk?~
O          +
p          e
n          j

W=20, H=5, N=3:

G                  %
o                  y
%                  3
-                  7
U'F?Vml&rVch7{).fLDF
o                  }
U                  I
h                  y
a                  g
;W.58bl'.iHm\8v?bIn&
,                  U
N                  S
4                  c
5                  r
F3(R|<BP}C'$=}xK$F]^
'                  h
h                  u
x                  $
6                  5

can you add the (numerical) range for the ascii characters?

@Rod Good idea. Done

What kind of lower limit on the quality of randomness is there?  I assume starting at a random point and incrementing modulo (126-33) wouldn't qualify because of obvious correlation between adjacent values.  Or does it have to be capable of producing every possible sequence?  (So an 8-bit linear congruential generator wouldn't work, because one character uniquely determines the next character?)

@PeterCordes There is no problem with having some correlation, as long as every possible combination can occur. The approach you describe is, as you say, not valid because it introduces too strong statistical dependence between characters at different positions, making some combinations impossible

Every possible 2-character sequence sounds reasonable.
Requiring that every possible sequence (for the whole thing) has non-zero probability is actually a pretty strong requirement.  Most C implementations have a pretty week rand() function (e.g. standards for other functions that interact with it make it hard to use more state).  I wouldn't be surprised if the C answers using 33+rand()%93 or similar can't produce some sequences on x86 gcc + glibc.  I think using a library RNG satisfies your intent, though.  Is there a meta question about RNG strength?  (In x86 asm I'd use rdrand :)

@PeterCordes Yes, I meant theoretically. Don't worry about RNG strength; you can assume the RNG is ideal. There's some meta consensus about that. I thought there was something more specific, but all I could find was this and this

Jelly,  24 23  22 bytes
«þỊoU$ẋ⁵‘¤Ḋ×94X€€+32ỌY

A full program taking the three arguments W, H, N and printing the result.
Try it online!
How?
Builds a 2d array mask of a single rung and its vertical sections below, repeats it N+1times and removes the top rung then places random characters or spaces depending upon the mask value.
«þỊoU$ẋ⁵‘¤Ḋ×94X€€+32ỌY - Main link: W, H (N is third input / 5th command line argument)
 þ                     - outer product (build a table using):
«                      -  minimum
                       -  ...note: þ implicitly builds ranges of W and H prior
  Ị                    - insignificant? (abs(z)<=1) - yields a W by H 2-d array,
                       -   all zeros except the left and top edges which are 1s
     $                 - last two links as a monad:
    U                  -   upend (reverse each row)
   o                   -   or (vectorises) - giving us our |‾| shape of 1s
         ¤             - nilad followed by link(s) as a nilad:
       ⁵               -   5th command line argument, N
        ‘              -   increment -> N+1
      ẋ                - repeat list - giving us our ladder-mask plus a top rung)
          Ḋ            - dequeue - remove the top rung
            94         - literal ninety-four
           ×           - multiply (vectorises) - replace the 1s with 94s
              X€€      - random for €ach for €ach - 0 -> 0; 94 -> random integer in [1,94]
                  32   - literal thirty-two
                 +     - add (vectorises) - 0 -> 32; random integers now from [33,126]
                    Ọ  - character from ordinal (vectorises)
                     Y - join with newlines
                       - implicit print

Operation Flashpoint scripting language, 643 624 bytes
f={l=["""","!","#","$","%","&","'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~"];t=_this;w=t select 0;r={l select random 92};v="";s=v;i=2;while{i<w}do{i=i+1;v=v+" "};p={i=1;while{i<t select 1}do{i=i+1;s=s+call r+v+call r+"\n"}};k=0;call p;while{k<t select 2}do{k=k+1;i=0;while{i<w}do{i=i+1;s=s+call r};s=s+"\n";call p};s}

Ridiculously long because there is no way to create the characters from the character codes.
Call with:
hint ([5, 3, 2] call f)

Output:

The ladder is extra chaotic because the font is not monospaced.
Unrolled:
f =
{
    l = ["""","!","#","$","%","&","'","(",")","*","+",",","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","\","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~"];

    t = _this;
    w = t select 0;

    r =
    {
        l select random 92
    };

    v = "";
    s = v;

    i = 2;
    while {i < w} do
    {
        i = i + 1;
        v = v + " "
    };

    p =
    {
        i = 1;
        while {i < t select 1} do
        {
            i = i + 1;
            s = s + call r + v + call r + "\n"
        }
    };

    k = 0;
    call p;
    while {k < t select 2} do
    {
        k = k + 1;

        i = 0;
        while {i < w} do
        {
            i = i + 1;
            s = s + call r
        };
        s = s + "\n";

        call p
    };

    s
}

It seems as  "\n" works, "\xa3" to get something like £ doesn't work? if you can use unicode escapes you might be able to trim that array of yours.

How can I run this myself? :D

This just looks like a script was written and the spaces and newlines were removed. Is it only getting upvotes because of an image of a ladder or have I missed some clever golfing?

@steadybox are you using contextual screenshots now after I requested a non-grassland screenshot on that one question xD?

@Tschallacka \n is the only escape that is recognized. (And "" inside quotes to represent one ")

@GeekyI You'll need the game, version 1.85 or higher. No other way unfortunately :D

@JonathanAllan Not much to be done about golfing this further. I agree that there other answers with cleverer golfing more deserving of the upvotes.

@MagicOctopusUrn Did it with this one before that already :)

05AB1E, 29 bytes
Input taken in the order N, H, W
>*GNUžQ¦©.RIÍFð®.R«X²Öè}®.RJ,

Try it online!
Explanation
>*G                              # for N in [1 ... (N+1)*H)-1] do:
   NU                            # store N in variable X
     žQ                          # push a string of printable ascii
       ¦©                        # remove the first (space) and save a copy in register
         .R                      # pick a random character
           IÍF                   # W-2 times do:
              ð                  # push a space
               ®.R               # push a random ascii character
                  «              # concatenate
                   X²Ö           # push X % H == 0
                      è          # index into the string of <space><random_char> with this
                       }         # end inner loop
                        ®.R      # push a random ascii character
                           J,    # join everything to a string and print

This is a bit cheating.

@user544262772 why so?

may you explain this a little bit?

@MischaBehrend: Sure, I've added an explanation now.

@JonathanAllan not really cheating you know but, this is a language that's built for golf coding, so the final code is sure short. But this is more for fun than just a real challenge right ?

@user544262772 it can be quite challenging to make a well golfed answer in a golfing language, believe me, they are designed for golfing, but using them usually requires some thought (unless it's just "here's a built-in that does exactly what you want").

@JonathanAllan I understand. But yeah, it's more a show-off of what everyone's language has in the gut, their features, weaknesses or strong-points, than a real challenge, because if everyone use a golf-code-oriented language, everyone wins I guess.

@user544262772 Please look at some other answers on this website, you'll see that languages designed for code golf are often used. These languages were made for code golfing, that's totally right to use them.

C, 95 bytes
f(w,h,n,i){++w;for(i=0;i++<w*~(h*~n);)putchar(i%w?~-i%w%(w-2)*((i/w+1)%h)?32:33+rand()%94:10);}

93 bytes

R, 138 129 111 98 93 bytes
-13 bytes thanks to Neal Fultz!
-1 byte thanks to Robin Ryder
function(W,H,N){m=matrix(intToUtf8(32+sample(94,W*(h=H*N+H-1),T),T),h)
m[-H*1:N,3:W-1]=" "
m}

Try it online!
Anonymous function; returns the result as a matrix.
Thanks to that Word Grids question, I've been thinking about matrices a lot more than usual. I observed that the rungs are in those matrix rows that are a multiple of the step height H (R is 1-indexed), and that the rails are the first and last columns, 1 and W. So I create a matrix of random ASCII characters, and replace those letters that didn't match those criteria with spaces, and return the matrix. TIO link prints it out nicely.
Neal Fultz suggested a different indexing for the space characters, [-H*(1:N),3:W-1], which replaces all characters except for those in rows of multiples of H: -H*(1:N) and not on the edge, 3:W-1 <==> 2:(W-1).
R, 121 bytes
function(W,H,N)for(i in 1:(H*N+H-1)){for(j in 1:W)cat("if"(!(i%%H&j-1&j-W),sample(intToUtf8(33:126,T),1)," "))
cat("\n")}

Try it online!
An improvement over the original matrix-based approach I started with; it's the same algorithm but for loops are shorter than constructing and printing a matrix (but not if I don't print it!)

m[-H*(1:N),3:W-1]=" " seems a little shorter - you can always replace testing row and col with a 2-d slice.

@NealFultz wow, that's quite excellent! Thank you!

-1 byte by replacing sample(33:126,...) with 32+sample(94,...).

Perl 5, 81 bytes
80 bytes code + 1 for -p.
/ \d+ /;$_=(($}=(_.$"x($`-2)._.$/)x($&-1))._ x$`.$/)x$'.$};s/_/chr 33+rand 94/ge

Try it online!

the space after \d+ may be removed because of greedy match

C (gcc), 141 131 114 109 107 bytes
Should be able to golf this down quite a bit...
i,j,c;f(w,h,n){for(i=1;i<h*n+h;i+=j==w)printf(i%h?i++,j=0,"%c%*c\n":"%c",++j^w?c^8:10,w-2,c=33+rand()%94);}

Try it online!

can we edit i=1 in the global declaration?

106 bytes

Charcoal, 34 32 bytes
Ｅ…¹×⁺¹ＮＮ⪫ＥＩζ⎇∧﹪ιＩη﹪λ⁻Ｉζ¹ §⮌γ‽⁹⁴ω

Try it online! Takes input in the order N, H, W. Verbose approximation (Plus(InputNumber(), 1) is currently broken on TIO). Explanation:
Ｅ…¹×⁺¹ＮＮ

Map over the range 1..H*(N+1). This means that the rungs appear when i is a multiple of H.
⪫

Join the result of:
ＥＩζ

mapping over the implicit range 0..W:
⎇∧﹪ιＩη﹪λ⁻Ｉζ¹

if the column is not 0 or W-1 and the row is not a multiple of H then output a space;
§⮌γ‽⁹⁴

otherwise, take the predefined ASCII character variable, reverse it (putting the space in 94th place), and print a random character from what is now the first 94. (Because Slice sucks.)
ω

Join using the empty string. Final result is implicitly printed.

Not sure if it's helpful but you could draw the ladder and then peekall and map over random printable I think? EDIT It appears to be broken. Oops.

I'll try to fix it (pretty sure it was working before) but I've been a bit busy so it might take a while

@ASCII-only I assume you're thinking of ＮθＧＨ↓θ→Ｎ↑θ*‖Ｏ↓Ｆ⁻Ｎ¹Ｃ⁰θ¿ＥＫＡ§⮌γ‽⁹⁴«? Well, I bisected and commit a0a6316 broke it.

@ASCII-only Actually that's not quite true, there was an unrelated bug in Map where it used not is_command when it meant is_command. So you were supposed to write ＮθＧＨ↓θ→Ｎ↑θ*‖Ｏ↓Ｆ⁻Ｎ¹Ｃ⁰θＵＭＫＡ§⮌γ‽⁹⁴ if it hadn't been for that bug.

Perl 6, 76 73 bytes
->\h,\n,\w{map {chrs (roll(w,1..94)Z*1,|($_%%h xx w-2),1)X+32},1..^h*n+h}

Try it online!
Takes (h, n, w) as arguments. Returns a list of strings.
Explanation:
-> \h, \n, \w {  # Block taking arguments h, n, w
    map {
        # String from codepoints
        chrs
             # Generate w random numbers between 1 and 94
             (roll(w, 1..94)
              # Set inner numbers on non-rungs to zero
              Z* 1, |($_%%h xx w-2), 1)
             # Add 32 to numbers
             X+ 32
    }
    # Map h*n+h-1 row numbers (1-indexed)
    1..^h*n+h
}

Alternative 73 byter using xx and ++$ instead of map. Maybe you can find a place to golf off any bytes?

Python 2, 142 bytes
lambda w,h,n,e=lambda:chr(randint(33,126)):[e()+[eval(("e()+"*(w-2))[:-1])," "*(w-2)][-~i%h>0]+e()for i in range(h*-~n-1)]
from random import*

Try it online!
Saved bytes thanks to ovs!

@LuisMendo I think I fixed it now.

@LuisMendo It's my fault for not checking carefully.

42 bytes

@ovs Thanks! You forgot a 1 in the front though >_>

PowerShell, 132 124 bytes
param($w,$h,$n)-join([char[]]((($a=('#'+' '*($w-2)+"#`n")*--$h)+'#'*$w+"`n")*$n+$a)|%{($_,[char](33..126|Random))[$_-eq35]})

Try it online!
We construct a ladder composed of only # first (example), then loop |%{...} through each character and if it's -equal to 35, we pull out a new Random character from the appropriate range. Otherwise we output (i.e., either a space or newline).

JavaScript (ES6), 117 115 bytes
A recursive function building the output character by character.
"Look Ma, no literal line-feed!"
(w,h,n)=>(g=x=>y<h*n+h-1?String.fromCharCode(x++<w?x%w>1&&-~y%h?32:Math.random()*94+33|0:10)+g(x>w?!++y:x):'')(y=0)

Demo

let f =

(w,h,n)=>(g=x=>y<h*n+h-1?String.fromCharCode(x++<w?x%w>1&&-~y%h?32:Math.random()*94+33|0:10)+g(x>w?!++y:x):'')(y=0)

O.innerText = f(5,3,4)

Damnit! I was in the process of golfing mine down when I saw this. :\ You win again! :p

I finished golfing mine down (for now) - I drew the line at moving all the ternaries within String.fromCharCode, as I couldn't honestly say I'd come up with that myself after seeing this. Let me know if you feel mine is now too similar to yours.

@Shaggy No worries! (Actually, I saw your answer only after posting mine. If I had seen it earlier, I would probably have given up.)

Ah, it's the nature of the game! :) Combining our solutions gives 113 bytes, by the way

Pyth, 33 bytes
VhEjtW!Nmsm?&d}kr1tQ\ Or\!C127Qvz

Try it online: Demonstration

Java 8, 203 188 168 133 132 130 128 126 bytes
W->H->N->{for(double i=0,j,q;++i<H*N+H;)for(j=W,q=10;j-->=0;q=i%H*j<1|j>W-2?33+Math.random()*94:32)System.out.print((char)q);}

Try it online!

133 bytes: W->H->N->{for(int i=0,j;i++<H*N+H-1;){char c=10;for(j=W;j-->0;c=i%H<1|j>W-2|j<2?(char)(Math.random()*94+33):32)System.out.print(c);}}

You are currently printing the result for W-1, the inner loop has to do an additional iteration (>=0 +1 byte).

132 bytes: W->H->N->{for(int i=0,j;i++<H*N+H-1;){char c=10;for(j=W;j-->=0;c=i%H*j<1|j>W-2?(char)(Math.random()*94+33):32)System.out.print(c);}}

;++i<H*N+H; : -2 bytes.

SOGL V0.12, 32 31 bytes
 ~ΔkψR
I{e{R}¶bH{Re⁾⌡@R¶}}¹∑e⌡k

Try it Here!
Input in the order N, W, H.
Explanation:
 ~ΔkψR

     R  a function named "R", pushes a random character:
 ~       push "~"
  Δ      get the charasters from " " to "~"
   k     remove the 1st character
    ψ    choose a random character from that

I{e{R}¶bH{Re⁾⌡@R¶}}¹∑e⌡k  main program

I                         increase the 1st input - N
 {                }       N times do
  e                         push the variable e, which is here initialised to the next input - W
   { }                      E times do
    R                         execute R
      ¶                     push a newline
       bH                   push b-1, where b is initialised to the next input - H
         {       }          B-1 times do
          R                   execute R
           e⁾                 push e-2 aka width-2
             ⌡@               push that many spaces
               R              execute R
                ¶             push a newline
                   ¹∑     join the stack together
                     e⌡k  remove the first width characters

18 bytes without the random characters :/

Python 2, 114 bytes
lambda w,h,n:[[chr(32+randint(1,94)*(x%~-w*(y%h)<1))for x in range(w)]for y in range(1,h*-~n)]
from random import*

Try it online!

Haskell, 226 220 211 190 bytes
import System.Random
a=mapM id
b=(putStr.unlines=<<).a
c=randomRIO('!','~')
r w=a$c<$[1..w]
s w=a$c:(return ' '<$[3..w])++[c]
(w#h)0=b$s w<$[2..h]
(w#h)n=do{b$(s w<$[2..h])++[r w];(w#h)$n-1}

Try it online!
Saved 9 bytes thanks to Laikoni
Saved 21 bytes thanks to wchargin
Should be golfable (b$(s w)<$[2..h] and b$((s w)<$[2..h])++[r w]). I don't feel comfortable with IO and golfing.

You can use infix notation for t w h n= ...: (w#h)n= .... pure can be used instead of return. You can drop the parentheses around (d ' ')<$and (s w)<$.

@Laikoni I won't forget the infix notation next time! Thanks.

Save a bunch of bytes with c=randomRIO('!','~'), which also lets you inline d=return. Also, mapM id is one byte shorter than sequence.

@wchargin Thanks. I learned something today!

Japt -R, 42 41 40 37 34 28 25 bytes
Takes input in the order H,W,N.
;*°WÉ ÆJ²ùVXgJùU¹r,@EÅöÃé

Try it

JavaScript (ES6), 144 bytes
(w,h,n)=>Array(n+1).fill(("#".padEnd(w-1)+`#
`).repeat(h-1)).join("#".repeat(w)+`
`).replace(/#/g,_=>String.fromCharCode(33+Math.random()*94|0))

Creates the ladder out of # characters then replaces each one with a random ASCII char.
Test Snippet

let f=
(w,h,n)=>Array(n+1).fill(("#".padEnd(w-1)+`#
`).repeat(h-1)).join("#".repeat(w)+`
`).replace(/#/g,_=>String.fromCharCode(33+Math.random()*94|0))

;(W.oninput=H.oninput=N.oninput=B.onclick=_=>{let vals=[W.value,H.value,N.value].map(eval);D.innerText=vals.join`, `;O.innerText=f(...vals);})()
W: <input id=W type=range min=3 max=25 value=12>

H: <input id=H type=range min=2 max=25 value=5>

N: <input id=N type=range min=2 max=10 value=2>

<button id=B>Rerun</button>

String.fromCharCode and Math.random in one solution - why does JavaScript hate us?! Came up with this for 137 bytes, which is very similar to yours, just without the array. I wonder now if a recursive solution might be shorter still; will investigate later.

Knocked another byte off that

JavaScript (ES6), 129 117 bytes
Unfortunately, while I was in the process of golfing this down, Arnauld beat me to a similar but shorter solution. By combining our 2 solutions, this can be 113 bytes
Includes a trailing newline.
(w,h,n)=>(g=c=>l?(c++<w?c%w>1&&l%h?` `:String.fromCharCode(94*Math.random()+33|0):`
`)+g(c>w?!--l:c):``)(0,l=h*++n-1)

Try it

o.innerText=(f=
(w,h,n)=>(g=c=>l?(c++<w?c%w>1&&l%h?` `:String.fromCharCode(94*Math.random()+33|0):`
`)+g(c>w?!--l:c):``)(0,l=h*++n-1)
)(i.value=5,j.value=3,k.value=2);oninput=_=>o.innerText=f(+i.value,+j.value,+k.value)
label,input{font-family:sans-serif;font-size:14px;height:20px;line-height:20px;vertical-align:middle}input{margin:0 5px 0 0;padding:0 0 0 5px;width:100px;}
W: <input id=i min=3 type=number>H: <input id=j min=2 type=number>N: <input id=k min=2 type=number>

QBIC, 76 bytes
[:*:+b-1|G=chr$(_r33,126|)~a%b\[:-2|G=G+@ `]][e|G=G+chr$(_r33,126|)]?_sG,1,e

Explanation
[                       FOR a = 1 TO
 :                         input 1 (Height, now in var b)
  *                        times
   :                       input 2 (# of rungs, now in var c)
    +b-1|                  plus one bottom rung without crossbar
G=chr$(_r33,126|)       Assign to G a random char (_r is the RAND() function, chr$() is BASIC's num-to-char)
~a%b|                   IF we are not at a crossbar (the modulo returns anything but 0),
  [:-2|G=G+@ `            add to G x spaces, where x is width (input 3, now 'e') - 2
                        Note that G is now either 'X' or 'X   '  (for rnd char X and W=5)
]]                      Close the spacing FOR, close the IF
[e|                     FOR f = 1 to width
  G=G+chr$(_r33,126|)]     Append to G a rnd char
                        G is now either 'XXXXXX'  or 'X   XXXXX' (for rnd char X and W=5)
?_sG,1,e                PRINT the first w characters of G, and on to the next line

Sample run
Command line: 3 2 5
N   F
M   `
Bj#=y
!   (
S   N
q(.Ho
%   7
g   ,

MATL, 63 50 bytes
-13 bytes thanks to Luis Mendo
Q*qXJ*6Y2HY)wT3$ZrJ3G3$eJ3G&Ol5LZ(J:HG\~3GTX"!+g*c

Try it online!
I'm still new to golfing in MATL (and I'm not super good at MATLAB for that matter), so I know this probably isn't close to optimal. Tips are welcome. Takes input in order N,H,W.
Here we go:
Q*qXJ                     # compute H*(N+1)-1, store as J
     *                    # multiply by W
      6Y2HY)              # push printable ASCII
            wT3$Zr        # sample uniformly with replacement
                  J3G3$e  # reshape to make a matrix of the appropriate shape.

We now have a matrix of random char.
J3G                       # push J,W
   &O                     # zero matrix, J x W
     l5LZ(                # assign 1 to first and last columns

Now there's also a logical matrix for the rails.
J:                        # push J, range, so 1...J
  HG                      # take second input (H)
    \~                    # mod and bool negate (so it's 1 for rows of multiples of H)
      3GTX"!              # repmat and transpose so we have 1's for rungs

Now we have 3 matrices on the stack:

Top: 0 for non-rung, 1 otherwise
Middle: 0 for non-rail, 1 otherwise
Bottom: random characters, -20

So we do the following:
+                         # add the top two matrices.
 g                        # convert to logical so 0->0, nonzero->1
   *                      # elementwise multiply
    c                     # convert to char, implicit output (0 -> space).

Here are a few quick tips: X" is 3$ by default. 6Y2 may be handy instead of 13:106...20+. ~~ is g. J3G&Ol5LZ( can be used instead of 1F3G2-Y"h1hJT3$X"

@LuisMendo Ah, I didn't quite make it through all the docs or I would have discovered that about X". In that last tip, 5L is [1 0] but I'm not sure how that's used in conjunction with Z( -- I get that it's assigning 1 to the first and last columns but I don't get how 5LZ( accomplishes that. I'll probably ping you in MATL CHATL sometime later about this so don't worry about that for now.

Indexing is modular, so 0 is the same as "end". Z( assigns to columns. Of course, feel free to ping me in chat!

Powershell, 102 bytes
param($w,$h,$n)1..(++$n*$h-1)|%{$l=$_%$h
-join(1..$w|%{[char](32,(33..126|Random))[!$l-or$_-in1,$w]})}

Less golfed test script:
$f = {

param($w,$h,$n)
1..(++$n*$h-1)|%{       # for each lines of the ladder
    $l=$_%$h            # line number in a step
    -join(1..$w|%{      # make a line
        [char](32,(33..126|Random))[!$l-or$_-in1,$w]
    })                  # a random character if the line number in a step is a rung line or char position is 1 or width
                        # otherwise a space
}

}

&$f 5 3 2
&$f 3 2 2
&$f 12 4 5
&$f 20 5 3

Output:
0   {
H   S
']UxR
G   ]
3   t
q^R8O
q   y
t   J
U h
YQZ
_ i
3#D
I #
=          m
&          <
]          6
8nmuyw2'Y7%+
o          l
;          !
D          M
Fn[zGfT";RYt
@          B
$          e
z          @
@J[1|:-IS~y<
(          L
:          [
|          q
zBow0T0FnY8)
/          *
e          B
R          p
9{d2(RacBdRj
u          ~
`          l
J          h
v                  t
T                  -
v                  H
'                  Y
IS7{bx2&k@u7]o}>[Vq?
F                  U
?                  U
|                  Q
}                  T
:wv1wEfc6cS;430sigF|
<                  L
:                  }
*                  `
H                  =
L8k5Q/DQ=0XIUujK|c6|
j                  =
!                  p
V                  :
#                  w

Ruby, 71 bytes
EDIT: Oops I thought this was a new challenge because of the recent edit to fix a typo lol. I'm still leaving this up though because there's no Ruby answer for it yet.
->w,h,n{(1..h*-~n-1).map{|i|[*?!..?~].sample(x=i%h>0?2:w)*(' '*(w-x))}}

Try it online!

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Randomly select from an array
This challenge is rather simple:
You are given an array of positive (not including 0) integers, and have to select a random element from this array.
But here's the twist:
The probability of selecting an element is dependent on the value of the integer, meaning as the integer grows larger, the probability of it to get selected does too!
Example
You are given the array [4, 1, 5].
The probability of selecting 4 is equal to 4 divided by the sum of all elements in the array, in this case 4 / ( 4 + 1 + 5 ) = 4 / 10 = 40%.
The probability of selecting 1 is 1 / 10 or 10%.
Input
An array of positive integers.
Output
Return the selected integer if using a method, or directly print it to stdout.
Rules

This is code-golf so shortest code in bytes in any language wins.
Standard loopholes are forbidden.

Is [4, 1, 4] a valid input and, if so, should the odds of outputting 4 be 4/5, 4/9 or 8/9?

Jelly, 3 bytes
x`X

Try it online!
Look 'ma, no Unicode!
Explanation:
x`X
 `  Make monad from dyad and use same left and right arguments
x   Repeat each element of the left argument (implicit) list its respective number of times in the right argument list
  X Random element

Can you explain what your code does, please? :)

@IanH. It's really a simple algorithm repeat each element itself times then choose randomly.

R, 25 bytes
function(s)sample(s,1,,s)

Try it online!
Explanation:
function(s){
 sample(x = s, size = 1, replace = FALSE, prob = s)
}

Takes a sample from s of size 1 without replacement, with weights s; these are rescaled to be probabilities.
To verify the distribution, use this link.

you beat me to it by 9 months! :D

@JayCe heh, my only advantage over you seems to be "going first" as you're quite the golfer! :-)

Pyth, 4 bytes
OsmR

Try it here.
Saved one byte, thanks to @Jakube, with a rather unusual approach.
Pyth, 5 bytes
Osm*]

Try it here!
How?
#1

OsmR   - Full program.

   R   - Right Map...
  m    - ... Using Map. This essentially creates the list [[4,4,4,4], [1], [5,5,5,5,5]].
       - ... Credit goes to Jakube for this!
 s     - Flatten.
O      - Random element of ^. Display implicitly.

#2

Osm*]   - Full program.

  m     - Map over the input.
    ]   - The current element, d, wrapped; [d].
   *    - Repeated d times.
 s      - Flatten.
O       - Random Element. Implicitly print the result.

I can do it in 4.
Should I spoil it, or do you want to find it by yourself?

@Jakube Wait a tiny bit. Wanna see if I can do it. Is it that obvious?

No, not obvious. I think it is even a bit strange. It uses only common things, but I don't think I have seen this combination yet.

@Jakube Ok, I'll ping when I give up.

@Jakube TBH, I have absolutely no idea... Spoil?

BTW If you do spoil, you are welcome to edit in, because I'll most likely be sleeping.

OsmL or OsmR

@Jakube >.> - How could I miss that?

@Jakube Ooh that is very clever! Implicit argument d, then maps d over a range...genius!

CJam (9 bytes)
q~_]ze~mR

Online demo. This is a full program which takes input in CJam array format on stdin and prints the selected element to stdout.
Dissection
q~   e# Read and parse input
_]z  e# Copy and transpose
e~   e# Run-length decode
mR   e# Select random element uniformly

A so powerful golf for such a simple task.

Perl 6, 20 bytes
Saved 1 byte thanks to @Brad Gilbert b2gills.

{bag(@_ Zxx@_).pick}

Try it online!
This takes 1 list argument. We zip 2 copies of this list using the xx operator. So with @_ Zxx@_, we get a list in which element x is presented x times. It is then coerced to Bag, which is a collection that stores objects along with how many times they appear in the collection. Finally, we pick a random element from this collection with pick, which takes the counts into the account and does The Right Thing™.

This can be shortened to {bag(@_ Z=>@_).pick}

@BradGilbertb2gills, sadly that doesn't work. It makes a bag from the pairs (so there would be not "1" once, "2" twice etc., but "1 => 1" once, "2 => 2" also once etc. — not what I want). That's because composers are not coercers, as explained in this Advent Calendar.

@BradGilbertb2gills, but thank you anyway, you helped me to golf out some spaces here and in other challenges too!

I meant {bag(@_ Zxx@_).pick}

Aah, I see. Why it didn't occur to me... :--) Thanks.

Python 3.6, 44 bytes
lambda A:choices(A,A)[0]
from random import*

Yay for built-ins. The other A in choices(A, A) is an optional weights argument.
Try it online!

Ruby, 32 bytes
->a{a.flat_map{|x|[x]*x}.sample}

Try it online!

MATL, 8 6 bytes
tY"1Zr

Try it at MATL Online!
Explanation
t    % Implicit input. Duplicate
Y"   % Run-length decoding
1Zr  % Randomly take one value with uniform distribution. Implicitly display

Mathematica, 19 bytes
RandomChoice[#->#]&

Python 3, 62 bytes
lambda k:choice(sum([x*[x]for x in k],[]))
from random import*

Try it online!

Java (OpenJDK 8), 88  87 86 83 bytes
a->{int r=0,x=-1;for(int i:a)r-=i;for(r*=Math.random();r<1;)r+=a[++x];return a[x];}

Try it online!

Could you add an explanation? I'm trying to understand why the for(r*=Math.random();;) is needed, or if all you need is r*=Math.random().

@Ayb4btu Without the for(;;) loop this would require a second (never reached) return statement after the for(int i:a)... to satisfy the compiler - which would be 3 bytes longer.

Ah, of course, your for(int i:a) is like a foreach in C#. I had the same problem, but just used a for that continually loops. Your new answer intrigues me, I might try and pilfer some of your ideas.

J, 8 7 8 bytes
The 7 byter is invalid; I'll revert this to a previous edit when I get back to my computer in a day or two.
Try it online!
?@+/{#~

:( selecting random elements from an array is costly.
8 bytes
#~{~1?+/

9 bytes
(1?+/){#~

Explanation
?@+/{#~
?        Choose random number in range
  +/     Sum of the array
    {    Select that element from
     #~  The elements duplicated as many times as their value

?@+/ is (?@+)/; I'm afraid you'll have to bump that up to 8 again…

@FireFly I should've tested it more, good catch.

JavaScript (ES6), 50 bytes
a=>a.sort((a,b)=>b-a)[Math.random()**2*a.length|0]

Hopefully it's apparent how this works, but I'll explain it here anyway.  It sorts the integers in descending order, then chooses one at random with a beta distrubution (1/2,1).

I don't think this will have the correct distribution. My tests show that with a=[4,1,5], you'll get about 18% 1, 24% 4, and 58% 5, which suggests you'll get that distribution with any input of length 3.

That seems correct to me. Higher integer, higher probability.

Oh, I see. I misread the question. Excellent solution, +1!

05AB1E, 9 bytes
εD¸.×}˜.R

Try it online!

PowerShell, 27 bytes
($args[0]|%{,$_*$_})|Random

Try it online!
Takes input $args[0] as a literal array. Loops through each element |%{...} and each iteration constructs a new array ,$_ of $_ elements -- e.g., for 4 this will create an array @(4,4,4,4). Those array elements are then piped into Get-Random which will pluck out one of the elements with (pseudo) equal probability. Since, e.g., for @(4,1,5) this gives us @(4,4,4,4,1,5,5,5,5,5) this satisfies the probability requirements.

Japt, 7 bytes
ËÆD
c ö

Test it here

Explanation
Implicit input of array U.
Ë

Map over the array passing each element through a function where D is the current element.
ÆD

Generate an array of length D and fill it with D.
c

Flatten.
ö

Get a random element.

C# (.NET Core), 93 89 87 76+18 = 94 bytes
a=>{int i=-1,r=new Random().Next(a.Sum());while(r>=0)r-=a[++i];return a[i];}

Try it online!
An extra 18 bytes for using System.Linq;
Acknowledgements
11 bytes saved thanks to Nevay, whose random number implementation was a lot more concise (as well as being an int instead of a double).
Degolfed
a=>{
    int i=-1,
    r=new Random().Next(a.Sum());
    while(r>=0)
        r-=a[++i];
    return a[i];
}

Explanation
Get a random number, r, between 0 and sum of elements. Then at each iteration subtract the current element from r. If r is less than 0, then return this element. The idea is that there are bigger portions of the random number for the larger numbers in the array.

94 bytes: a=>{int i=-1,r=new Random().Next(a.Sum());for(;r>=0;)r-=a[++i];return a[i];}

CJam, 5 bytes
lS/mR

Try it online!
Note: seperate numbers by a space

Perl, 31 bytes
@a=map{($_)x$_}@ARGV;$a[rand@a]

This assumes the input to be command line arguments. Note that it may run out of memory if the numbers are large.

Perl 5, 31 + 1 (-a) = 32 bytes
@p=map{($_)x$_}@F;say$p[rand@p]

Try it online!

GolfScript, 17 bytes
~{.({.}*}%.,rand=

Try it online!

Charcoal, 12 bytes
Ｆ⪪θ;ＦＩι⊞υι‽υ

Try it online! Link is to verbose version of code. Since Charcoal tries to be too clever, I'm having to use semicolon-delimited input for the array. Explanation:
  θ             Input variable as string
 ⪪ ;            Split on semicolons
Ｆ               Loop i over each string
     Ｉι         Cast i to integer
    Ｆ           Repeat that many times
       ⊞υι      Push i to (originally empty) list
          ‽υ    Random selection from list
                Implicitly print

Javascript (ES6), 61 54 bytes
-7 bytes thanks to @Justin Mariner
a=>a.find(m=>(n-=m)<0,n=Math.random()*eval(a.join`+`))

Example code snippet

f=
a=>a.find(m=>(n-=m)<0,n=Math.random()*eval(a.join`+`))
console.log(f([4,1,5]))

You can sum by using eval(a.join`+`) instead of reduce.

If you're ok with ES7+ you can use: [].find(m=>(n-=m)<0,n=Math.random()*eval(a.join+)) and call with input::[].find(...)

Haskell, 87 bytes
import System.Random
f l|m<-[x<$[1..x]|x<-l]>>=id=randomRIO(0,length m-1)>>=print.(m!!)

Try it online!

Haskell, 78 77 bytes
import System.Random
f l=randomRIO(0,sum l-1)>>=pure.((l>>= \n->n<$[1..n])!!)

Try it online! Usage example: f [1,99] probably yields 99.
Explanation:

f takes a list of integers l and returns the randomly selected integer as IO Int.
l>>= \n->n<$[1..n] constructs a list with each element n repeated n times.
randomRIO(0,sum l-1) yields an integer in the range from 0 to the length of the list of repeated elements, which is exactly the sum of all elements, minus one to avoid a out of bound exception.

Bonus: 85 byte point-free version
import System.Random
(>>=).randomRIO.(,)0.pred.sum<*>(pure.).(!!).(>>= \n->n<$[1..n])

Try it online!

Bash, 51 bytes
for n in $@;{ printf $n\\n%.s `seq $n`;}|shuf|sed q

Takes space-separated or newline-separated input in one argument or multiple arguments.
Try it online!
Validate the random frequencies with a more complicated test case.

Perl 6, 21 bytes
{flat($_ Zxx$_).pick}

Try it online!
$_ Zxx $_ zips the input list with itself using the xx replication operator, turning (for example) (1, 2, 3) into ((1), (2, 2), (3, 3, 3)).  flat flattens that into a list of integers, and finally pick picks one at random.

Java 8, 127 122 121 bytes
import java.util.*;a->{List l=new Stack();for(int i:a)for(int j=i;j-->0;Collections.shuffle(l))l.add(i);return l.get(0);}

-1 byte thanks to @Nevay.
Uses a similar approach as @ErikTheOutgolfer's Jelly answer, by adding n times the item n to the list, and then select one randomly from that list.
Explanation:
Try it here.
import java.util.*;        // Required import for List, Stack and Collections
a->{                       // Method with integer-array parameter and integer return-type
  List l=new Stack();      //  Create a List
  for(int i:a)             //  Loop (1) over the input array
    for(int j=i;j-->0;     //   Inner loop (2) from `i` down to 0
        Collections.shuffle(l))
                           //   and shuffle the List randomly after every iteration
      l.add(i);            //    Add `i` that many times to List `l`
                           //   End of inner loop (2) (implicit / single-line body)
                           //  End of loop (1) (implicit / single-line body)
  return l.get(0);         //  And then return the first item of the list
}                          // End of method

You can move the #shuffle call into the for loop to save 1 byte for(int j=i;j-->0;Collections.shuffle(l))l.add(i);.

@Nevay Thanks! Shuffling the List after every iteration is pretty inefficient, but what do we care about efficiency, warnings and such when we can get rid of one additional pesky byte. ;p

GNU APL 1.2, 26 23 bytes; 1.7 21 19 bytes
Approach inspired by Erik the Outgolfer's Jelly answer. Relies on ⎕IO being 0 instead of 1, which is the default for GNU APL (sort of +5 bytes for ⎕IO←0).
-3, -2 bytes thanks to @Zacharý
∇ function form
∇f R
S[?⍴S←∊0 0⍉R∘.⍴R]∇

Anonymous lambda form
{S[?⍴S←∊0 0⍉⍵∘.⍴⍵]}

For the explanation, I will use ⍵ to represent the argument passed to the function, but it is equivalent to R in the ∇ form.
⍵∘.⍴⍵ computes the outer product on the list using the reshape (⍴) operator. Effectively, this creates a table (like a multiplication table) but instead of multiplying, it repeats the element in the column a number of times equal to the element in the row. For the example given in the question, this is:
4 4 4 4    1 1 1 1    5 5 5 5
4          1          5
4 4 4 4 4  1 1 1 1 1  5 5 5 5 5

0 0⍉⍵∘.⍴⍵ transposes the matrix and returns just the main diagonal. This gives us just the parts where the row and column in ⍵∘.⍴⍵ were the same i.e. we repeated the number a number of times equal to its value. For the example, this is:
4 4 4 4  1  5 5 5 5 5

∊ turns its argument into a list. Using the transpose (⍉) operator, we got a vector containing 3 vectors. Enlist (∊) turns it into a single vector containing all the elements.
S←... assigns this new vector to vector S. ⍴S gives us the length of that list. ? is the random operator, so ?⍴S gives us a random number between 0 and the length of the list (exclusive) (this is why it relies on ⎕IO being 0; otherwise it's between 1 and the length, inclusive). S[...] returns the element at the given index.

You don't need Q, since you never use it. And IIRC you can remove the newline before the del (little triangle-thing marking  the end of the function.)

Wow, I never new <IO> <IO>⍉ to get the main diagonal was even a thing!

@Zacharý Right, thanks. Frankly, I didn't even know about the transpose thing until I tried this task either. Found it here

Oh, there does exist a much better free APL than GNU, it's called ngn APL. It's actually pretty cool! (https://ngn.github.io/apl/web/, but it doesn't have tradfn)

@Zacharý I have that one too :) unfortunately the transpose function doesn't work (or I missed something). I will be testing it again now that I have a better understanding of how it works.

https://ngn.github.io/apl/web/#code=0%200%u23492%202%u2374%u23734, it works :}

@Zacharý for some reason I get 404? But thanks for testing it :)

Dyalog APL, 8 bytes
/⍨⌷⍨1?+/

Try it online!
How?

/⍨, n copies of n for each n in the argument.
⌷⍨, at the index of
1?, a random value between 1 and
+/, the sum of the argument

MATLAB, 30 bytes
@(a)datasample(repelem(n,n),1)

This assumes MATLAB R2015a or newer and with the Statistics & Machine Learning toolbox installed.
See the explanation below for how repelem is used. The difference between this shorter one and the one below is that the S&ML toolbox includes the function datasample which can be used to take one or more elements from an array at random (with uniform probability) which allows an anonymous function to be used, stripping away the input/disp calls.
MATLAB, 49 bytes
n=input('');a=repelem(n,n);disp(a(randi(nnz(a))))

This code assumes that MATLAB R2015a or newer is used as that is when the repelem function was introduced. repelem is a function which takes two parameters, the first is an array of numbers to be replicated, and the second is an array of how many times the corresponding element should be replicated. Essentially the function performs run-length decoding by providing the number and the run-length.
By providing the same input to both inputs of repelem we end up with an array which consists of n times more of element n if that makes sense. If you provided [1 2 3] you would get [1 2 2 3 3 3]. If you provided [1 2 4 2] you would get [1 2 2 4 4 4 4 2 2]. By doing this it means that if we select an element with uniform probability (randi(m) gives a random integer from 1 to m with uniform probability), each element n has an n times higher probability of being selected. In the first example of [1 2 3], 1 would have a 1/6 chance, 2 would have a 2/6 chance and 3 would have a 3/6 chance.

As a side note, because repelem is not available yet for Octave, I can't give a TIO link. Additionally because Octave can't be used there is a big character penalty as input() and disp() need to be used as an anonymous function is not possible. If Octave supported repelem, the following could be used:
@(n)a(randi(nnz(a=repelem(n,n))))

That would have saved 16 bytes, but it was not to be.

Really appreciate the explanation, thanks!

Vyxal, 3 bytes
ẋf℅

Try it Online!
  ℅ # Choose a random element of
ẋ   # Each element n in the array repeated n times
 f  # Flattened

Uiua SBCS, 8 bytes
⊡⌊×⚂⧻.▽.

Try it!
⊡⌊×⚂⧻.▽.
      ▽.  # repeat each array item <itself> times
    ⧻.    # length
  ×⚂      # times random unit
 ⌊        # floor
⊡         # pick

Nice, that’s what I had too

Go (1.22+ only), 116 bytes
import."math/rand"
func f(s[]int)int{A:=[]int{}
for _,e:=range s{for range e{A=append(A,e)}}
return A[Intn(len(A))]}

Attempt This Online!
Go (all versions), 121 bytes
import."math/rand"
func f(s[]int)int{A:=[]int{}
for _,e:=range s{for i:=0;i<e;i++{A=append(A,e)}}
return A[Intn(len(A))]}

Attempt This Online!
Explanation
import."math/rand"
func f(s[]int)int{
// construct a slice with each element `n` repeated `n` times
A:=[]int{}
for _,e:=range s{for i:=0;i<e;i++{A=append(A,e)}}
// actually select the element
return A[Intn(len(A))]
}

Attempt This Online!

Clojure, 64 bytes
(defn a[i](rand-nth(reduce #(concat %(take %2(repeat %2)))[]i)))

Appends each item item number of times to a new list, then takes a random element.
Finally a clojure answer that's not incredibly much longer than other answers :D

05AB1E, 21 bytes
O/ždT6m/svy-D0‹s})1kè

Try it online!

Here's a weird implementation for you, uses microseconds on the system's CPU for the randomized seed.
O/                     # [.4,.1,.5] | Push prob distribution.
  ždT6m/               # ?????????? | 0 < x < 100000 divided by 100000.
        s              # [.4,.1,.5] | Swap...
         v             # For each prob in distribution...
          y-           # Remove from random number b/w 0 and 1.
            D0‹        # Dupe each, find if this number made the random number less than 0.
               s})     # Continue loop, swapping current random diff to the front of the stack.
                  1kè  # First instance of the random number going negative is our random return.

TI-BASIC, 20 bytes
Ans→L₁
SortD(L₁
L₁(1+int(rand²dim(L₁

Input and output are stored in Ans.  If you see a box, L₁ is L1.  Same algorithm as my JavaScript answer.

Clojure, 46 bytes
(fn[s](rand-nth(flatten(map #(repeat % %)s))))

Try it online!
The usual Clojure pain: simple idea, long-ass (for golfing) function names.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Pandigital Doubling
Inspired by this CMC
Given a positive integer greater than 0, perform the following operation on it:

If all ten single digits (1234567890) are in the number at least once, output the count and exit the program
Otherwise, double the number and repeat, incrementing the count.

The count starts at 0 and is the number of times the input was doubled. For example, if the input were 617283945, it would need to be doubled once because 1234567890 has all 10 digits in it.
This is a code-golf so shortest code wins. Input may be taken as a string, if you want.
Test cases
input => output

617283945 => 1
2 => 67
66833 => 44
1234567890 => 0
100 => 51
42 => 55

Can we take input as a string?

@Stephen you may take input as a string.

@Shaggy what do you think they should be? Also, its 66833 with 2 3s

@Shaggy It might be that test case 2 will need a big integer since doubling 2 67 times gives 2^68

@Shaggy as with all challenges, no.

Is it guaranteed that for any n there exists some k such that nk is pandigital? I'd love to see a proof.

@shooqie That question was asked in the Maths chat room, but wasn't answered. I think that every n greater than 0 can be doubled into pandigitality. (Is that the right word?)

I checked all inputs up to 100,000 and the largest value for n was 78 given an input of 1471. There may be a larger n for long numbers but my stupid VBA solution takes about 8 seconds per 1,000 inputs and I don't want to wait that long. I did find an interesting pattern, though. For the first 100,000 inputs, the number of times a certain n occurred fits a normal distribution.

What does "CMC" mean?

@bfontaine Chat Mini Challenge

@shooqie Proof! For any n which is coprime to 10, it's also coprime to 10^10, and so there exists some k such that nk is 1 mod 10^10. Then 1234567890nk = 1234567890 mod 10^10, so each digit necessarily appears at least once.  If not, multiply by 2, 5, or 25 as necessary to make the last non-zero digit coprime with 10, and a variant of the above proof works (formally, n = 10^m * p, where p satisfies the above condition, then 1234567890*p*k as above is pandigital, so 1234567890*p*k10^m = 1234567890kn is). :)

A similar idea of modular inverses proves this nicely if the question asked about tripling instead, doubling only seems a little harder.

@EngineerToast 1471 stays the largest up to 1 000 000, and is in fact the last value for which the output reaches 78 below a million.

@B.Mehta Both are true up to at least 160 868 750, too.

There's no result higher than 78 in the first 1,000,000,000 values - is there a mathematician who can tell us whether any larger results can be proved or disproved?

Python 3, 39 bytes
f=lambda n:len({*str(n)})<10and-~f(n*2)

Try it online!
Outputs False for 0.

05AB1E, 11 10 bytes
-1 byte thanks to scottinet
[D9ÝåË#·]N

Try it online! or as a Test Suite
[          // Start infinity loop
 D         // Duplicate current value (or input)
  9Ý       // Push [0,1,2,3,4,5,6,7,8,9]
    å      // Does each exist in the current value
     Ë#    // Break if all equal (if every digit exists)
       ·   // Else double the current value
        ]N // End loop and print the number of times through the loop

-1 byte

@scottinet Thanks! I don't know how I missed that.

@riley was going to say use x but that's 10 too... Nice answer. Thought x would get rid of D, but it's the same idea.

J, 24 23 bytes
(]1&(+$:)2**)10>#@~.@":

Try it online!
Explanation
(]1&(+$:)2**)10>#@~.@":  Input: integer n
                     ":  Format as string
                  ~.@    Unique
                #@       Length
             10>         Less than 10
           *             Multiply, gives n if previous was true, else 0
         2*              Multiply by 2
 ]                       Get the previous condition
  1&(   )                Execute this if true on 2n, else return 0
      $:                   Recurse
  1  +                     Add 1

Nice. I was stuck on collecting the results, didn't think about using that type of recursive function.

Perl 6, 31 28 bytes (27 chars)
-3 bytes thanks to @Joshua
{($_,2×*...*.comb.Set>9)-1}

Try it online!
Explanation: Still the same construct to recursively generate lists. The first element is the given number ($_), each next element is 2 times the previous (2×* — we use ×, because, although 2 byte character, it's still 1 byte cheaper than 2 * *), and we do this until the end condition of *.comb.unique>9 is satisfied, i. e. when there is more than 9 unique characters in the number. (Technically, we break the string down to a list of characters with .comb, force it to a set with .Set (of course, Sets contain each element only once), and compare with 9, which forces the set into numerical context, which in turn gives its number of elements.)
Finally, we subtract 1 from this list. Again, the list is forced into numerical context, so what we return is 1 less than the length of that list.

You can use .Set instead of .unique to save 3 bytes.

@Joshua, good point! Thank you. I never thought of this.

JavaScript (ES6) + big.js, 84 74 73 70 bytes
Thanks @ConorO'Brien for saving 10 bytes by suggesting big.js instead of bignumber.js
Thanks to @Rick Hitchcock for -1 byte
Thanks to @Shaggy for -3 bytes
f=n=>[..."4"+2**29].every(d=>RegExp(d).test(c=Big(n)))?0:1+f(c.mul(2))

Takes input as string; supports up to around 269 due to automatic scientific notation conversion occurring beyond that point.
Test Snippet

f=n=>[..."4"+2**29].every(d=>RegExp(d).test(c=Big(n)))?0:1+f(c.mul(2))

;[617283945, 2, 66833, 1234567890, 100, 42].forEach(t=>console.log(`f(${t}) = `+f(t)))

Infinite range, 106 88 87 84 bytes
By using the config option to effectively disable scientific notation when converting numbers to strings, we can have nearly infinite range.

f=n=>[..."4"+2**29].every(d=>RegExp(d).test(c=Big(n)),Big.E_POS=1e9)?0:1+f(c.mul(2))

let num = `${Math.random()*1e6|0}`.repeat(100)
O.innerText=`f(\n${num}\n) = ${f(num)}`

Maybe you could shorten the BigNumber bit by using big.js?

@ConorO'Brien That will definitely help, especially because new is optional in that one. Will update, thanks!

Save one byte with f=n=>[..."0123456789"].every(d=>RegExp(d).test(c=Big(n)))?0:1+f(c.mul(2)).

We don't need to handle big integers so you could drop big.js if you wanted, bringing you down to 61 bytes. And you can save 3 bytes by replacing the string of digits with "4"+2**29: https://tio.run/##BcGxDkAwEADQb2GQO41LNBZDbX7AKgbhKkSu0jZSX1/vXeu7hs2fT2zE7ZyzNWKGYiaisiuVrmvdL8Qv@w@SGSY@xvRAQoocIghiVVkQJajavDkJ7ma63QEWOo2Yfw

Jelly, 12, 11 bytes
QLn⁵
ḤÇÐ¿L’

Try it online!

Gotta go fast!

Explanation:
        # Helper link, takes one argument 'z'
Q       # The unique digits of 'z'
 L      # Length
  n     # Does not equal
   ⁵    # 10
        #
        # Main link
  Ð¿    # While <condition> is true, run  and return all intermediate results
        # Condition:
 Ç      #   The helper link
        # Body:
Ḥ       #   Double the input
        # Now we have a list of all the 'z's that we passed to the helper link
    L   # Return it's length
     ’  # minus one

Test suite

J, 43 bytes
f=:(,$:@+:@{.)`[@.(9<[:#@~.10&#.inv)
<:@#@f

Try it online!
Defines an anonymous function. Collects results quite suboptimally. Check out miles's superior answer here!

There’s no need for recursion, use ^:a:: 1#@}.+:^:(10>#@~.@":)^:a:

Haskell, 46 bytes
f n|all(`elem`show n)['0'..'9']=0|1<3=1+f(2*n)

Try it online!

Clojure, 115 89 82 bytes
-26 bytes by just using a string to represent the list of characters (duh, in retrospect), and changing from using recursion to loop, which allowed me to make a couple of optimizations.
-7 bytes by getting rid of the call to bigint. Apparently we only need to handle input that won't cause an overflow.
#(loop[n % c 0](if(empty?(remove(set(str n))"1234567890"))c(recur(* 2 n)(inc c))))

Pregolfed:
(defn pan [num]
  (loop [n num
         cnt 0]

    ; Remove all the characters from the stringified input
    ;  that are numeric. If the result is an empty list, all
    ;  the numbers were present.
    (if (empty? (remove (set (str n)) "1234567890"))
      cnt
      (recur (* 2 n) (inc cnt)))))

You can save 7 bytes by using every? instead of empty? (remove …: #(loop[n % c 0](if(every?(set(str n))"1234567890")c(recur(* 2 n)(inc c)))))

@bfontaine Oh, you're right! Thanks. I'll fix that later. Thanks.

Haskell, 44 bytes
until(\c->all(`elem`show(n*2^c))['0'..'9'])(+1)0

Retina, 85 bytes
^\d*
$&¶$&
D`.(?=.*¶)
\d{10}¶\d+|\d*¶

[5-9]
#$&
T`d`EE
T`_d#`d_`\d#
#
1
}`\d\b
$&@
@

Try it online! Link includes test cases. Slightly optimised for run time. Explanation:
^\d*
$&¶$&

Duplicate the input number.
D`.(?=.*¶)

Deduplicate the digits in the first copy.
\d{10}¶\d+|\d*¶

If 10 digits remain, delete both numbers, otherwise just delete the first copy. Note that deleting both numbers causes the rest of the loop to no-op.
[5-9]
#$&

Place a # before large digits.
T`d`EE

Double each digit.
T`_d#`d_`\d#

Add in the carries.
#
1

Deal with a leading carry.
}`\d\b
$&@

Append an @ and loop until all 10 digits are found.
@

Print the number of @s added.

APL (Dyalog Unicode), 19 + 2 = 21 bytes
0∘{∧/⎕D∊⍕⍵:⍺⋄⍺+1∇2×⍵}

Try it online!
This is a dyadic Dfn (direct function), taking 0 as its left argument and the integer as the right. Since the input is supposed to be only the integer, I added 2 bytes for the argument 0∘ to the byte count.
f← is not included in the byte count, since it's not necessary. It just makes it easier to build the test cases.
How it works:
The headers:
I removed those from the byte count after some chatting in the APL room, since the function does what it's supposed to do and the results are only incorrect because of the default settings of APL's REPL.
⎕FR←1287 Sets the Float Representation to 128-bit decimal (7 is the code for decimal in APL's REPL).
⎕PP←34 Sets the Print Precision to 34 digits.
Both of these are needed, since APL's default representation for big numbers transforms them to scientific notation (e.g. 3.14159265359E15) which messes up the code big time.
0∘{∧/⎕D∊⍕⍵:⍺⋄⍺+1∇2×⍵} ⍝ Dyadic Dfn
0∘                     ⍝ Fixes 0 as the left argument
          :            ⍝ If
     ⎕D                ⍝ String representation of all digits [0, 9]
       ∊               ⍝ "is in"
        ⍕⍵             ⍝ String representation of the input
   ∧/                  ⍝ AND-reduction. Yields 1 (true) iff all digits are in the right argument.
           ⍺           ⍝ return the left argument
            ⋄          ⍝ Else
                 2×⍵   ⍝ Double the right arg
             ⍺+1       ⍝ increment the left arg
                ∇      ⍝ Recursively call this function with the new arguments.

Java 8, 132 110 87 74 bytes
n->{int c=0;for(;(n+"").chars().distinct().count()!=10;n*=2)c++;return c;}

-57 bytes thanks to @OlivierGrégoire.
Explanation:
Try it here. (Note: test case for 2 is disabled because it should stop at 268, but the size of long is limited to 263-1.)
n->          // Method with long parameter and integer return-type
  int c=0;   //  Count-integer, starting at 0
  for(;(n+"").chars().distinct().count()!=10;
             //  Loop (1) as long as the unique amount of digits in the number are not 10
    n*=2)    //    After every iteration: multiply the input by 2
   c++;      //   Increase the count by 1
             //  End of loop (1) (implicit / single-line body)
  return c;  //  Return the counter
}            // End of method

Old 132 bytes answer using a String input and regex:
n->f(n,0)int f(String n,int c){String t="";for(int i=0;i<10;t+="(?=.*"+i+++")");return n.matches(t+".*")?c:f(new Long(n)*2+"",c+1);}

Try it here. (Note: test case for 2 is disabled because it causes a StackOverflowException due to slightly too much recursion.)
The total regex to check if the String contains all 9 digits becomes ^(?=.*0)(?=.*1)(?=.*2)(?=.*3)(?=.*4)(?=.*5)(?=.*6)(?=.*7)(?=.*8)(?=.*9).*$, which uses a positive look-ahead for the entire String.

111 bytes (yup, the byte count is a "uni-digital" ;-)

Note that 2 will never work because we expect 2^68 as first pandigital number, but longs in Java are limited to 2^63-1.

@OlivierGrégoire Thanks! And 1 more byte saved by putting the ints inside the loop.

Yeah, kind of forgot that. I liked my "uni-digital", though ^^

87 bytes. Thanks reduce \o/

74 bytes. Stopping here ;-)

@OlivierGrégoire Ah nice, of course. (n+"").chars().distinct().count()!=10 if the number contains all ten digits. Smart, smart.

@KevinCruijssen I know you obliterated your old method, but just want to point out that you can use the following regex to match all 10 digits: (?:.*?(\d)(?!.*\1)){10}

@jaytea Ah nice, that's 81 bytes, which isn't too bad either: n->{int c=0;for(;!(n+"").matches("(?:.*?(\\d)(?!.*\\1)){10}");n*=2)c++;return c;}. Feel free to post it as an alternative answer if you want.

Husk, 10 bytes
←Vö>9Lud¡D

Try it online!
Explanation
        ¡D    Repeatedly double the input, collecting results in a list
 V            Return the first index where the following is true
     L          The length of
       d        the digits
      u         with duplicates removed
  ö>9           is greater than 9
←             Decrement (as Husk uses 1-indexing)

Mathematica, 59 48 47 46 38 bytes
-9 bytes thanks to Jenny_mathy.
If[!FreeQ[DigitCount@#,0],#0[2#]+1,0]&

Try it online using Mathics!

46 bytes:  If[Tr[1^Union@IntegerDigits@#]<10,#0[2#]+1,0]&

Mathematica allows for anonymous recursive functions. :o Thanks!

38 bytes:   If[!FreeQ[DigitCount@#,0],#0[2#]+1,0]&

Oh, thanks! BTW,   can be used for code but leading whitespace is not allowed. a will work but  a won't.

sure!BTW you can use this footer in TIO  Print/@f/@{617283945,2,66833,1234567890,100,42}

PowerShell, 70 69 bytes
for($n=[bigint]$args[0];([char[]]"$n"|group).count-le9;$n*=2){$i++}$i

Try it online!
(Nearly twice as long as the Python answer :-\ )
Takes input $args[0], casts it as a [bigint], saves it to $n. Enters a for loop. Each iteration we check against whether the $number converted to a string then to a char-array, when Group-Object'd together, has a .count -less than or equal to 9. Meaning, the only way that it equals 10 is if at least one digit of every number 1234567890 is present. If yes, we exit the loop. If not, we $n*=2 and continue. Each iteration inside the loop, we're simply incrementing $i. When we exit the loop, we simply output $i.
Note that for input like 1234567890 where every digit is already accounted for, this will output nothing, which is a falsey value in PowerShell, and equivalent to 0 when cast as an [int]. If that's not OK, we can simply put a + in front of the output $i to explicitly cast it as an integer.
Saved a byte thanks to Roland Heath.

Could you use le9 instead of ne10? I'm not familiar with powershell, but that might save a byte.

@RolandHeath Indeed; good call. Thanks!

R, 74 bytes
function(x){while(!all(0:9%in%el(strsplit(c(x,""),"")))){F=F+1;x=2*x};F*1}

Try it online! Note that R will give the wrong answer to f(2) due to limitations of how the language stores large integers.
Explanation: For the test of pandigitality, the input is coerced to a character vector by joining with an empty string and then split into individual digits. We then check whether all of 0:9 are present in the resulting vector; if not, we increment the counter, double the input and repeat.
The counter uses F which initialises as FALSE. To make sure it is coerced to numeric, we multiply by one before returning.

using c(x,"") is a neat trick for el(strsplit(...))

Ruby, 46 45 39 38 bytes
def f n;n.digits.uniq[9]?0:1+f(n*2)end

Try it online!
Updates:

-1 by using def f n; instead of def f(n);.
-6 by using …[9] instead of ….size==10
-1 by removing a semicolon

q/kdb+, 33 bytes
Solution:
(#)1_{x*2 1 min!:[10]in 10 vs x}\

Examples:
q)(#)1_{x*2 1 min!:[10]in 10 vs x}\[100]
51
q)(#)1_{x*2 1 min!:[10]in 10 vs x}\[1234567890]
0
q)(#)1_{x*2 1 min!:[10]in 10 vs x}\[42]
55

Explanation:
All the bytes are in the equality, might be able to golf this one down a little further. Utilises q's scan adverb:
count 1_{x*2 1 min til[10] in 10 vs x}\ / ungolfed solution
        {                            }\ / scan over this lambda until it yields same result
                              10 vs x   / convert to base 10
                           in           / left list in right list, returns boolean list
                   til[10]              / range 0..9
               min                      / return the minimum of the list, 0 or 1
           2 1                          / list (2;1) indexed into with 0 or 1
         x*                             / return x multiplied by either 2 or 1
      1_                                / 1 drop, drop one element from front of list
count                                   / count the length of the list

Notes:
If we drop to the k prompt then we can have a 25 byte solution. Converts the number to a list of characters:
q)\
  #1_{x*2 1@&/($!10)in$$x}\[100]
51

Pyth, 11 bytes
f>l{`.<QT9Z

Test suite.
First natural number T where input << T meets the requirement.

Perl 5, 52 + 1 (-p) = 53 bytes
$/=10;for$i(0..9){$/-=/$i/}$_*=2;++$\;$/&&redo}{$\--

Try it online!

Perl, 43 + 1 bytes
for$x(0..9){$_*=2,++$\,redo LINE if!/$x/}}{

Using the -p flag. This builds on the solution provided by Xcali above.

Swift 4, 111 bytes
func p(_ x:Int,_ c:Int=0)->Int{if !(String(Set(String(x)).sorted())=="0123456789"){return p(x*2,c+1)};return c}

Note: Won't work for x = 2, because of overflow.
Explanation - Input x is first typecasted to string. Then Set() removes the repeating characters. Then it is sorted to match the result. If it doesn't match, x is doubles and counter is incremented.

it doesn't wok because the var is 64 bits. There a lot of other answers with same problem.

@FunkyComputerMan It is common practice to restrict challenges to cases where input, output and/or intermediate values of the algorithm of choice fit into the language's native number type. At least for input and output, this is generally assumed even if not stated in the challenge specification.

If you think that this should be allowed bring it up with the OP.  It may be common practice but the OP has not specifically allowed it and the testcases seem to suggest you need to support 2.

@FunkyComputerMan actually, I did allow answers that can't handle numbers outside the bounds of the language, but Shaggy seems to have deleted the comment asking about that. This answer is fine.

Japt, 15 bytes
LÆ*2pXÃbì_â Ê¥A

Try it

Explanation
Implicit input of integer U.
LÆ    Ã

Create an array of integers from 0 to 99 and pass each through a function  where X is the current element.
*2pX

U multiplied by 2 raised to the power of X.
b

Get the index of the first element thay returns true when passed through the following function.
ì_â

Split to an array of digits and remove the duplicates.
Ê¥A

Get the length of the array and check for equality with 10.

Alternative, 15 bytes
@*2pX)ìâ sÊ¥A}a

Try it

Explanation
Implicit input of integer U.
@            }a

Starting with 0, return the first number that returns true when passed through the following function, with X being the current number.
*2pX)

As above, multiply U by 2 to the power of X.
ìâ

Split to an array of digits, remove duplicates and rejoin to an integer.
sÊ

Convert to a string, get the length and convert back to an integer.
¥A

Check for equality with 10.

GNU dc, 61 bytes
Input is copied from top of stack (which must be otherwise empty); output is pushed to top of stack.
[I~1r:ad0<s]ss[d1+r;a1=p]sp[d2*lfx]sh[0Sadlsxlpx11!=h]dsfxz1-

Explanation
We use the array variable a, storing a 1 in a[d] if digit d is present, otherwise falling back to 0 there.  We use the GNU extension ~ to obtain quotient and remainder in a single command.
# populate a[0-9] from the digits
[I~1r:ad0<s]ss

# check pandigit
# return 1 more than lowest unset element of a[]
# start with stack=0
[d1+r;a1=p]sp

# Test for pandigit; double and repeat if needed
[dd+lfx]sh
[0Sadlsxlpx11!=h]dsfx

# We left one value on the stack for each doubling, plus the original
z1-

As a bonus, this will work in arbitrary number bases (not only decimal): simply set the input radix as required (the constant 11 in the definition of f will be read using that number base, so is automatically correct).
Test
for i in 617283945 2 66833 1234567890 100 42
do
    printf '%s => ' $i
    dc -e $i \
       -e '[I~1r:ad0<s]ss[d1+r;a1=p]sp[dd+lfx]sh[0Sadlsxlpx11!=h]dsfxz1-' \
       -e p
done

617283945 => 1
2 => 67
66833 => 44
1234567890 => 0
100 => 51
42 => 55

REXX, 57 bytes
arg n
do b=0 while verify(0123456789,n)>0
  n=n*2
  end
say b

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Draw my Contours
Given a rectangular matrix of elevations, draw its contours.
Task
Two elements x and y are on the same contour level if floor(x/10) == floor(y/10). For example, 52 and 58 are on the same contour level, but 58 and 64 are not.
The act of drawing contours is defined as follows:
For every element e, replace it with a two-char string chosen as follows:

the first character is " " if the element below e is on the same contour level as e or if there is no element to the below e and "_" otherwise
the second character is " " if the element to the right of e is on the same contour level as e or there is no element to the right of e and "|" otherwise

The elements within rows are joined together, then the rows are joined together with newlines.
Example
Let's say the input is [[5,20],[3,6]], visualized as
5 20
3 6

We first look at 5. Since 3 is on the same contour level as 5, the first character is " ". Since 20 is not on the same contour level as 5, the second character is "|".
Now we look at 20. Since 6 is not on the same contour level as 20, the first character is "_". Since there is no element to the right of 20, the second character is " ".
Now we look at 3. Since there is no element below 3, the first character is " ". Since 6 is on the same contour level as 3, the second character is " ".
Now we look at 6. Since there is no element below 6, the first character is " ". Since there is no element to the right of 6, the second character is " ".
Based on these two-char strings, we make replacements to get [[" |","_ "],["  ","  "]]. Joining these together, we get an output of
 |_

Rules

The input matrix will always be rectangular and composed of positive integers.
Trailing spaces or newlines may be in any amount (including 0) and do not have to be consistent in any way.
You do not have to follow the same algorithm as long as you produce the same results.
Your program or function may output a newline-separated string, list of strings, or equivalent.
This is code-golf, so shortest code in bytes wins.

Test Cases
input
output

[[1,5,8,9],[3,11,13,8],[7,14,10,9],[4,8,7,6]]
  _ _
 |   |
 |_ _|

[[0,10,20,30,40,50,60,70,80,90],[0,0,10,10,20,20,30,30,40,40],[0,0,0,10,10,10,20,20,20,30],[0,0,0,0,10,10,10,10,20,20],[0,0,0,0,0,10,10,10,10,10],[0,0,0,0,0,0,10,10,10,10],[0,0,0,0,0,0,0,10,10,10],[0,0,0,0,0,0,0,0,10,10],[0,0,0,0,0,0,0,0,0,10],[0,0,0,0,0,0,0,0,0,0]]
 |_|_|_|_|_|_|_|_|_
   |_  |_ _|_ _|_ _
     |_    |_ _  |_
       |_      |_ _
         |_
           |_
             |_
               |_
                 |_

[[5,5,5,5,5,5,5,5,5,5,5],[5,10,10,10,10,10,10,10,10,10,5],[5,10,15,15,15,15,15,15,15,10,5],[5,10,15,20,20,20,20,20,15,10,5],[5,10,15,20,25,25,25,20,15,10,5],[5,10,15,20,25,30,25,20,15,10,5],[5,10,15,20,25,25,25,20,15,10,5],[5,10,15,20,20,20,20,20,15,10,5],[5,10,15,15,15,15,15,15,15,10,5],[5,10,10,10,10,10,10,10,10,10,5],[5,5,5,5,5,5,5,5,5,5,5]]
  _ _ _ _ _ _ _ _ _
 |                 |
 |    _ _ _ _ _    |
 |   |         |   |
 |   |    _    |   |
 |   |   |_|   |   |
 |   |         |   |
 |   |_ _ _ _ _|   |
 |                 |
 |_ _ _ _ _ _ _ _ _|

[[35,32,29,26,25,25,25,26,29,32,35],[32,28,25,22,20,20,20,22,25,28,32],[29,25,21,18,15,15,15,18,21,25,29],[26,22,18,14,11,10,11,14,18,22,26],[25,20,15,11,7,5,7,11,15,20,25],[25,20,15,10,5,0,5,10,15,20,25],[25,20,15,11,7,5,7,11,15,20,25],[26,22,18,14,11,10,11,14,18,22,26],[29,25,21,18,15,15,15,18,21,25,29],[32,28,25,22,20,20,20,22,25,28,32],[35,32,29,26,25,25,25,26,29,32,35]]
  _|             |_
_|    _ _ _ _ _    |_
    _|         |_
   |    _ _ _    |
   |   |     |   |
   |   |     |   |
   |   |_ _ _|   |
   |_           _|
_    |_ _ _ _ _|    _
 |_               _|
   |             |

I don't even begin to read this before realizing how cool this will be

Perl 6, 135 bytes (131 chars)
{my$n="_";sub w{$^a.chop-$^b.chop??$n!!" "};my&q={|.[1..*],.tail};(($_ «[&w]».&q) ZZ~{$n="|";$_ «[&w]».map(*.&q)}()).map:{say |$_}}

Try it online!
Slightly ungolfed:
{
    my $n = "_";
    sub w { $^a.chop - $^b.chop ?? $n !! " "};
    my &q = {|.[1..*],.tail};
    (
        ($_ «[&w]».&q)
        ZZ~
        {$n="|";$_ «[&w]».map(*.&q)}()
    ).map:{say |$_}
}

Explanation: First, we define a variable $n (line 2) and a function w (line 3). This function returns a space if its two arguments are at the same "elevation", and the contents of variable $n otherwise. Instead of dividing by 10 and flooring, we abuse the fact that ints are Cool (can be treated like strings) and use chop to remove the last character (=digit). Then we calmly subtract them, forcing them into numbers again :—).
After that (line 4) we make up a function q that takes a list and returns that list with first element removed and the last element duplicated.
On the next 3 lines, we're going to make 2 more matrices from the input matrix: the first one has the first row missing and the last row duplicated (that's just .&q — using .&, you can call a function on anything as if it was a method — the thing in front of the dot is then the first argument), the other one has the first column missing and the last column duplicated (that's .map(*.&q)).
First (line 4) we take the original matrix $_, "overlay" it with the "shifted rows" matrix and use the function w as a binary operator (that's that [&w]) on the matching elements. That one puts a _ wherever the matching elements are on the different elevations, and a  otherwise. So we get ½ of the result (only the "first characters").
At line 6, we do the same thing, but first we change $n to |, and we now "overlay" the original matrix with the matrix with shifted columns. Result has a | at different and  at the same elevations. These are the "second characters".
Now we just combine them together. We zip the arrays with a zip with a concat (yeah...), which results in a matrix of the original shape whose each element is the 2 matching elements of the "half-solutions" concatenated. Finally, we just map over this matrix (which is really a list of lists). Each of these lists is flattened and then say-ed (printed with a newline). Since say can take any number of arguments and it prints them all without separators, making the newline only at the end, we get the desired picture on stdout. (And the block returns a list of Trues (each say returns one True), but who cares.)

+1 for but who cares

Jelly,  25 23  22 bytes
-1 byte thanks to miles (I vectorises)
:⁵I;€0ao⁶
Zç”_Zż"ç”|$Y

A full program printing the result. As a monadic link  it takes a list of lists of numbers, the elevations, and returns a list lists, however these "rows" consist of lists of two character "pairs" - if this is fine then 1 byte may be saved by removing Y.
Try it online!
How?
:⁵I;€0ao⁶ - Link 1, assignCharacters (row-wise): list of lists of numbers; character, c
 ⁵        - literal 10
:         - integer division (vectorises)
  I       - incremental differences (vectorises) (zero if the same else non-zero)
     0    - literal 0
   ;€     - concatenate for €ach (rightmost edge of a row has no contour mark)
      a   - logical and (vectorises) with c (replace non-zeros with the contour character)
        ⁶ - literal space character
       o  - logical or (vectorises) (replace the zeros with spaces)

Zç”_Zż"ç”|$Y - Main link: list of lists of numbers, contours
Z            - transpose the input (get the columns)
  ”_         - literal underscore character, '_'
 ç           - call the last link (1) as a dyad with '_'
    Z        - transpose the result
          $  - last two links as a monad:
        ”|   -   literal pipe character, '|'
       ç     -   call the last link (1) as a dyad with '|'
      "      - zip with the dyadic operation:
     ż       -   zip (interleave the column-wise characters with the row-wise ones)
           Y - join with newlines
             - implicit print

grr 3 bytes. +1 but I will try to outgolf you ;)

Independent solution - just saw yours is very similar! ⁵ saves you one straight off...

You can save a byte using each on the join in the helper :⁵I;€0ao⁶ instead of in the main link Zç”_Zż"ç”|$Y

@miles Oh wow, that works? Thanks! I imagined I would not vectorise like that.

Yeah I vectorizes at depth 1, and both a and o vectorize at depth 0

Jelly, 24 bytes
:⁵IṠ;€0
ZÇZị⁾_ +³Ç¤ị⁾| ¤

Try it online!
Explanation
:⁵IṠ;€0           Helper Link; get contour data
:                 Floor division by
 ⁵                10
  I               Compute increments
   Ṡ              Sign; ±1 for different values and 0 for same values
    ;             Append
      0           Zero
     €            To each row
ZÇZị⁾_ +³Ç¤ị⁾| ¤  Main Link
Z                 Zip the input (for vertical contours _)
 Ç                Get the contour data
  Z               Zip the data (because it's zipped from the first Z)
   ị              Index into the string
    ⁾_            "_ "
       +          Add (vectorizing twice) to
        ³ ¤    ¤  Nilad starting from (input)
         Ç        Get contour data (horizontal contours |)
           ị      Index into the string
            ⁾|    "| "

-2 bytes thanks to Jonathan Allan

Your solution can actually do away with the Y - it will return a list of lists of characters, which I believe is OK (while mine has pairs inside the "rows").

@JonathanAllan oh yeah true... thanks!

Python 2, 199 186 157 155 bytes
lambda a:(lambda x:'\n'.join(''.join('_ '[x==z]+'| '[x==y]for x,y,z in zip(r,r[1:]+r[-1:],q))for r,q in zip(x,x[1:]+x[-1:])))([[v/10for v in r]for r in a])

Try it online!

Python 2, 226 bytes
l=[[j/10for j in i]for i in input()]
for i,j in enumerate(l[:-1]):print''.join('_ '[h==l[i+1][g]]+'| '[h==j[g+1]]for g,h in enumerate(j[:-1]))+'_ '[j[-1]==l[i+1][-1]]
print''.join(' '+'| '[i==j]for i,j in zip(l[-1],l[-1][1:]))

Try it online!
Whew, that was a doozy to work the logic out. I now see Hyper Neutrino ninja'd me with a shorter answer but I spent too much work on this not to post it. :P
Also, can I just say, this is an awesome way to make ASCII-art. Excuse me while I make a boatload more of these.

ninja'd: dude it's been 45 minutes

Yeah, I didn't look at the answers... :P

You can save 4 bytes by defining a variable for enumerate instead of using the full name twice.

218 bytes by removing the first enumerate (obs, i had to remove some inputs to be able to link it here)

J, 58 bytes
f=.{~0==/@]
[:(,/"2)2 2((' _'f{."1),' |'f{.);.3 1:+<.@%&10

Try it online!
An anonymous function which takes a matrix and outputs the contours.
Lotta room for improvement here. I didn't have time to try all the test cases so let me know if there are any issues. Will try to golf more and explain later.
(Quick) Explanation
Helper function: indexes into a length 2 string based on whether the first element of a 2 length array is equal to the second. If it is equal, it indexes into the zeroth element, if it is unequal, it indexes into the first. A 1 length array always indexes into the zeroth element of the string.
f=.{~0==/@]

Main function
[:(,/"2)2 2((' _'f{."1),' |'f{.);.3 1:+<.@%&10

1:+<.@%&10 floors each element divided by 10 and adds 1 (so we will never get 0 -- this is important for the helper function).
2 2((' _'f{."1),' |'f{.);.3 cuts the matrix into 2 x 2 segments if it can (otherwise it'll give a 2 x 1, 1 x 2, or 1 x 1 segment near the edges) and applies the function that uses f to compare the top left element to the top right and the top left element to the bottom left.
(,/"2) flattens the result into the desired shape. I really feel like I should be able to avoid having to use this (and a lot of other things, but I digress).

J, 46 45 bytes
' _|'({~];"1@(,&.>-@|:)&(0,~}.~:}:)|:)<.@%&10

Try it online!

JavaScript (ES6), 120 118 bytes
a=>a.map(b=>b.map(c=>c/10|0)).map((b,i,a)=>b.map((c,j)=>((a[i+1]||0)[j]-c?'_':' ')+(b[j+1]-c?'|':' ')).join``).join`\n`

Where \n represents the literal newline character. Edit: Saved 2 bytes thanks to @Bálint.

f=
a=>a.map(b=>b.map(c=>c/10|0)).map((b,i,a)=>b.map((c,j)=>((a[i+1]||0)[j]-c?'_':' ')+(b[j+1]-c?'|':' ')).join``).join`
`
;[
[[5,20],[3,6]]
,
[[1,5,8,9],[3,11,13,8],[7,14,10,9],[4,8,7,6]]
,
[[0,10,20,30,40,50,60,70,80,90],[0,0,10,10,20,20,30,30,40,40],[0,0,0,10,10,10,20,20,20,30],[0,0,0,0,10,10,10,10,20,20],[0,0,0,0,0,10,10,10,10,10],[0,0,0,0,0,0,10,10,10,10],[0,0,0,0,0,0,0,10,10,10],[0,0,0,0,0,0,0,0,10,10],[0,0,0,0,0,0,0,0,0,10],[0,0,0,0,0,0,0,0,0,0]]
,
[[5,5,5,5,5,5,5,5,5,5,5],[5,10,10,10,10,10,10,10,10,10,5],[5,10,15,15,15,15,15,15,15,10,5],[5,10,15,20,20,20,20,20,15,10,5],[5,10,15,20,25,25,25,20,15,10,5],[5,10,15,20,25,30,25,20,15,10,5],[5,10,15,20,25,25,25,20,15,10,5],[5,10,15,20,20,20,20,20,15,10,5],[5,10,15,15,15,15,15,15,15,10,5],[5,10,10,10,10,10,10,10,10,10,5],[5,5,5,5,5,5,5,5,5,5,5]]
,
[[35,32,29,26,25,25,25,26,29,32,35],[32,28,25,22,20,20,20,22,25,28,32],[29,25,21,18,15,15,15,18,21,25,29],[26,22,18,14,11,10,11,14,18,22,26],[25,20,15,11,7,5,7,11,15,20,25],[25,20,15,10,5,0,5,10,15,20,25],[25,20,15,11,7,5,7,11,15,20,25],[26,22,18,14,11,10,11,14,18,22,26],[29,25,21,18,15,15,15,18,21,25,29],[32,28,25,22,20,20,20,22,25,28,32],[35,32,29,26,25,25,25,26,29,32,35]]
].forEach(a=>document.write(['<pre>','</pre>'].join(f(a))));

You can turn the (a[i] || [])[j] constructs to (a[i] || 0)[j]

Also, in the last join\\n`you could remove the\n` part and replace it with an actual newline

114 bytes: a=>a.map(b=>b.map(c=>c/10|0)).map((b,i,a)=>b.map((c,j)=>" _"[(a[i+1]||0)[j]-c&1]+" |"[b[j+1]-c&1]).join\`).join```

@Bálint Bah, I keep forgetting to do that \n part; I test in a REPL so literal newlines would get in the way.

@Bálint But your last suggestion fails for the original example, which I've added to the list of outputs.

Proton, 202 bytes
R=(L=len)+range
k=[map((//)&10,r)for r:eval(input())]
d=(x,y,X,Y)=>X>=L(k)or Y>=L(k[X])or k[x][y]==k[X][Y]
print('\n'.join(map(''.join,[['_ '[d(x,y,x+1,y)]+'| '[d(x,y,x,y+1)]for y:R(k[x])]for x:R(k)])))

Try it online!
-2 bytes thanks to Jonathan Frech
-15 bytes by switching to Proton instead of Python 2

You can save two bytes by replacing len with Land defining L=len;.

Java 8, 200 170 169 bytes
a->{String r="";for(int l=a.length,i=0,j;i<l;i++,r+="\n")for(j=0;j<l;r+=(i>l-2||a[i][j]/10==a[i+1][j]/10?" ":"_")+(j++>l-2||a[i][j-1]/10==a[i][j]/10?" ":"|"));return r;}

Explanation:
Try it here.
Note that integer division in Java automatically floors.
a->{                   // Method with 2D int-array as parameter and String return-type
  String r="";         //  Result-String
  for(int l=a.length,  //  Length of the input array
      i=0,j;           //  Index integers
      i<l;i++,         //  Loop (1) over the rows of the input array
          r+="\n")     //  and append a new-line to the result after every iteration
    for(j=0;j<l;       //   Inner loop (2) over the columns of a row
      r+=              //    Append the String with:
         (i>l-2        //      If it's the last row,
         ||a[i][j]/10==a[i+1][j]/10?
                       //      or the current and next rows are equal floored/10:
          " "          //       Use a space
         :             //      Else:
          "_")         //       Use a "_"
        +              //     Plus
         (j++>l-2      //      If it's the last column in the row,
         ||a[i][j-1]/10==a[i][j]/10?
                       //      or the current and next columns are equal floored/10:
          " "          //       Use a space
         :             //      Else:
          "|")         //       Use "|"
    );                 //   End of column loop (2)
                       //  End of row-loop (1) (implicit / single-line body)
  return r;            //  Return the result-String
}                      // End of method

R, 159 bytes
f=function(m){M=m%/%10;a=cbind(0,t(apply(M,1,diff)));b=rbind(apply(M,2,diff),0);a[!!a]="|";b[!!b]="_";M[]=gsub("0"," ",paste0(a,b));write(t(M),"",ncol(m),,"")}

With newlines and indentations:
f=function(m){
    M=m%/%10
    a=cbind(0,t(apply(M,1,diff))) #row-wise difference
    b=rbind(apply(M,2,diff),0) #column-wise difference
    a[!!a]="|"
    b[!!b]="_"
    M[]=gsub("0"," ",paste0(a,b)) # M[] is a trick to force the result to have the same structure as M
    write(t(M),"",ncol(m),,"")
    }

Does the integer division of the matrix, measures the row-wise and column-wise differences, and when not null replace by |and _ respectively, then pastes both (painless, thanks to R's vectorization) and outputs.
Test cases:
> m=matrix(c(0,10,20,30,40,50,60,70,80,90,0,0,10,10,20,20,30,30,40,40,0,0,0,10,10,10,20,20,20,30,0,0,0,0,10,10,10,10,20,20,0,0,0,0,0,10,10,10,10,10,0,0,0,0,0,0,10,10,10,10,0,0,0,0,0,0,0,10,10,10,0,0,0,0,0,0,0,0,10,10,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0),byrow=T,ncol=10)
> f(m)
  |_|_|_|_|_|_|_|_|_
    |_  |_ _|_ _|_ _
      |_    |_ _  |_
        |_      |_ _
          |_
            |_
              |_
                |_
                  |_

> m=matrix(c(5,5,5,5,5,5,5,5,5,5,5,5,10,10,10,10,10,10,10,10,10,5,5,10,15,15,15,15,15,15,15,10,5,5,10,15,20,20,20,20,20,15,10,5,5,10,15,20,25,25,25,20,15,10,5,5,10,15,20,25,30,25,20,15,10,5,5,10,15,20,25,25,25,20,15,10,5,5,10,15,20,20,20,20,20,15,10,5,5,10,15,15,15,15,15,15,15,10,5,5,10,10,10,10,10,10,10,10,10,5,5,5,5,5,5,5,5,5,5,5,5),byrow=T,ncol=11)
> f(m)
   _ _ _ _ _ _ _ _ _
  |                 |
  |    _ _ _ _ _    |
  |   |         |   |
  |   |    _    |   |
  |   |   |_|   |   |
  |   |         |   |
  |   |_ _ _ _ _|   |
  |                 |
  |_ _ _ _ _ _ _ _ _|

Perl 5, 130 126 bytes
124 bytes of code + 2 for -ap flags
push@a,[map 0|$_/10,@F]}{map{say map{($a[$r+1][$c]-$_&&$r<$#a?'_':$").($a[$r][++$c]-$_&&$c<@{$a[0]}?'|':$")}@$_;$c=0;$r++}@a

Try it online!
Input format is 2-D grid of space separated numbers.
Explanation
This is from a previous iteration of the code.
push@a,[map 0|$_/10,@F]     # read the input, divide it by 10, and store it in a 2-D array
}{                          # end the implicit while loop and start the final block
map{                        # repeat this for each line
  $_=($a[$r+1][$c]-$_&&$r<$#a?'_':$")       # set appropriate characters to output based
     .($a[$r][++$c]-$_&&$c<@{$a[0]}?'|':$") # on the given rules
  for@$_;                                   # repeat for each number on the line
  $c=0;$r++;                         # setup row and column counters for next iteration
  say@$_                             # output this line
}@a