31
\$\begingroup\$

Introduction:

I think we all know it, and it has probably been translated in loads of different languages: the "Head, Shoulders, Knees and Toes" children song:

Head, shoulders, knees and toes, knees and toes
Head, shoulders, knees and toes, knees and toes
And eyes and ears and mouth and nose
Head, shoulders, knees and toes, knees and toes
wikipedia


Challenge:

Input: A positive integer.

Output: Output one of the following words based on the input as n-th index:

head
shoulders
knees
toes
eyes
ears
mouth
nose

Here the body parts are appended with the indexes:

Head (0), shoulders (1), knees (2) and toes (3), knees (4) and toes  (5)
Head (6), shoulders (7), knees (8) and toes (9), knees (10) and toes (11) 
And eyes (12) and ears (13) and mouth (14) and nose (15)
Head (16), shoulders (17), knees (18) and toes (19), knees (20) and toes (21)

Head (22), shoulders (23), knees (24) and toes (25), knees (26) and toes  (27)
Head (28), shoulders (29), knees (30) and toes (31), knees (32) and toes (33) 
And eyes (34) and ears (35) and mouth (36) and nose (37)
Head (38), shoulders (39), knees (40) and toes (41), knees (42) and toes (43)

etc.

Challenge rules:

  • You are of course allowed to use 1-indexed input instead of 0-indexed. But please specify which one you've used in your answer.
  • The output is case insensitive, so if you want to output it in caps that's fine.
  • You should support input up to at least 1,000.

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code.
  • Also, please add an explanation if necessary.

Test cases (0-indexed):

Input:  Output:
0       head
1       shoulders
7       shoulders
13      ears
20      knees
35      ears
37      nose
98      knees
543     nose
1000    knees
\$\endgroup\$
  • 3
    \$\begingroup\$ Added the kolmogorov complexity tag since most answers will probably use the input as a cyclic index into a constant array, whose generation will dominate the byte count. \$\endgroup\$ – Martin Ender Nov 17 '16 at 12:54
  • \$\begingroup\$ @MartinEnder Thanks. I, incorrectly, only used kolmogorov-complexity for answers that always have the same fixed output, but now I see that's it about fixed output-strings in the code, and finding patterns to golf it (or encode it like with @Enigma's 05AB1E answer). Thanks for adding it; I wasn't too sure what tags were relevant for this challenge, which was one of my (unfortunately unanswered) questions in the Sandbox. \$\endgroup\$ – Kevin Cruijssen Nov 17 '16 at 13:00
  • 1
    \$\begingroup\$ Relevant meta post about usage of the tag. \$\endgroup\$ – Martin Ender Nov 17 '16 at 13:01
  • 1
    \$\begingroup\$ @KevinCruijssen At least your question caught some +1's :) (optimistic remark) You can search in the sandbox using inquestion:2140 shoulders. \$\endgroup\$ – Erik the Outgolfer Nov 17 '16 at 15:15
  • 3
    \$\begingroup\$ Did anyone else got this song stuck in their head all day?... \$\endgroup\$ – Kevin Cruijssen Nov 18 '16 at 10:38

21 Answers 21

12
\$\begingroup\$

05AB1E, 36 35 34 bytes

“‡ä¾ØsÏ©s¸±s“#2䤫Г—íÖÇ©¢ÄÓ#s)˜è

Try it online! or as a Test suite

Explanation

“‡ä¾ØsÏ©s¸±s“                        # dictionary string 'head shoulders knees toes'
             #                       # split on spaces
              2ä                     # split in 2 parts
                ¤                    # get the last part ['knees', 'toes']
                 «                   # concatenate and flatten
                                     # STACK: [['head', 'shoulders'], ['knees', 'toes'], 'knees', 'toes']
                  Ð                  # triplicate
                   “—íÖÇ©¢ÄÓ        # dictionary string 'eyes ears mouth nose'
                             #s      # split on spaces and swap top 2 elements of stack
                               )˜    # wrap stack in a list and flatten
                                 è   # index into list with input

In short, we build the list ['head', 'shoulders', 'knees', 'toes', 'knees', 'toes', 'head', 'shoulders', 'knees', 'toes', 'knees', 'toes', 'eyes', 'ears', 'mouth', 'nose', 'head', 'shoulders', 'knees', 'toes', 'knees', 'toes'] and index into it with input (0-indexed).

