11
\$\begingroup\$

Modern British number plates (a.k.a. registration marks or license plates) use the format AANNXXX where AA is a "DVLA memory tag" (basically a location code), NN is the age identifier, and XXX is three random letters.

Your task is to, given a date, generate a random valid number plate with a date code matching the supplied date. Simplified from the actual implementation, this is how to generate them:

  • The memory tag will just be generated randomly:

    • First letter: random from ABCDEFGHKLMNOPRSVWY (the alphabet, minus IJQTUXZ)
    • Second letter: random from ABCDEFGHJKLMNOPRSTUVWXY (the alphabet, minus IQZ)
  • The age identifier follows this pattern:

    • 1st September 2001 - 28th February 2002: 51
    • 1st March 2002 - 31st August 2002: 02
    • September 2002 - February 2003: 52
    • March 2003 - August 2003: 03
    • ...
    • March 2010 - August 2010: 10
    • September 2010 - February 2011: 60
    • March 2011 - August 2011: 11
    • September 2011 - 29th February 2012: 61
    • ...
    • September 2020 - February 2021: 70
    • ...
    • September 2049 - February 2050: 99
    • March 2050 - August 2050: 00
    • September 2050 - February 2051: 50
    • March 2051 - August 2051: 01
  • The 3 random letters are picked from ABCDEFGHJKLMNOPRSTUVWXYZ (the alphabet, minus IQ)

