26 Singers, 26 Letters
Python 2, 80 71 bytes
def f(s):i=sum(map(ord,s))%98%40;return chr(i-i/26*18+i/32*3-i/37*8+65)
Try it online!
The sums of ordinals modded give numbers between 0
and 38
The numbers larger than 25 are then shifted to fill in the blanks as below (sorted sequence shown):
0 1 2 3 4 5 6 7 8 - - - - 13 14 - 16 - 18 - - - 22 23 24 25 - 27 28 29 30 - 32 - 34 35 36 - 38
Subtract 18
if i>25
:
0 1 2 3 4 5 6 7 8 - - - - 13 14 - 16 - 18 - - - 22 23 24 25
- 27 28 29 30 - 32 - 34 35 36 - 38
Add 3
if i>31
:
0 1 2 3 4 5 6 7 8 - - - - 13 14 - 16 - 18 - - - 22 23 24 25
- 27 28 29 30
- 32 - 34 35 36 - 38
Subtract 8
if i>37
:
0 1 2 3 4 5 6 7 8 - - - - 13 14 - 16 - 18 - - - 22 23 24 25
- 27 28 29 30
- 32 - 34 35 36
- 38
Which gives the sequence 0..25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
These are then converted to A-Z
with chr(i+65)
6502 machine code routine (C64), 83 bytes
20 FD AE 20 9E AD 85 FC 20 A3 B6 A9 79 85 FB A0 00 84 FD B1 22 10 03 69 A0 18
45 FD 65 FB 85 FD E6 FB C8 C4 FC D0 EC E9 29 B0 FC 69 29 C9 1A 90 1C 29 0F C9
0D 90 04 69 09 90 12 C9 02 F0 0F C9 08 D0 04 A9 06 D0 06 C9 0C D0 02 A9 11 18
69 41 4C D2 FF
This is position-independent code, just put it somewhere in RAM and jump there, e.g. using the sys
command.
Online demo (loads to $C000
/49152
).
Usage: sys49152,"[name]"
, e.g. sys49152,"Aretha Franklin"
.
Important: If the program was load from disk (like in the online demo), issue a new
command first! This is necessary because loading a machine program trashes some C64 BASIC pointers.
Note: The C64 is by default in a mode without lowercase letters -- in order to be able to enter readable names, switch to lowercase mode first by pressing SHIFT
+CBM
.
Explanation
The challenge is in fact to find a minimal perfect hash function for these names; for the C64, I had to find one that's easily computable in simple 8bit operations. Here's a commented disassembly listing:
.C:c000 20 FD AE JSR $AEFD ; consume comma
.C:c003 20 9E AD JSR $AD9E ; evaluate expression
.C:c006 85 FC STA $FC ; save string length
.C:c008 20 A3 B6 JSR $B6A3 ; free string
.C:c00b A9 79 LDA #$79 ; value for adding during hashing
.C:c00d 85 FB STA $FB
.C:c00f A0 00 LDY #$00 ; offset for reading string
.C:c011 84 FD STY $FD ; and initial hash value
.C:c013 .hashloop:
.C:c013 B1 22 LDA ($22),Y ; read next character from string
.C:c015 10 03 BPL .xor ; if bit 8 set (shifted)
.C:c017 69 A0 ADC #$A0 ; translate to same unshifted character
.C:c019 18 CLC
.C:c01a .xor:
.C:c01a 45 FD EOR $FD ; xor with previous hash
.C:c01c 65 FB ADC $FB ; add offset
.C:c01e 85 FD STA $FD ; store new hash
.C:c020 E6 FB INC $FB ; increment offset
.C:c022 C8 INY
.C:c023 C4 FC CPY $FC
.C:c025 D0 EC BNE .hashloop ; repeat until last character
.C:c027 .modloop:
.C:c027 E9 29 SBC #$29 ; subtract $29 until
.C:c029 B0 FC BCS .modloop ; underflow, then
.C:c02b 69 29 ADC #$29 ; add once again ( => mod $29)
.C:c02d C9 1A CMP #$1A ; value in hash range?
.C:c02f 90 1C BCC .tochar ; -> output
.C:c031 29 0F AND #$0F ; mask lowest 4 bits only
.C:c033 C9 0D CMP #$0D ; greater 12 ?
.C:c035 90 04 BCC .fixedvals
.C:c037 69 09 ADC #$09 ; then just add 10 (9 plus carry)
.C:c039 90 12 BCC .tochar ; and done -> output
.C:c03b .fixedvals:
.C:c03b C9 02 CMP #$02 ; 2 becomes 3 by adding
.C:c03d F0 0F BEQ .tochar2 ; with carry (jump after the CLC)
.C:c03f C9 08 CMP #$08 ; if value was 8
.C:c041 D0 04 BNE .check2
.C:c043 A9 06 LDA #$06 ; new value is 6
.C:c045 D0 06 BNE .tochar ; and output
.C:c046 .check2:
.C:c047 C9 0C CMP #$0C ; else if value was 12
.C:c049 D0 02 BNE .tochar
.C:c04b A9 11 LDA #$11 ; new value is 17
.C:c04d .tochar:
.C:c04d 18 CLC
.C:c04d .tochar2:
.C:c04e 69 41 ADC #$41 ; add character code for 'a'
.C:c050 4C D2 FF JMP $FFD2 ; jump to kernal CHROUT routine
Test suite (C64 BASIC, containing the machine code routine in data
lines)
0fOa=49152to49234:rEb:pOa,b:nE:pO53272,23
1sY49152,"Aretha Franklin":?":Aretha Franklin"
2sY49152,"Ray Charles":?":Ray Charles"
3sY49152,"Elvis Presley":?":Elvis Presley"
4sY49152,"Sam Cooke":?":Sam Cooke"
5sY49152,"John Lennon":?":John Lennon"
6sY49152,"Marvin Gaye":?":Marvin Gaye"
7sY49152,"Bob Dylan":?":Bob Dylan"
8sY49152,"Otis Redding":?":Otis Redding"
9sY49152,"Stevie Wonder":?":Stevie Wonder"
10sY49152,"James Brown":?":James Brown"
11sY49152,"Paul McCartney":?":Paul McCartney"
12sY49152,"Little Richard":?":Little Richard"
13sY49152,"Roy Orbison":?":Roy Orbison"
14sY49152,"Al Green":?":Al Green"
15sY49152,"Robert Plant":?":Robert Plant"
16sY49152,"Mick Jagger":?":Mick Jagger"
17sY49152,"Tina Turner":?":Tina Turner"
18sY49152,"Freddie Mercury":?":Freddie Mercury"
19sY49152,"Bob Marley":?":Bob Marley"
20sY49152,"Smokey Robinson":?":Smokey Robinson"
21sY49152,"Johnny Cash":?":Johnny Cash"
22sY49152,"Etta James":?":Etta James"
23sY49152,"David Bowie":?":David Bowie"
24sY49152,"Van Morrison":?":Van Morrison"
25sY49152,"Michael Jackson":?":Michael Jackson"
26sY49152,"Jackie Wilson":?":Jackie Wilson"
27dA32,253,174,32,158,173,133,252,32,163,182,169,121,133,251,160,0,132,253,177
28dA34,16,3,105,160,24,69,253,101,251,133,253,230,251,200,196,252,208,236,233
29dA41,176,252,105,41,201,26,144,28,41,15,201,13,144,4,105,9,144,18,201,2,240
30dA15,201,8,208,4,169,6,208,6,201,12,208,2,169,17,24,105,65,76,210,255
Online demo of test suite.
Python 2, 68 bytes
def f(n):i=hash(n)%337%125%45;return chr(65+i-i/25*2-i/29*21+i/35*2)
Try it online!