\$\endgroup\$
  • 4
    \$\begingroup\$ @KevinCruijssen: An explanation is ofc coming :) It's pretty mandatory for golfing languages imo. \$\endgroup\$ – Emigna Nov 17 '16 at 12:55
  • \$\begingroup\$ ‡ä¾ØsÏ©s¸±s seems weird, considering that each word is 2 characters. Is it something else? \$\endgroup\$ – Erik the Outgolfer Nov 17 '16 at 15:03
  • 2
    \$\begingroup\$ @EriktheGolfer: Yes, the 3 s's are there to pluralize shoulder, knee, toe which are singular in the dictionary. We don't need that with eyes, ears as they're already pluralized in the dictionary so that string has the expected even length. \$\endgroup\$ – Emigna Nov 17 '16 at 15:09
  • \$\begingroup\$ Oh, they confused me. Thanks. \$\endgroup\$ – Erik the Outgolfer Nov 17 '16 at 15:10
31
\$\begingroup\$

JavaScript (ES6), 91 88 87 bytes

n=>'knees,toes,head,shoulders,eyes,ears,mouth,nose'.split`,`[(245890>>(n%22&~1))&6|n%2]

How it works

We have 4 distinct pairs of words that always appear together: 'head' is always followed by 'shoulders', 'knees' is always followed by 'toes', etc.

Therefore, we can use the following index:

00: [ 'knees', 'toes' ]
01: [ 'head', 'shoulders' ]
10: [ 'eyes', 'ears' ]
11: [ 'mouth', 'nose' ]

And compress the whole sequence (in reverse order) into the following binary mask:

00 00 01 11 10 00 00 01 00 00 01

We use [ 'knees', 'toes' ] as the first pair to get as many leading zeros as possible.

We pad this sequence with an extra 0 so that the extracted value is premultiplied by 2, which leads to:

0b00000111100000010000010 = 245890

Hence the final formula for the correct word:

(245890 >> (n % 22 & ~1)) & 6 | n % 2

Test cases

let f =

n=>'knees,toes,head,shoulders,eyes,ears,mouth,nose'.split`,`[(245890>>(n%22&~1))&6|n%2]

console.log(f(0));    // head
console.log(f(1));    // shoulders
console.log(f(7));    // shoulders
console.log(f(13));   // ears
console.log(f(20));   // knees
console.log(f(35));   // ears
console.log(f(37));   // nose
console.log(f(98));   // knees
console.log(f(543));  // nose
console.log(f(1000)); // knees

\$\endgroup\$
10
\$\begingroup\$

Python 2, 158 148 137 128 114 109 104 bytes

Lookup table seems better. Also shortened the big string and reordered the items. -5 bytes thanks to Rod for using string as a list.

c=int('602323'*2+'4517602323'[input()%22])
print"smkteehnhonoyaeooueeerasutesssdelhs"[c::8]+"ders"*(c<1)

initial solution:

n=input()%22
n-=10*(n>15)
if n>=12:n-=8
else:n%=6;n-=2*(n>3)
print"hskteemnehnoyaooaoeeerusduessste ls   h  d       e       r       s"[n::8].strip()
\$\endgroup\$
  • 1
    \$\begingroup\$ Very original answer! +1. But, umm..., most answers that use the complete strings are shorter than this. Still, I like the afford you took to see some kind of pattern in the strings! Chapeau for that. \$\endgroup\$ – Kevin Cruijssen Nov 17 '16 at 13:31
  • \$\begingroup\$ I think you can make this shoulder by making the string this: hskteemnehnoyaooaoeeerusduessste ls h d and then appending 'ers' if you know the word is supposed to be 'shoulders' :) \$\endgroup\$ – Kade Nov 17 '16 at 13:42
  • 1
    \$\begingroup\$ you can just use c=int('602323'*2+'4517602323'[input()%22]) and drop the h c: \$\endgroup\$ – Rod Nov 18 '16 at 10:49
  • 1
    \$\begingroup\$ [i%22] on the first, [input()%22] on the second \$\endgroup\$ – Rod Nov 18 '16 at 15:54
  • 1
    \$\begingroup\$ @Rod Ah sorry, if you look at your code long enough you get blind. \$\endgroup\$ – Karl Napf Nov 18 '16 at 15:56
6
\$\begingroup\$

Perl, 74 bytes

73 bytes code + 1 for -p.

