# Checking a Windows 95 OEM Key for validity [closed]

### Introduction

Windows 95 used a very simple algorithm for verifying license keys. The scheme of an OEM license key always looked like this:

xxxyy-OEM-NNNNNNN-zzzzz


The day can be anything within 001-366, and the year cannot be lower than 95 or above 03.

xxx represents the day of the year the key was printed on (for example 192 = 10th of July) and is a number between 001-366. yy represents the year the key was printed on and cannot be lower than 95 or above 03.

This means for example, a key with 19296 as the first segment was printed on 10th of July 1996.

The second segment is always OEM.

The third segment (NN..) is always starts with 00 and the sum of the digits has to be divisible by 7

The fourth segment is irrelevant, provided the field is the appropriate length, but has to be filled out with digits.

### Challange

Given a string, output a truthy or falsy value whether this oem key is valid or not.

### Rules

• You may provide a function or a program
• This is , so the submission with the least amount of bytes wins!

## Valid keys

12899-OEM-0042134-31009
15795-OEM-0001355-07757
35201-OEM-0009165-64718


## Invalid keys

12804-OEM-0033143-31009
16595-OEM-0001695-9
12899-OEM-0022134-31009
27497-OEM-0525347-80387

• Is 36695 a valid day/year combo? (knowing that 1995 is not a leap year) – Arnauld Jun 3 '20 at 14:12
• You probably should add some invalid keys where everything goes wrong, e.g. FOO$23-ABC. (Or, if this is an invalid test case, specify what exactly may go wrong.) – Arnauld Jun 3 '20 at 14:19 • Why is the title "Generate a valid key", but the challenge asks to check whether a key is valid? – the default. Jun 3 '20 at 14:23 • Windows 95 installer, 0 bytes – Adám Jun 3 '20 at 14:38 • Suggested invalid test cases: 12899-OEM-0042134-310099 and 012899-OEM-0042134-31009 – Noodle9 Jun 3 '20 at 14:46 ## 3 Answers # perl -pl -MList::Util=sum, 106 113 bytes $_=/^(?!000)(([012]\d\d|3([0-5]\d|6[0-5]))(9[5-9]|0[0-3])|366(00|96))-OEM-00(\d{5})-\d{5}$/&&!(sum(split//,$6)%7)


Try it online!

This assumes an ASCII only input. If the input can be outside of ASCII, we'd have to add a single extra byte (a trailing a modifier on the main regexp). It also assumes a leading 366 can only occur in the years 96 and 00, them being leap years. The bulk of the matching is done by a regexp; testing of divisibility by 7 is done outside of it.

Reads keys from STDIN; writes 1 to STDOUT for valid keys, empty lines for invalid keys.

Edit: fixed the issue mentioned by @Dingus.

• @Dingus Fixed now. – Abigail Jun 3 '20 at 16:27

# 05AB1E, 7385 78 bytes

•J" L•S£ε"©366L ₃Ƶ2Ÿт%y4Ö≠i®366Ê* '- …OEM '- 0мõ ÐþQ×SO7Ö1 '- ÐþQ×g5"#Nè.VQà}P


+12 bytes to account for leap years.

Will try to golf it down from here. If only 05AB1E had regex.. :/

Explanation:

•J" L•      "# Push compressed integer 321312516
S      # Convert it to a list of digits: [3,2,1,3,1,2,5,1,6]
£     # Split the (implicit) input-string into parts of that size
ε            # Map each part to:
"©366L ₃Ƶ2Ÿт%y4Ö≠i®366Ê* '- …OEM '- 0мõ ÐþQ×SO7Ö1 '- ÐþQ×g5"
#  Push this string
#          #  Split the string on spaces
Nè        #  Use the map-index to index into this string
.V      #  Evaluate/execute it as 05AB1E code
Q     #  Check that the top two values on the stack are equal
à    #  Pop and take its maximum (no op if it's already a single 0/1 boolean)
}P           # After the map: check if all were truthy by taking the product
# (after which the result is output implicitly)


As for each individual part:

             # xxx:
©            #  Store the string in variable ® (without popping)
366L        #  Push a list in the range [1,366]
#  After the eval:
Q       #   Check for each value whether it's equal to the current xxx part
à      #   Check if any are truthy in this list by taking the maximum

# yy:
₃            #  Push builtin 95
Ƶ2          #  Push compressed integer 103
Ÿ         #  Pop both an push a list in the range [95,103]
т%       #  Take modulo-100 on each value
y            #  Push the current yy part again
4Ö≠i        #  If it's NOT divisible by 4 (so neither 96 nor 00):
®       #   Push the xxx part from variable ®
366Ê   #   Check that it's NOT equal to 366
*  #   And check if both are truthy by multiplying them together
}        #  (implicit due to the eval: close the if-statement)
#  After the eval:
Q       #  Check for each value whether it's equal to the current yy part
à      #  Check if any are truthy in this list by taking the maximum

# OEM:
…OEM         #  Push string "OEM"
#  After the eval:
Q        #   Check if it's equal to the current OEM part
à       #   No-op maximum, since the max digit of 0/1 is 0/1 respectively

# 00:
0м           #  Remove all 0s from the current 00 part
õ          #  Push an empty string ""
#  After the eval:
Q         #   Check if the 00 part with zeroes is equal to the empty string
à        #   No-op maximum, since the max digit of 0/1 is 0/1 respectively

# NNNNN:
Ð            #  Triplicate the current NNNNN part
þ           #  Pop and only leave its digits
Q          #  Check that it's equal to the NNNNN part (1 if truthy; 0 if falsey)
×         #  Repeat the part that many times (NNNNN if truthy; "" if falsey)
S        #  Convert it to a list of characters
O       #  Sum those digits together
7Ö     #  Check that it's divisible by 7
1    #  Push a 1
#  After the eval:
Q   #   Check whether the divisibility check is equal to the 1
à  #   No-op maximum, since the max digit of 0/1 is 0/1 respectively

# zzzzz:
ÐþQ×         #  Similar as above for NNNNN
g        #  Pop and push its length
5       #  Push a 5
#  After the eval:
Q      #   Check if the length is equal to the 5
à     #   No-op maximum, since the max digit of 0/1 is 0/1  respectively

# -:
'-          '#  Push a "-"
#  After the eval:
Q          #   Check if the - part is equal to the "-"
à         #   No-op maximum, since the max digit of 0/1 is 0/1  respectively


See this 05AB1E tip of mine (section How to compress large integers?) to understand why •J" L• is 321312516 and Ƶ2 is 103.

• 2000 was also a leap year – Jonathan Allan Jun 3 '20 at 16:39
• @JonathanAllan Fixed at no change in bytes. Thanks for noticing. – Kevin Cruijssen Jun 3 '20 at 16:48