# Generate a US License Plate

Given one of the following as input:

AK,AR,AS,AZ,CA,CT,DC,FL,GA,IL,IN,IA,KS,KY,LA,MD,MI,MN,MS,NV,NH,NJ,NM,NY,NC,ND,MP,OH,OK,OR,PA,PR,RI,SC,TN,TX,UT,VT,VA,WA,WI


(with quotes)

"AK","AR","AS","AZ","CA","CT","DC","FL","GA","IL","IN","IA","KS","KY","LA","MD","MI","MN","MS","NV","NH","NJ","NM","NY","NC","ND","MP","OH","OK","OR","PA","PR","RI","SC","TN","TX","UT","VT","VA","WA","WI"


Generate and output a (uniformly) random license plate of the format matching the input. If there are multiple (comma separated) formats, use a (uniformly) random format:

AK, IA, MS, MP, VT: AAA 000
AS: 0000
AZ, GA, WA: AAA0000
AR, KS, KY, LA, ND, OR: 000 AAA
CA: 0AAA000
CT: AA-00000
DC: AA-0000
FL: AAA A00
IL: AA 00000
IN: 000A,000AA,000AAA,AAA000
MD: 0AA0000
MI: AAA 0000,0AA A00,AAA 000
MN: 000-AAA
NV: 00A-000
NH: 000 0000
NJ: A00-AAA
NM: 000-AAA,AAA-000
NY, NC, PA, TX, VA, WI: AAA-0000
OH: AAA 0000
OK: 000AAA
PR: AAA-000
RI: 000-000
SC: AAA 000,000 0AA
TN: A00-00A
UT: A00 0AA


Where A means a random character in the uppercase alphabet minus IOQ and 0 means a random single digit number (0 to 9).

All information from Wikipedia. These (states) were all of the ones that I understood and that didn't have wonky rules.

This is , so shortest answer in bytes wins!

• @MagicOctopusUrn heh, about that, different states with the same format don't keep tabs on each other, so they can both issue the same number, and cops would have to look to see what state the plate is from – Stephen Jun 27 '17 at 18:56
• The size number space for each state varies. Do we 1) consider the combined number space for all states and uniformly pick from that (which will more heavily weight states with larger number spaces)? Or do we 2) first uniformly pick one of the 50 states and then uniformly pick a number from that state's number space (which will weight all states equally)? – Digital Trauma Jun 27 '17 at 19:18
• Oh sorry I didn't read it properly. State is input. – Digital Trauma Jun 27 '17 at 19:25
• Ok, similar question for states that have multiple formats, e.g. IN. Do we uniformly pick a format (one of 000A, 000AA, 000AAA or AAA000), then pick a number from that format (each format weighted equally). Or do we consider the number space for all formats for that state and pick from that entire number space (larger formats weighted greater)? – Digital Trauma Jun 27 '17 at 20:22
• I think you left out "AR" and "OR" from the list of inputs, even though you describe their plate formats below. – Not a tree Jun 28 '17 at 3:03

# Perl 6, 492 350 bytes

{$_=('AKIAMSMPVT:7 3AS:4AZGAWA:74ARKSKYLANDOR:3 7CA:173CT:6-5DC:6-4FL:7 52IL:6 5IN:35,36,37,73MD:164MI:7 4,16 52,7 3MN:3-7NV:25-3NH:3 4NJ:52-7NM:3-7,7-3NYNCPATXVAWI:7-4OH:7 4OK:37PR:7-3RI:3-3SC:7 3,3 16TN:52-25UT:52 16'~~/$^a
[..]*?\:(<[\d]+[-\ ]>+)+%\,/)[0].pick;s:g/<[567]>/{[~]
(('A'..'Z')∖<I O Q>).pick xx($/-4)}/;S:g/\d/{[~] (^10).pick xx$/}/}


Try it online!

I was so far ahead after my first attempt, I didn't make much of an effort to pare the code down. Now I have.

In my encoding of the license plate patterns, the numbers 1-4 indicate a run of that many random digits, and the numbers 5-7 indicate of run of random permitted letters, of length four less than the number.

• Do you handle the spaces? – Zacharý Jun 28 '17 at 13:59
• Ah, no indeed, I removed spaces from the rest of the text too enthusiastically before. I've put back the spaces for twelve extra bytes. – Sean Jun 28 '17 at 17:27