$_=(@a=(head,shoulders,(knees,toes)x2),@a,eyes,ears,mouth,nose,@a)[$_%22]

Uses 0-based indexing. Doesn't output a separator, but that could be amended with -l in the flags.

Try it online.

\$\endgroup\$
  • \$\begingroup\$ you can save 1 byte with x2)x2 instead of x2),@a \$\endgroup\$ – Adam Nov 18 '16 at 14:50
4
\$\begingroup\$

Python 2, 97 90 Bytes

There may be some math that makes it so I don't have to make the word list, but this works for now!

lambda n,k='head shoulders '+'knees toes '*2:(k*2+'eyes ears mouth nose '+k).split()[n%22]

Thanks to Flp.Tkc for saving 7 bytes :)

\$\endgroup\$
  • 1
    \$\begingroup\$ I got a similar solution, but used split() to make it shorter: k='head shoulders '+'knees toes '*2 print(k*2+'eyes ears mouth nose'+k).split()[input()%22] \$\endgroup\$ – FlipTack Nov 17 '16 at 13:56
  • \$\begingroup\$ sorry, there should be a space after the 'nose' there :) \$\endgroup\$ – FlipTack Nov 17 '16 at 14:04
  • \$\begingroup\$ @Flp.Tkc Yeah I had just realized that :) Updating in a second! \$\endgroup\$ – Kade Nov 17 '16 at 14:07
4
\$\begingroup\$

Java 7, 155 137 131 123 111 110 bytes

String c(int i){return"knees,toes,head,shoulders,eyes,ears,mouth,nose".split(",")[(245890>>(i%22&~1))&6|i%2];}

-12 bytes thanks to @Neil.
-1 byte by shamelessly creating a port of @Arnauld's amazing answer.

Java is 0-indexed, so that's what I've used.

Ungolfed & test code:

Try it here.

class M{
  static String c(int i){
    return "knees,toes,head,shoulders,eyes,ears,mouth,nose".split(",")
      [(245890>>(i%22&~1))&6|i%2];
  }

  public static void main(String[] a){
    System.out.println(c(0));
    System.out.println(c(1));
    System.out.println(c(7));
    System.out.println(c(13));
    System.out.println(c(20));
    System.out.println(c(35));
    System.out.println(c(37));
    System.out.println(c(98));
    System.out.println(c(543));
    System.out.println(c(1000));
  }
}

Output:

head
shoulders
shoulders
ears
knees
nose
ears
knees
nose
knees
\$\endgroup\$
  • 1
    \$\begingroup\$ String c(int i){return "head,shoulders,knees,toes,knees,toes,eyes,ears,mouth,nose".split(",")[(i+16)%22%16%10];} is only 112 bytes. \$\endgroup\$ – Neil Nov 17 '16 at 21:15
  • \$\begingroup\$ If you try to copy from the comment you get some extra invisible bytes courtesy of Stack Exchange. \$\endgroup\$ – Neil Nov 17 '16 at 22:44
  • \$\begingroup\$ @Neil Ok, I'm an idiot.. No idea how I've counted rougly 120 yesterday evening late.. It was probably too late.. >.> Anyway, I've edited it (plus 1 additional byte by removing the space), so thanks! \$\endgroup\$ – Kevin Cruijssen Nov 18 '16 at 10:25
3
\$\begingroup\$

C, 153 bytes 141 bytes

*b[]={"head","shoulders","knees","toes","eyes","ears","mouth","nose"};i;char*g(a){a%=22;i=(a+4)%10;return b[a<4?a:(a&12)>8?a-8:i<2?i:a%2+2];}

Thanks to @cleblanc for 4 bytes. Declaring b globally throws a ton of warnings about casting to int, but didn't break for me.

Ungolfed:

*b[]={"head","shoulders","knees","toes","eyes","ears","mouth","nose"};
i;
char* g(a) {
    a%=22;
    i=(a+4)%10;
    return b[a < 4        ? a
            :(a & 12) > 8 ? a-8
            :i < 2        ? i
            :               a % 2 + 2];
}

It's not the smallest answer, but I liked the technique, and had fun finding a few patterns.

Changelog:

  • Moved b to global to avoid char (4 bytes)
  • a > 11 && a < 16 => (a & 12) > 8 (2 bytes)
  • i=(a-6)%10 => i=(a+4)%10 so that i < 2 && i >= 0 => i < 2 (6 bytes)
