Parse a variable star designation
Python 3, 121 bytes
lambda z,a='ABCDEFGHIKLMNOPQ',r='RSTUVWXYZ':int(z[1:])if z[2:]else[t+u for t in['',*r+a]for u in a+r if t<=u].index(z)-15
Try it online!
Explanation
The list comprehension [t+u for t in['',*r+a]for u in a+r if t<=u]
evaluates to these strings:
t='': A B C D E F G H I K L M N O P Q R S T U V W X Y Z
t='R': RR RS RT RU RV RW RX RY RZ
t='S': SS ST SU SV SW SX SY SZ
t='T': TT TU TV TW TX TY SZ
t='U': UU UV UW UX UY SZ
t='V': VV VW VX VY VZ
t='W': WW WX WY WZ
t='X': XX XY XZ
t='Y': YY YZ
t='Z': ZZ
t='A': AA AB AC AD AE AF AG AH AI AK AL AM AN AO AP AQ AR AS AT AU AV AW AX AY AZ
t='B': BB BC BD BE BF BG BH BI BK BL BM BN BO BP BQ BR BS BT BU BV BW BX BY BZ
...
...
...
t='Q': QQ QR QS QT QU QV QW QX QY QZ
If there are any characters past the first two (z[2:]
) then the result is int(z[1:])
. Otherwise (i.e. if there are only one or two characters) we look the string up in the list we created and subtract 15 from the index.
JavaScript (ES6), 104 100 98 92 bytes
s=>+s.slice(1)||(n=parseInt(s,36))-((v=n/36|0)?250-v*~v/2+(n%36>18)+(v>18?v>26?360:35:v):26)
Try it online!
How?
We first test whether removing the first character of the input string leads to a numeric value. If it does, we just return that. For instance, V5000
gives \$5000\$.
Otherwise, we convert the whole string from base-36 to decimal and store the result in \$n\$.
The index \$i_n\$ of the star is always less than \$n\$. What we want to do is find out the difference \$d_n\$ such that:
$$i_n=n-d_n$$
Let \$v_n\$ be the higher base-36 digit:
$$v_n=\left\lfloor\frac{n}{36}\right\rfloor$$
If \$v_n=0\$, it means that this is a single letter designation and we just need to subtract \$d_n=26\$ from \$n\$ to get the correct index (R=1
, S=2
, etc.).
Otherwise, we compute:
$$d_n=250+t_n+k_n+o_n$$
\$t_n\$ is the term reflecting the fact the designation is triangular (ZZ
, YY YZ
, XX XY XZ
, etc.):
$$t_n={v_n+1 \choose 2}=\frac{v_n\cdot(v_n+1)}{2}$$
\$k_n\$ is the correction term for the missing J
for the second letter:
$$k_n=\cases{0,&\text{$n\bmod36\le18$}\\ 1,&\text{$n\bmod36>18$} }$$
Finally, \$o_n\$ acts both as a correction term for the missing J
for the first letter and as an offset for the 'wrapping' nature of the designation which goes first from RR
to ZZ
and then from AA
to QZ
:
$$o_n=\cases{v_n,&\text{$v_n\le18$}\\ 35,&\text{$18<v_n\le26$}\\ 360,&\text{$v_n>26$} }$$
Charcoal, 41 bytes
≔…R¦[η≔Φα⁻κ⁹ζF﹪⁻Eζκ⁹LζF✂ζι⊞η⁺§ζικI∨⊕⌕ηθΣθ
Try it online! Link is to verbose version of code. Explanation:
≔…R¦[η
Start building up a list of designations with the single letters R
to Z
.
≔Φα⁻κ⁹ζ
Get the alphabet without the letter J
.
F﹪⁻Eζκ⁹Lζ
Loop over each possible first letter, but offset the value so it starts at the index of R
, wraps around, and stops at the index of Q
.
F✂ζι
Loop over each possible second letter.
⊞η⁺§ζικ
Push the letter pair to the list of designations.
I∨⊕⌕ηθΣθ
Output the index in the list, or if not found, the embedded number.