Rules

  • You must output in uppercase with no spaces or dashes between letters. However, trailing newlines, or any other output from your language that is not easily suppressible, are allowed
  • For the purposes of this challenge, "random" means picked pseudo-randomly with any distribution as long as all possibilities have a non-zero chance of occurring
  • You may assume the date will always be in the range 1st September 2001 to 31st August 2051
  • The date can be in any reasonable input format (for example, your language's native date object, april 28 2021, (28,4,21), 1619615864 (a Unix epoch timestamp))
  • You may ignore leap seconds, daylight savings time, and timezone issues (just assume the date is always in UTC)
  • You may use any reasonable I/O method
  • Standard loopholes are forbidden
  • This is , so the shortest code in bytes wins

Test cases

These are to test the date conversion alone.

23rd September 2001     51
1st March 2006          06
29th February 2012      61
1st December 2021       71
11th October 2049       99
19th January 2051       50
\$\endgroup\$
8
  • \$\begingroup\$ Sandbox \$\endgroup\$
    – pxeger
    May 29 '21 at 14:08
  • \$\begingroup\$ Are you sure about the last few age identifiers? (None of the current three answers match in February 2050.) \$\endgroup\$ May 29 '21 at 19:27
  • 3
    \$\begingroup\$ The doc just says the "pattern" will continue - a pattern which certainly fits is to alternate between adding 50 and subtracting 49 every six months (and keeping the trailing two digits), this would give the end as: March 2049 – Aug 2049 49 Sept 2049 – Feb 2050 99 March 2050 - Aug 2050 50 Sept 2050 - Feb 2051 00 March 2051 - Aug 2051 51 \$\endgroup\$ May 29 '21 at 20:16
  • 1
    \$\begingroup\$ As a person living in Brussels, I got to see a lot of British cars while UK was in the EU (because a lot of Brits live(d) in Brussels for the EU), and my best guess about the UK licence plates pattern was that it was fully random and tried to make shortened words/sentences. TIL there actually is a pattern! \$\endgroup\$ May 31 '21 at 7:40
  • 1
    \$\begingroup\$ @JonathanAllan They can't use 51 twice (the sequence started with that). They could use 50 and 00, which didn't feature at the beginning of the sequence. However, after 99, they are more likely to reverse and go with XXXNNAA where NN is 50 for March 2050. \$\endgroup\$ May 31 '21 at 17:16
6
\$\begingroup\$

Jelly, 48 bytes

Ṗḅ12_3:6d2Ṛ%50ḅ50ṾŻṫ-“IQ“““Z“JTUX”;\ØAḟⱮ$X€ŒH¤jṚ

Try it online!

A full program taking the date as a list of integers [y,m,d] and printing the numberplate.

Thanks to @JonathanAllan for pointing out a couple of errors!

\$\endgroup\$
0
5
\$\begingroup\$

JavaScript (ES6),  121  116 bytes

Expects (month)(year). The day is ignored. Returns an array of characters.

m=>y=>[...'9512444'].map(n=>((y-(m<3))%50-50*~-~(m<3|m>8)+n)[n]||'ABCDEFGHKLMNOPRSVWYJTUXZ'[Math.random()*(28-n)|0])

Try it online!

Commented

m =>                         // m = 1-indexed month
y =>                         // y = full year
[...'9512444']               // split 9,5,1,2,4,4,4 as characters
.map(n =>                    // for each value n above:
  (                          //   build a string:
    ( y -                    //     subtract 1 from y if ...
      (m < 3)                //     ... the month is January of February
    ) % 50                   //     reduce modulo 50
    - 50 *                   //     add 100 to the result for March to August
    ~-~(m < 3 | m > 8)       //     or 150 otherwise
    + n                      //     coerce to a string
  )[n]                       //   attempt to extract the n-th character
  ||                         //   if n is greater than or equal to 4:
  'ABCDEFGHKLMNOPRSVWYJTUXZ' //     use this string instead
  [ Math.random()            //     and extract a random character
    * (28 - n)               //     in [0 ... 18] (if n = '9')
    | 0                      //     or [0 ... 22] (if n = '5')
  ]                          //     or [0 ... 23] (if n = '4')
)                            // end of map()
\$\endgroup\$
2
  • \$\begingroup\$ This fails for January 2050 - it should use 99. Note, when updating your answer, that I forgot to add the final value (March '51 - August '51, 01), (but since one of the answers worked correctly for that input already and the other two (including this one) was invalid, I thought it was ok to change). Also, the correct range should be 1 <= year <= 51 \$\endgroup\$
    – pxeger
    May 29 '21 at 19:47
  • \$\begingroup\$ @pxeger This should now work as expected. \$\endgroup\$
    – Arnauld
    May 29 '21 at 22:13
4
\$\begingroup\$

Charcoal, 51 bytes

≔⁻⪪α¹⪪IQ¹ζ‽⁻ζ⪪JTUXZ¹‽⁻ζZ﹪%02d⁺﹪⁻θ›³η⁵⁰∧÷⁻⁸η⁶¦⁵⁰F³‽ζ

Try it online! Link is to verbose version of code. Takes input as [Y, M, D] (well the D is optional and unused). Explanation:

≔⁻⪪α¹⪪IQ¹θ

Make a copy of the uppercase alphabet with the letters I and Q removed.

‽⁻θ⪪JTUXZ¹

Print a random letter excluding the letters J, T, U, X and Z.

‽⁻θZ

Print a random letter excluding Z.

﹪%02d⁺﹪⁻θ›³η⁵⁰∧÷⁻⁸η⁶¦⁵⁰

Decrement the year if the month is January or February, reduce modulo 50, then add 50 if appropriate, and format the result as two digits.

F³‽θ

Print three more random letters.

\$\endgroup\$
2
  • \$\begingroup\$ This fails for January 2050 - it should give 99. Note, when updating your answer, that the final value for March '51 - August '51 is 01 \$\endgroup\$
    – pxeger
    May 29 '21 at 19:49
  • \$\begingroup\$ @pxeger Bah, all that time I wasted writing out that incorrect explanation... \$\endgroup\$
    – Neil
    May 29 '21 at 20:20
4
\$\begingroup\$

Excel, 142 bytes

=REPLACE(CONCAT(MID("ABCDEFGHKLMNOPRSVWYJTUXZ",INT(RANDARRAY(7)*{19;23;1;1;24;24;24}+1),1)),3,2,TEXT(MOD(B2,50)+IFS(A2<3,49,A2>8,50,1,),"00"))

Link to Spreadsheet

Assumes Month in A2 and Year is in B2

Excel date as input, 161 bytes

=LET(x,EOMONTH(A1,-2),REPLACE(CONCAT(MID("ABCDEFGHKLMNOPRSVWYJTUXZ",INT(RANDARRAY(7)*{19;23;1;1;24;24;24}+1),1)),3,2,TEXT(MOD(YEAR(x),50)+(MONTH(x)>6)*50,"00")))
\$\endgroup\$
3
\$\begingroup\$

Retina, 118 bytes

T`d`9d`.0?(?=/0[12])
T`5-9`d`^.
T`d`5-9`^.(?!./0[3-8])
L$`^..
==$&===
=
<26*=>
Y`=`L
I|Q

,4`[JTUXZ]

0`Z

<(\w)+>
$?1

Try it online! Takes input in the format YY/MM but link includes test suite that trims off any trailing /DD. Explanation:

T`d`9d`.0?(?=/0[12])

Decrement the year if the month is January or February.

T`5-9`d`^.

Reduce the year modulo 50.

T`d`5-9`^.(?!./0[3-8])

Add 50 to the year unless the month is in the range March to August.

L$`^..
==$&===

Remove the month and add placeholders for the letters.

=
<26*=>
Y`=`L

Expand each placeholder to a run of letters <A..Z>.

I|Q

,4`[JTUXZ]

0`Z

Delete the Is, Qs, the first J, T, U, X and Z, and the (originally second) Z.

<(\w)+>
$?1

Pick a random remaining letter from each run.

\$\endgroup\$
3
\$\begingroup\$

Vyxal, 60 bytes

«ÞTȮa⟩Ȯ2¬~Zyė∆₂ċ«⇧D3ȯ℅₴7ȯ℅₴6ɾ2+?ḟu=50*?50%+:₀<[\0p]₴2ȯDẊẊ℅ṅ₴

Try it Online!

It's... not terrible, but still bad.

\$\endgroup\$
3
\$\begingroup\$

Python 3.8 (pre-release), 167... 164 bytes

lambda m,y,p=lambda e=0:choice('ZJTUXABCDEFGHKLMNOPRSVWY'[e:]):p(5)+p(1)+[str((z:=y%50)+49+(m>2)+50*(z<1)),'0'*(z<10)+str(z)][2<m<9]+p()+p()+p()
from random import*

Try it online!

Similar technique to Arnauld: this was written by analyzing the age identifiers. If the month is between 3 and 8 (bounds included) add the y%50 string with a leading zero if y%50<10. Otherwise, add either 50 or 49 to y%50 and return that.

Takes two inputs: month and year (in that order).

I know that from random import* definitely saves bytes, but I'm yet to find a way to integrate that without breaking TIO and adding f= (which actually inflates the bytecount.)

- 1 3 bytes thanks to ovs.

+9 bytes to fix a bug.

\$\endgroup\$
6
  • \$\begingroup\$ You can do the import after the function like this: tio.run/… \$\endgroup\$
    – ovs
    May 29 '21 at 15:55
  • \$\begingroup\$ @ovs thanks, I'll remember that in the future. \$\endgroup\$
    – user100690
    May 29 '21 at 16:01
  • \$\begingroup\$ This fails for January 2050 - it should use 99. Note, when updating your answer, that I forgot to add the final value (March '51 - August '51, 01), (but since one of the answers worked correctly for that input already and the other two (including this one) was invalid, I thought it was ok to change) \$\endgroup\$
    – pxeger
    May 29 '21 at 19:43
  • \$\begingroup\$ @pxeger Bug fixed. \$\endgroup\$
    – user100690
    May 30 '21 at 7:28
  • \$\begingroup\$ You can save two bytes by removing IQ from the string and changing e. \$\endgroup\$
    – ovs
    May 30 '21 at 14:46
2
\$\begingroup\$

Julia, 100 bytes

!n=rand(setdiff('A':'Z',"IQZJTUX"[1:n]))
m$y=!7*!3lpad((a=(m+12y-3)÷6)÷2%50+a%2*50,2,'0')*!2*!2*!2

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.