\$\endgroup\$
  • 1
    \$\begingroup\$ You can golf this down a bit further. By moving b[] to a global scope it can be declared without using char* like this *b[]={"head","shoulders","knees","toes","eyes","ears","mouth","nose"},i' and then replace the return b[...] with a puts(b[...]) you can get it down to 143 bytes \$\endgroup\$ – cleblanc Nov 17 '16 at 14:52
  • \$\begingroup\$ +1 And in addition to @cleblanc's suggestion, you can also change both && to &. \$\endgroup\$ – Kevin Cruijssen Nov 17 '16 at 14:54
  • \$\begingroup\$ I'm curious how @cleblanc suggestion about declaring b globally works. The compiler told me it would be an *int[], and I thought that the size difference would break the code. It didn't though, so thanks! \$\endgroup\$ – nmjcman101 Nov 17 '16 at 15:27
2
\$\begingroup\$

JavaScript (ES6) 91 89 Bytes

f=
n=>((d='head:shoulders:'+(b='knees:toes:')+b)+d+'eyes:ears:mouth:nose:'+d).split`:`[n%22]

console.log(f.toString().length)
console.log(f(0) === 'head')
console.log(f(1) === 'shoulders')
console.log(f(7) === 'shoulders')
console.log(f(13) === 'ears')
console.log(f(20) === 'knees')
console.log(f(35) === 'ears')
console.log(f(37) === 'nose')
console.log(f(98) === 'knees')
console.log(f(543) === 'nose')
console.log(f(1000) === 'knees')

\$\endgroup\$
  • 1
    \$\begingroup\$ Nice! +1. When I port your answer to Java 7 it's a solid -7 bytes compared to @Arnauld's already-shorter-than-mine answer. ;) Thanks! \$\endgroup\$ – Kevin Cruijssen Nov 17 '16 at 13:26
  • 1
    \$\begingroup\$ I saved a byte by being creative with my use of %: n=>`head:shoulders:knees:toes:knees:toes:eyes:ears:mouth:nose`.split`:`[(n+16)%22%16%10]. \$\endgroup\$ – Neil Nov 17 '16 at 15:02
2
\$\begingroup\$

R, 95 bytes

c(o<-c("head","shoulders",y<-c("knees","toes"),y),o,"eyes","ears","mouth","nose",o)[scan()%%22]

Creates a character vector to function as a lookup table. Takes input from stdin (1-indexed) and %%22 to find the corresponding body part.

Bonus: %% is vectorized which means that this will work with a vector inputs as well.