# Python3, 861821819714678674670662661658596591561555551 536 bytes.

-8 bytes thanks to @DestructibleLemon (b=a+... and d=B...), -15 bytes thanks to @Felipe Nardi Batista (useless lambda and variable)

And thanks to everyone over in chat who helped golf this!

from random import*
C=choice
Z='000'
A='AAA'
B=A+'-0'+Z
a=A+' '+Z
b=A+'0'+Z
c=a[::-1]
d=B[1:]
print(C(''.join(C(['ABCDEFGHJKLMNPRSTUVWXYZ','0123456789',i]['A0'.find(i)])for i in([a]*5+[Z+'0',b,b,b]+[c]*6+['0'+A+Z,d,d+'0',A+' A00','AA 00'+Z,Z+'A,000AA,000AAA,'+A+Z,'0AA0'+Z,a+'0,0AA A00,'+a,Z+'-'+A,'00A-'+A,Z+' 0'+Z,'A00-'+A,Z+'-AAA,AAA-'+Z]+[B]*6+[a+'0',Z+A,B[:-1],Z+'-'+Z,a+','+c,'A00-00A','A00 0AA'])[[*zip('AIMMVAAGWAKKLNOCDCFIIMMMNNNNNNPTVWOOPRSTU','KASPTSZAARSYADRACTLLNDINVHJMYCAXAIHKRICNT')].index(tuple(input()))]).split(',')))


Try it online

Any golfing suggestions are welcome (and wanted). And, please, if you spot any errors, just tell me via the comments!