Test cases on R-fiddle (Note that this is a named function because scan doesn't work on R-fiddle)

\$\endgroup\$
2
\$\begingroup\$

jq, 80 characters

(77 characters code + 3 characters command line option)

((("head shoulders "+"knees toes "*2)*2+"eyes ears mouth nose ")*2/" ")[.%22]

Sample run:

bash-4.3$ jq -r '((("head shoulders "+"knees toes "*2)*2+"eyes ears mouth nose ")*2/" ")[.%22]' <<< 1000
knees

On-line test (Passing -r through URL is not supported – check Raw Output yourself.)

\$\endgroup\$
2
\$\begingroup\$

WinDbg, 207 157 151 bytes

ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41

-50 bytes by encoding the offset/length of the body parts as ascii chars.

-6 bytes by using a local var when looking up the offset/length.

Input is done with a value set in the pseudo-register $t0.

How it works:

* Initialization, writes this string at address 0x2000000. The nonsense after the body parts
* are the offsets and lengths of the body parts in the first part of the string, each of
* which is incremented by 0x41 to make it a printable ascii character.
ea 2000000 
        "headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";


* Display the output:
r$t4=(@$t0%16)*2+2000027
da1FFFFBF+by(@$t4) Lby(@$t4+1)-41

* Display output explanation:
r $t4 = (@$t0%16)*2+2000027   * Set $t4 = input, @$t0, mod 22, doubled +0x2000027
by(@$t4)                      * byte_at(@$t4)-0x41 is the {Offset} into the string 
                              * for the start of output. The -0x41 is already subtracted
                              * from 0x2000000 to make 0x1FFFFBF.
Lby(@$t4+1)-41                * byte_at(@$t4+1)-0x41 is the {Length} of the output.
da 1FFFFBF+{Offset} L{Length} * Display {Length} chars from {Offset} of the above string.

Sample output:

0:000> r$t0=0
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
02000000  "head"


0:000> r$t0=1
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
02000004  "shoulders"


0:000> r$t0=7
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
02000004  "shoulders"


0:000> r$t0=0n13
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
0200001a  "ears"


0:000> r$t0=0n20
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
0200000d  "knees"


0:000> r$t0=0n35
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
0200001a  "ears"


0:000> r$t0=0n37
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
02000023  "nose"


0:000> r$t0=0n98
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
0200000d  "knees"


0:000> r$t0=0n543
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
02000023  "nose"


0:000> r$t0=0n1000
0:000> ea2000000"headshoulderskneestoeseyesearsmouthnoseAEEJNFSENFSEAEEJNFSENFSEWE[E_FdEAEEJNFSENF";r$t4=(@$t0%16)*2+2000027;da1FFFFBF+by(@$t4) Lby(@$t4+1)-41
0200000d  "knees"
\$\endgroup\$
2
\$\begingroup\$

PHP, 91 102 118 128 129 Bytes

<?=[head,shoulders,knees,toes,eyes,ears,mouth,nose]['0123230123234567012323'[$argv[1]%22]];

0-Indexed

Down to 91 following removal of str_split, didn't realise PHP string were accessible as a char array (a PHP 5+ thing?)

Down to 102 thanks to insertusername suggestion for removing string quotes and allowing the notices

\$\endgroup\$
  • \$\begingroup\$ -16 bytes: remove all ' around words, like 'head' becomes head etc. \$\endgroup\$ – insertusernamehere Nov 17 '16 at 15:31
  • \$\begingroup\$ Not sure what the rules are with this, but with a default PHP install, I get the expected undefined constant warnings when doing that \$\endgroup\$ – CT14.IT Nov 17 '16 at 15:35
  • 1
    \$\begingroup\$ Yes, but this is absolutely fine with the site's rules. Notices and warnings can be ignored. \$\endgroup\$ – insertusernamehere Nov 17 '16 at 15:36
  • \$\begingroup\$ @CT14.IT, that is not a warning, is a notice. “PHP 5.3 or later, the default value is E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED. This setting does not show E_NOTICE, E_STRICT and E_DEPRECATED level errors.” – PHP documentation about error_reporting. \$\endgroup\$ – manatwork Nov 17 '16 at 16:39
  • 1
    \$\begingroup\$ It seems that str_split() is useless \$\endgroup\$ – Crypto Nov 18 '16 at 14:59
1
\$\begingroup\$

Jelly, 55 bytes

“¥ḷne“¥ṇṭḲ»ẋ2ṭ“¢1$“@⁼5⁼»µẋ2;“¥ḳVo“¥ḳ'k“£Qo“£³ạ»;⁸FḊḲ
ị¢

Try it online! (1-based index)

Come on! Really?

As a bonus, this is the compressed string I was supposed to use instead of the top line:

“¡¦ṡb[wfe=⁺żɦ4Gƈġhḳ"ẇ⁴ż>oH¹8ṡʠʠḟṀUṿḶ>¬Þ:ĖẇrṗṁɼlDṫỤ¬ȷ⁶Dḥci*⁻³GḲOÞạṖṃ\»

Both encode this string:

head shoulders knees toes knees toes head shoulders knees toes knees toes eyes ears mouth nose head shoulders knees toes knees toes

Guess I should go exercise now :P

\$\endgroup\$
1
\$\begingroup\$

Powershell, 91 Bytes, Zero-Indexed

$a='head shoulders '+'knees toes '*2;($a*2+'eyes ears mouth nose '+$a).Split()[$args[0]%22]

Very straightforward approach, generate the array of the first 22 items using some string multiplication where possible, by compiling them with spaces and splitting at the end. (splitting is 2 bytes shorter than the equivalent setup as an array) then just find the point in that array using the modulus of the input, not exactly interesting or language-specific.

Test Case:

PS C:\++\golf> 0..1000|%{.\hskt $_}
head
shoulders
knees
toes
knees
toes
head
shoulders
knees
toes
knees
toes
eyes
ears
mouth
nose
head
shoulders
knees
toes
knees
toes
head
shoulders
knees
toes
....

etc.

\$\endgroup\$
1
\$\begingroup\$

ruby, 81 bytes

Lambda function using zero indexing.

->n{("head shoulders#{" knees toes "*2}eyes ears mouth nose".split*2)[n%22-6&15]}

explanation

We generate the following array, of which we use the first 16 elements, covering the correct lines 2,3,4 of the song:

%w{head shoulders knees toes knees toes
   eyes ears mouth nose
   head shoulders knees toes knees toes

   eyes ears mouth nose}                  #last 4 elements not used

We take n modulo 22 to reduce it to a single verse, then we subtract 6. Now the index 6 (for example) has been changed to 0 and points to the right word. Indicies 0..5 which point to the first line of the song are now negative. We use &15 (identical to %16 but avoids the need for brackets) to map the 1st line of the song to the 4th line. Thus index 0 -> -6 -> 10

in test program

f=->n{("head shoulders#{" knees toes "*2}eyes ears mouth nose".split*2)[n%22-6&15]}

#call as below to test index 0..43
44.times{|i|p f[i]}
\$\endgroup\$
  • \$\begingroup\$ Interesting index formula. But the same length can be achieved without it: ->n{(((%w{head shoulders}+%w{knees toes}*2)*2+%w{eyes ears mouth nose})*2)[n%22]} \$\endgroup\$ – manatwork Nov 18 '16 at 13:41
1
\$\begingroup\$

Befunge, 129 119 bytes

0-indexed

&29+2*%:2/v>00p>%#7_v
+%2\-"/"g2<|<:-1g007<"head*shoulders*knees*toes*eyes*ears*mouth*nose"p00
02202246022>$$:>7#:%#,_@

Try it online!

Explanation

As Arnauld pointed out, the words come in pairs, so we have an index of just 11 values and then add the word number % 2 to get the appropriate word in the pair. The words are pushed onto the stack as a single string separated by asterisks to save space. We test for word breaks by taking the char value modulo 7, since only the asterisk is a multiple of 7.

&29+2*%               n = getint() % 22             // % 22 to ensure it's in range
:2/2g                 i = index_array[n/2]          // we use n/2 because words are paired
-"/"                  i -= '/'                      // convert from ASCII to 1-based value
\2%+                  i += n%2                      // get the correct word in the pair
00p                   index = i                     // save for later

"head*shoulders*knees*toes*eyes*ears*mouth*nose"    // push all the words onto the stack

700g1-:|              while (index-1 != 0) {        // the 7 is used in the drop loop   
  00p                   index = index-1             
  >%#7_                 do while (pop() % 7)        // drop up to the next '*' (%7==0)
                      }                    

$$                    pop();pop()                   // get rid of index and extra 7

: 7 % _               while ((c = pop()) % 7)       // output up to the next '*' (%7==0)
 > : ,                  putchar(c)
\$\endgroup\$
1
\$\begingroup\$

SQL 2005 747 Bytes

Golfed:

GO
CREATE PROCEDURE H @n INT AS BEGIN IF NOT EXISTS(SELECT*FROM R)BEGIN INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('eyes')INSERT INTO R VALUES('ears')INSERT INTO R VALUES('mouth')INSERT INTO R VALUES('nose')INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')END SELECT W FROM R WHERE I=@n%22 END

Ungolfed:

GO
CREATE PROCEDURE H
@n INT 
AS 
BEGIN IF NOT EXISTS(SELECT*FROM R)
BEGIN 
INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('eyes')INSERT INTO R VALUES('ears')INSERT INTO R VALUES('mouth')INSERT INTO R VALUES('nose')INSERT INTO R VALUES('head')INSERT INTO R VALUES('shoulders')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')INSERT INTO R VALUES('knees')INSERT INTO R VALUES('toes')
END 
SELECT W FROM R WHERE I=@n%22 END

Needs a table like this, where the first column is auto-incremented:

enter image description here

This is a one-indexed answer. The table is populated the first time stored procedure is created - it wouldn't let me do all the INSERT in one statement, disappointingly, this feature is only available in >=SQL 2008. After this, it uses the %22 trick from the other answers. Once the table has been populated, it only uses the last part:

SELECT W FROM R WHERE I=@n%22

Input:  Output:
R 1       head
R 2       shoulders
R 8       shoulders
R 14      ears
R 21      knees
R 36      ears
R 38      nose
R 99      knees
R 54      nose
R 1001    knees
\$\endgroup\$
  • \$\begingroup\$ "it wouldn't let me do all the INSERT in one statement" why? Shouldn't something like this be possible in SQL after 2008? \$\endgroup\$ – Kevin Cruijssen Nov 18 '16 at 13:30
  • \$\begingroup\$ @KevinCruijssen I'm using SQL Server 2008 R2, so it is strange... I've just done some more Googling, apparently it's something to do with the "Compatibility Level" of the database, which I've just tried and failed to change - it's set to 2005 and this is the max value, so it hasn't got this feature. Should I either, specify the SQL version in my answer, or delete the answer if it can't be shortened properly? Gutted as that would save me a lot of text... \$\endgroup\$ – Pete Arden Nov 18 '16 at 13:55
  • \$\begingroup\$ Either is fine by me, so it's your call. I personally usually golf in Java 7 which I specify, because in most cases shorter answers are available in Java 8. You could specify it's 2005 in the same way. \$\endgroup\$ – Kevin Cruijssen Nov 18 '16 at 14:46
  • \$\begingroup\$ @KevinCruijssen Yeah, I've seen people doing that for Java and Python. Wouldn't really like to make the change without being able to test the code either, so I'll specify 2005, cheers :) \$\endgroup\$ – Pete Arden Nov 18 '16 at 15:17
1
\$\begingroup\$

bash (with ed), 83 chars

1-indexed

ed<<<"a
head
shoulders
knees
toes
eyes
ears
mouth
nose
.
3,4t4
1,6y
6x
$(($1%22))"

Sample call:

 $ bash test.sh 1001
 knees
\$\endgroup\$
1
\$\begingroup\$

dc, 135 bytes

6[head]6[:add6-r;ar:adA+r;ar:a]dshx7[shoulders]7lhx8[knees]8lhxA 2;aAlhx9[toes]9lhxB 3;aBlhx[eyes]C:a[ears]D:a[mouth]E:a[nose]F:a22%;ap

Try it online!

Arrays in dc have to be built an element at a time, which takes up the brunt of this exercise. Since 'eyes', 'ears', 'mouth', and 'nose' only appear once in our array, we just pop them in. But for the others, we save a few bytes by putting them on the stack like x[head]x, where x is the middle of its three values, then we run the macro [:add6-r;ar:adA+r;ar:a]dshx to put it in the array, pull it back, put it in at the same value less six, pull it back, and then put it in one last time at the original value plus ten. We use the middle value because dc allows us to use hex digits even in decimal mode, and subtracting A is one less byte than adding 16 - this also only works because all of the middle values are under fifteen. We have to do knees and toes twice, and making our macro smart enough to sort that out is more expensive than just running the macro twice; but we do save bytes here by loading a previously stored copy of the string instead of writing it out again (B 3;aB vs. B[toes]B - I think this saves 3 bytes total).

Once we have the array built, all we need to do is 22% and then ;ap to pull it from the array and print.

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

C#6, 138 bytes

string F(int i)=>(i+10)%22<4?"eyes,ears,mouth,nose".Split(',')[(i+10)%22%4]:"head,shoulders,knees,toes,knees,toes".Split(',')[(i+6)%22%6];

repl.it demo

Ungolfed + comments:

string F(int i)=>
    // Is it eyes/ears/mouth/nose?
    (i+10)%22<4
        // If yes, then set index to 4-word line and take modular 4
        // String array constructed by splitting comma-delimited words
        ? "eyes,ears,mouth,nose".Split(',')
            [(i+10)%22%4]
        // Else set index to last 6-word line and take modular 6
        : "head,shoulders,knees,toes,knees,toes".Split(',')
            [(i+6)%22%6];
\$\endgroup\$
  • \$\begingroup\$ You could combine the string and use a single Split, and have your same check as ternary (?:) inside the square-brackets (with +4 for the second part), like this: string F(int i)=>"eyes,ears,mouth,nose,head,shoulders,knees,toes,knees,toes".Split(',')[(i+10)%22<4?(i+10)%22%4:(i+6)%22%6+4]; (126 bytes) \$\endgroup\$ – Kevin Cruijssen Nov 18 '16 at 15:34
0
\$\begingroup\$

Excel, 146 bytes

=MID("Head     ShouldersKnees    Toes     Eyes     Ears     Mouth    Nose",CHOOSE(MOD(MOD(MOD(B1+16,22),16),10)+1,1,10,19,28,19,28,37,46,55,64),9)

Uses @Neil's MOD(MOD(MOD(B1+16,22),16),10) to save 15 bytes.

\$\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.