• Is there any way to set an item in a python list to the previous item, or another item in the list? Like, set IA to list[0] or something like that ( I don't know python ) – Stephen Jun 27 '17 at 21:39
• No. It's a dictionary, and I didn't assign a name to the dictionary, so there's no way to reference it. – Zacharý Jun 27 '17 at 23:43
• couldn't b assignment be b= a+"0"? d could be =B[1:]? – Destructible Lemon Jun 28 '17 at 2:02
• b can't be a+'0', as I screwed up the license plates. – Zacharý Jun 28 '17 at 11:09
• 561 down to 541 bytes by removing the lambda and adding repetition to lists – Felipe Nardi Batista Jun 28 '17 at 13:07

## JavaScript (ES6), 374 368 bytes

s=>(P=n=>parseInt(n,36),R=Math.random,g=F=>F?(' -'+(R()*10|0)+'ABCDEFGHJKLMNPRSTUVWXYZ'[R()*23|0])[F&3]+g(F>>2):'')(P('8cf,4q,8fz,ch6,8hq,xpb,8f3,8jj,xov,6i|ru|356|24f,8fy,xmn|8ji|8cf,ciy,8e2,xm2,ciz,ciy|8e7,xof,xmn,356,8e7,8dm,8cf|ca2,bjf,ca3'.split,[P('1k3600d2mha35h7bi00jc000o03000000809l002003n0h3032e0fh4g0h'[P(s)%159%131%70%58])].split|.sort(_=>R()-.5)[0]))


### Formatted and commented

In the following code, data sections have been truncated. Missing parts are marked with (...).

s => (                                  // given the state s
P = n => parseInt(n, 36),             // P = base-36 parsing function
R = Math.random,                      // R = random generator
g = F =>                              // g = recursive function taking an encoded format F
F ?                                 // if the format has not been yet fully processed:
(                                 //   build a string consisting of:
' -' +                          //     0: space, 1: hyphen
(R() * 10 | 0) +                //     2: a random digit
'ABCD(...)YZ'[R() * 23 | 0]     //     3: a random uppercase letter (minus I, O, Q)
)[F & 3] +                        //   pick the next character from this string
g(F >> 2)                         //   recursive call, dropping the 2 consumed bits
:                                   // else:
''                                //   stop recursion
)(                                    // initial call to g():
P(                                  //   base-36 decoding of a format picked from
'8cf,4q,(...),ca3'.split,[      //     a list of binary encoded formats
P(                              //       accessed through a base-36 decoded index
'1k36(...)0h'[                //         picked from a lookup-table of 58 entries
P(s) % 159 % 131 % 70 % 58  //           based on a hash of the state
]                             //         end of lookup-table access
)                               //       end of lookup-table index decoding
].split|                        //     end of list access / split it on '|'
.sort(_ => R() - .5)[0]           //     randomly pick a format from this list
)                                   //   end of format decoding
)                                     // end of call


### Demo

let f =

s=>(P=n=>parseInt(n,36),R=Math.random,g=F=>F?(' -'+(R()*10|0)+'ABCDEFGHJKLMNPRSTUVWXYZ'[R()*23|0])[F&3]+g(F>>2):'')(P('8cf,4q,8fz,ch6,8hq,xpb,8f3,8jj,xov,6i|ru|356|24f,8fy,xmn|8ji|8cf,ciy,8e2,xm2,ciz,ciy|8e7,xof,xmn,356,8e7,8dm,8cf|ca2,bjf,ca3'.split,[P('1k3600d2mha35h7bi00jc000o03000000809l002003n0h3032e0fh4g0h'[P(s)%159%131%70%58])].split|.sort(_=>R()-.5)[0]))

;[
'AK','AR','AS','AZ','CA','CT','DC','FL','GA','IL','IN','IA','KS','KY',
'LA','MD','MI','MN','MS','NV','NH','NJ','NM','NY','NC','ND','MP','OH',
'OK','OR','PA','PR','RI','SC','TN','TX','UT','VT','VA','WA','WI'
]
.forEach(s => console.log(s + ' --> ' + f(s)))

# T-SQL, 1104 1100 797 657 bytes

DECLARE @ CHAR(8)SELECT @=STUFF(value,1,2,'')FROM STRING_SPLIT(CAST(DECOMPRESS(CAST('H4sIAAAAAAAEAEWPUQ6DMAiGr2JCwlM9BKnZ7LTV2E7n7n+QlRbYC3yl8PNDCyIOAOACKcVstCudRYkytPSthUZPUrqM6KhxqC+3ZKNbaSWlNCltNuEJuozzdekITXDygu6xshNkx2u3xJhqREmWGUQqTiDWYpBLGEGkrOgij47N21k1eKdLM3trI+mF+h2tMSJK441qM3nDnQzLx/D8V69guM3mblvkiP1Q/SPwTqbs1XD2zVztKwnbL7p3wV77AcxSbMHfAQAA'as XML).value('.','varbinary(max)'))AS varchar(max)),','),t WHERE s=LEFT(value,2)ORDER BY NEWID()WHILE CHARINDEX('&',@)>0SET @=STUFF(@,CHARINDEX('&',@),1,SUBSTRING('ABCDEFGHJKLMNPRSTUVWXYZ',CAST(1+23*RAND()AS INT),1))WHILE CHARINDEX('#',@)>0SET @=STUFF(@,CHARINDEX('#',@),1,CAST(10*RAND()AS INT))PRINT @


EDIT 1: Saved over 300 bytes by changing VALUES() to STRING_SPLIT() (only available in SQL 2016 and later)

EDIT 2: Saved another 140 bytes by using GZIP compression as described here. We've already restricted ourselves to SQL 2016 and later, so these functions are available.

Input is via pre-existing table t with the State code in column s, per our IO standards.

After expanding the compressed string, here's the formatted code, with the super long list of states snipped:

DECLARE @ CHAR(8)
SELECT @=STUFF(value,1,2,'')
FROM STRING_SPLIT('AK&&& ###,IA&&& ###,MS&&& ###,...
(long string continues)
...,SC### #&&,TN&##-##&,UT&## #&&',','),t
WHERE s=LEFT(value,2)ORDER BY NEWID()

WHILE CHARINDEX('&',@)>0
SET @=STUFF(@,CHARINDEX('&',@),1,
SUBSTRING('ABCDEFGHJKLMNPRSTUVWXYZ',CAST(1+23*RAND()AS INT),1))

WHILE CHARINDEX('#',@)>0
SET @=STUFF(@,CHARINDEX('#',@),1,
CAST(10*RAND()AS INT))

PRINT @


So I created a huge in-memory table consisting of all the possible pairs of (state, pattern). Note that I'm not combining rows, each state is separate, and states like IN will have 4 rows, one for each pattern.

When I join that in-memory table to the input table, I sort by NEWID(), which randomizes the order and returns a random matching pattern to the variable @.

I then just replace each & with a random letter, and each # with a random digit and return the result.

## ><>, 967860 851 bytes

</b:++d**d85-*i9*i2
v\+?\"00A AAA"
/5:/
v\+?\"00000 AA"
/4:/\
v\+?\x"000-AAA"
/f:/
v\+?\>"AAA-000"
/1:/
v\+ ?\"A00-00A"
v/cb:/\/"A000"
v\++?\xx"AA000"
v/88:/\x"000AAA"
v\+-?\ >"AAA000"
/2f:/v\
v\*-?\xx"0000 AAA"
v/8c:/\x"00A AA0"
v\*-?\x>"000 AAA"
v/7c:/\"AA0 000"
v\*+?\"0000"
/6b:/
v\*-?\"0000-AA"
/5f:/
v\*-?\"0000AA0"
/bc:/
v\+-?\"AAA-00A"
/59:/
v\*+?\"000-AAA"
/4a:/
v\*- ?\"000-000"
/*a8:/
v\2+-?\"000AAA0"
/*a8:/
v\9++?\"00000-AA"
/*a8:/
v\5++?\"000-A00"
/*a4:/
v\1+-?\"0000 000"
/*a4:/
v\3+-?\"0000 AAA"
/*a5:/
v\3++?\"AA0 00A"
:63*+\:9a*4+-:aa*6++:73*+
/*+9:/
v\***?\"000 AAA"
8*-*$\::9a*-:4 /7*ae/ v\++*?\"0000AAA" :4a*3\:aa*-:cb++:ca*4++:a7++:b+ v/**++/"0000-AAA" v\***?/"AAA 000" <ov?="A":v?="0":;?=1l ~!/0\v[0< l<1x/?=]!5 +*2_/?= 1l -8::/*(~!*d2$**-2:-6:
^    >?!^"A"+o]
]~</0\v[0<
l <1x/?=4
+ *2_<v?=1l
^n^?)9:<


Try it online, or watch it at the fish playground!

This code has two parts: matching the state to the pattern, then replacing the pattern with the random characters. Neither of these things is easy in ><>.

First of all, we read in two characters, and compute 2 c1 - 9 c2 + 533, where c1 and c2 are the two character codes. The 2 and the 9 were chosen so that the formula gives each state a unique value, and the offset of 533 was chosen to maximise the number of these values that can be made using only 3 ><> instructions — it ended up being 28 out of 41 of them. We then send the fish zig-zagging down through the code until it finds the right value, at which point it escapes the zig-zag, reads the appropriate pattern and enters the fast stream in the leftmost column down to Part 2. Some of the states, particularly the ones with a choice of multiple patterns, needed some special consideration, but I managed to reuse some pieces of the code to save a few bytes.

Next, aka Part 2, we have to replace the "A"s and "0"s with random letters and numbers respectively. The only random command in ><> is x, which sets the fish's direction randomly out of up, down, left and right — not conducive to choosing something uniformly out of 10 digits or 23 letters. Let's look at the numbers bit to see how the fish does it:

]~</0\v[0<
l <1x<v?=4
l 1=_?\2*+
^n^?)9:<


The fish enters from the top right. The fish sets up an empty stack — 0[ — then randomly pushes 1 or 0 with equal probability until the stack has length 4:

   /0\v
l <1x<v?=4
_


It then combines the four 1s and 0s together as if they were binary digits — l1=?\2*+ — giving a number from 0 to 15. If the result is greater than 9, it discards all the work it just did and tries again; otherwise, it prints the number and continues:

]~<   v[0<
x<

^n^?)9:<


Making the random letters is much the same, except we also check that the result isn't "I", "O" or "Q" with ::8-:6-:2-**.

# Mathematica, 635507 470 bytes

p=RandomChoice;a_±b_:=a<>b;r=""±Characters@"ABCDEFGHJKLMNPRSTUVWXYZ"~p~#&;j=""±ToString/@0~Range~9~p~#&;m=r@3;o=j@3;x=r@2;u=j@2;z=r@1;t=j@1;k=z±u±"-";w=m±" ";AS=y=j@4;AZ=GA=WA=m±y;CT=x±"-"±j@5;DC=x±"-"±y;FL=w±z±u;IL=x±" "±j@5;IN=p@{o±z,o±x,OK=o±m,s=m±o};CA=t±s;MD=t±x±y;MI=p@{OH=w±y,t±x±" "±z±u,AK=IA=MS=MP=VT=w±o};NV=u±z±"-"±o;NH=o±" "±y;NM=p@{MN=o±"-"±m,PR=m±"-"±o};NY=NC=PA=TX=VA=WI=m±"-"±y;RI=o±"-"±j@3;SC=p@{AR=KS=KY=LA=ND=OR=o±" "±m,VT};NJ=k±m;TN=k±u±z;UT=k±t±x;#&


-165 bytes from @JungHwanMin

input form

[NV]

• I didn't use Alphabet[] because we have to exclude 3 letters (IOQ) – ZaMoC Jun 28 '17 at 11:58
• Whoops, my last one didn't work. Working version: 507 bytes: pastebin.com/4YkkkQrC – JungHwan Min Jun 28 '17 at 12:18
• 470 bytes (CP-1252) by using \[PlusMinus]: pastebin.com/cGHvSJRi – JungHwan Min Jun 28 '17 at 14:19

# PHP, 609 bytes

<?$k='9 3';$l='3 9';$m='9-4';$f=[AK=>$k,IA=>$k,MS=>$k,MP=>$k,VT=>$k,'AS'=>4,AZ=>94,GA=>94,WA=>94,AR=>$l,KS=>$l,KY=>$l,LA=>$l,ND=>$l,'OR'=>$l,CA=>193,CT=>'8-5',DC=>'8-4',FL=>'9 72',IL=>'8 5',IN=>'37X38X39X93',MD=>184,MI=>'9 31X18 72X9 3',MN=>'3-9',NV=>'27-3',NH=>'3 4',NJ=>'72-9',NM=>'3-9X9-3',NY=>$m,NC=>$m,PA=>$m,TX=>$m,VA=>$m,WI=>$m,OH=>"$k1",OK=>39,PR=>'9-3',RI=>'3-3',SC=>"$kX3 18",TN=>'72-27',UT=>'72 18'];$a=str_split(ABCDEFGHJKLMNPRSTUVWXYZ);$n=range(0,9);$p=explode(X,$f[$argv[1]]);shuffle($p);for(;$c=$p[0][$i++];){if($c<1)echo$c;else for($j=0;$j<$c%6;$j++){echo$c>5?$a[rand(0,22)]:$n[rand(0,9)];}}  The main idea is to encode the license plate pattern with digits that indicate how many repetitions of a digit or letter follow. 1 to 5 refer to the number of digits while 7, 8 and 9 refer to 1, 2 or 3 letters, respectively. Multiple patterns are separated by an X, spaces and dashes are kept as-is. The state lookup is a simple array key lookup, redundant strings are put into variables to save space. Ungolfed: <?php$f=[
AK=>'9 3',
IA=>'9 3',
MS=>'9 3',
MP=>'9 3',
VT=>'9 3',
'AS'=>4,
AZ=>94,
GA=>94,
WA=>94,
AR=>'3 9',
KS=>'3 9',
KY=>'3 9',
LA=>'3 9',
ND=>'3 9',
'OR'=>'3 9',
CA=>193,
CT=>'8-5',
DC=>'8-4',
FL=>'9 72',
IL=>'8 5',
IN=>'37X38X39X93',
MD=>184,
MI=>'9 31X18 72X9 3',
MN=>'3-9',
NV=>'27-3',
NH=>'3 4',
NJ=>'72-9',
NM=>'3-9X9-3',
NY=>'9-4',
NC=>'9-4',
PA=>'9-4',
TX=>'9-4',
VA=>'9-4',
WI=>'9-4',
OH=>'9 31',
OK=>39,
PR=>'9-3',
RI=>'3-3',
SC=>'9 3X3 18',
TN=>'72-27',
UT=>'72 18'
];
$a=str_split(ABCDEFGHJKLMNPRSTUVWXYZ);$n=range(0,9);
$p=explode('X',$f[$argv[1]]); shuffle($p);
for ($i = 0;$i < strlen($p[0]);$i++) {
$c=$p[0][$i]; if ($c < 1)
echo $c; else { for ($j = 0; $j <$c % 6; $j++){ echo$c > 5 ? $a[rand(0,22)] :$n[rand(0,9)];
}
}
}


# PHP (Phar), 495 bytes

The binary Phar file can be downloaded here and can be run with php uslic.phar <state code>.

The base code used to generate the Phar is as follows (820 bytes):

<?$f=[AK=>'AAA 111',IA=>'AAA 111',MS=>'AAA 111',MP=>'AAA 111',VT=>'AAA 111','AS'=>'1111',AZ=>'AAA1111',GA=>'AAA1111',WA=>AAA1111,AR=>'111 AAA',KS=>'111 AAA',KY=>'111 AAA',LA=>'111 AAA',ND=>'111 AAA','OR'=>'111 AAA',CA=>'1AAA111',CT=>'AA-11111',DC=>'AA-1111',FL=>'AAA A11',IL=>'AA 11111',IN=>'111AX111AAX111AAAXAAA111',MD=>'1AA1111',MI=>'AAA 1111X1AA A11XAAA 111',MN=>'111-AAA',NV=>'11A-111',NH=>'111 1111',NJ=>'A11-AAA',NM=>'111-AAAXAAA-111',NY=>'AAA-1111',NC=>'AAA-1111',PA=>'AAA-1111',TX=>'AAA-1111',VA=>'AAA-1111',WI=>'AAA-1111',OH=>'AAA 1111',OK=>'111AAA',PR=>'AAA-111',RI=>'111-111',SC=>'AAA 111X111 1AA',TN=>'A11-11A',UT=>'A11 1AA'];$a=str_split(ABCDEFGHJKLMNPQRSTUVWXYZ);$n=range(0,9);$p=explode(X,$f[$argv[1]]);shuffle($p);for(;$i<strlen($p[0]);){$c=$p[0][$i++];echo$c==A?$a[rand(0,22)]:($c>0?$n[rand(0,9)]:$c);}  If you want to generate the Phar yourself from that code, you will need to do the following: <?php$phar = new Phar('uslic.phar', 0, 'u');
$phar->setSignatureAlgorithm(Phar::MD5);$phar->addFile('s');
$phar['s']->compress(Phar::GZ);$phar->setStub('<?include"phar://u/s";__HALT_COMPILER();');


Interestingly enough, this compresses better than a more golfed version.

The hexdump of the file is:

3C 3F 69 6E 63 6C 75 64 65 22 70 68 61 72 3A 2F
2F 75 2F 73 22 3B 5F 5F 48 41 4C 54 5F 43 4F 4D
50 49 4C 45 52 28 29 3B 20 3F 3E 0D 0A 30 00 00
00 01 00 00 00 11 00 00 00 01 00 01 00 00 00 75
00 00 00 00 01 00 00 00 73 34 03 00 00 26 C8 A9
59 76 01 00 00 E3 82 AE C9 B6 11 00 00 00 00 00
00 55 90 5D 6F 82 30 14 86 FF 8A 17 4D 0A B1 26
E2 9D 43 34 1D 4C 45 04 19 20 A2 84 2C 04 41 4D
0C 12 74 CB 92 65 FF 7D A5 AD A3 DC 34 7D CE C7
FB 9E 73 26 33 50 68 31 B6 B4 29 C4 18 F7 14 45
81 C8 C4 22 D9 7E 87 5C 91 C2 40 24 88 7D 48 58
A1 80 0F 2C C5 68 81 45 DA 11 E2 80 B0 C7 5A 7A
24 00 91 E5 77 68 2F D2 1A 8B E4 18 22 C1 8D 07
45 D6 69 2D F3 20 C4 C6 1C 28 CC DE D0 5B 84 68
BE E6 3B 60 BA 3B A3 1E 2F 35 1D A6 8A A3 E6 E1
2F 8E 9E C2 B6 C1 6C 58 B1 6D B6 D7 50 22 85 49
46 ED E9 B8 D6 80 CD 1F 52 A2 53 10 5A F2 E9 99
92 B3 6A 94 FE 4B ED B6 B1 91 E3 2D 7B E6 C6 D7
70 F4 0E BA B8 83 41 D4 C1 B0 9B DD 99 1D DC 2C
85 3D 08 5A FC 06 CD 2C AE D7 96 42 E4 99 7C 32
4A BE DE F6 45 74 99 A6 23 70 F8 2E 44 01 A2 6D
C0 88 E6 12 15 A4 DA FD 51 7F DC AB EB E5 21 E1
57 DD 78 9B 2F 96 2B 6B 6D 3B EE BB E7 07 DB 70
17 ED 0F B2 0A 4A AD 4E CB 53 2E 0D D1 98 50 A5
E5 DF D5 F5 76 CC A5 08 81 22 06 69 7D FA 8A 95
24 91 D5 FB F9 B3 28 AE B9 04 2A 59 2D 6E B5 A4
82 CB 84 18 5C F3 92 84 E2 21 A9 90 7F 40 A6 D1
7F 0C 2E FD 7E A2 E6 D9 F9 46 42 1A 9E 81 34 26
2E 47 62 32 1A C9 C9 8B 04 B2 E9 70 06 CA 67 70
4C 62 20 93 D5 DF 3F A0 DB 74 9C 07 ED A5 F7 4D
BA 32 97 A2 E7 9C 83 01 00 00 00 47 42 4D 42


## Clojure, 502 501 bytes

#(apply str(for[E[repeatedly]c(rand-nth(cond('#{AK IA MS MP VT}%)["D 3"]('#{AR KS KY LA ND OR}%)["3 D"]('#{AZ GA WA}%)["D4"]1(case % AS["4"]CA["1D3"]CT["C-5"]DC["C-3"]FL["D B1"]IL["C 4"]IN["3B""3C""3D""D2"]MD["1C3"]MI["D 4""1C B2""D 2"]MN["3-C"]NV["2B-2"]NH["3 3"]NJ["B2-C"]NM["3-D""D-2"]OH["D 3"]OK["3C"]PR["D-2"]RI["3-2"]SC["D 3""3 1B"]TN["B2-2"]UT["B2 1B"]["D-4"])))r(cond((set"BCD")c)(E(-(int c)65)(fn[](rand-nth"ABCDEFGHJKLMNPRSTUVWXYZ")))((set"1234")c)(E(-(int c)48)(fn[](rand-int 10)))1[c])]r))


The input argument is a symbol, not a string. This let me avoid many double-quotes. B - D encode repetitions A - AAA, 1 - 4 encode repetitions 0 - 0000.

# Python 2, 438 bytes

import re,random
lambda s,R=range,C=random.choice:re.sub('\d',lambda c:''.join(C(['0123456789','ABCDEFGHJKLMNPRSTUVWXYZ'][c.group()>'4'])for _ in R(int(c.group())%5+1)),C("063;6-3;072;3;7 2,2 06;6-4;51-15;2-7,7-2;7 2;;7 3;;6 4;2 7;2 7;2-2;25,26,27,72;2 7;;7 3,06 51,7 2;7 2;73;;2 3;;7 51;;73;7 2;2 7;;27;2 7;;7 2;7-2;;73;;51-7;;51 06;;2-7;15-2;7 2;;7-3".split(";")["MDCASCTNMSOHILARINDMIAZNHFLWAKSOKYMPRGANJUTMNVTOR".find(s)].split(",")))


Try it online!

Note how the states string is only 49 letters long. I folded overlapping letters into one as much as possible (MDDCCAASSC…) and omitted NY, NC, PA, TX, VA, WI which thus all map to -1.

In the list of codes, 12345 mean that many digits and 678 mean (that−5) many letters.

# C (gcc), 473 469 bytes

Thanks to ceilingcat for -4 bytes.

A first feeble attempt. I suspect there is a way to shorten the strings substantially.

n,c,d,i;f(char*s){n=0;for(s=strstr("AKnIAnMSnMPnVTnASAZrGArWArARfKSfKYfLAfNDfORfCAlCTtDCsFLpILmINbcdqMDkMInojMNhNViNHgNJuNMhxNYyNCyPAyTXyVAyWIyOHoOKdPRxRIaSCoeTNvUTw",s)+2;s[n]>90;n++);for(s="4    3-3  3A   3B   3C   3 1B 3 C  3 4  3-C  2A-3 1B A21B4  1BA3 B 5  C 3  C 4  C A2 C3   C4   B-4  B-5  A2-C A2-2AA2 1BC-3  C-4  "+(s[rand()%n]-96)*5,n=5;d=c=*s++,n--;)for(c>57?i=c-64,c=65:c>47?i=c-48,c=48:(i=1);i--;putchar(d))while(i&&index("IOQ",d=rand()%(c>57?26:10)+c));}
`

Try it online!

• @ceilingcat Nice, cheers! – gastropner May 14 '18 at 16:41