Head, Shoulders, Knees and Toes, Knees and Toes

31

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

Kevin Cruijssen

Posted 2016-11-17T12:21:05.630

Reputation: 67 575

3Added 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. – Martin Ender – 2016-11-17T12:54:16.977

@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.

– Kevin Cruijssen – 2016-11-17T13:00:42.850

1Relevant meta post about usage of the tag. – Martin Ender – 2016-11-17T13:01:58.920

I think I found where this one drew inspiration from... – Erik the Outgolfer – 2016-11-17T15:06:56.657

@EriktheGolfer I had no idea someone else posted a similar question in the sandbox. I had searched for it on the non-meta site and couldn't find anything. I was actually inspired by it because a colleague of mine was in a very childish mood and was singing it (including actually touching the body parts.. >.>) Sorry @Neil, I really should learn to check the sandbox as well when I post a question.. (although yours is a bit different than the one I posted). – Kevin Cruijssen – 2016-11-17T15:11:16.687

1@KevinCruijssen At least your question caught some +1's :) (optimistic remark) You can search in the sandbox using inquestion:2140 shoulders. – Erik the Outgolfer – 2016-11-17T15:15:24.873

3Did anyone else got this song stuck in their head all day?... – Kevin Cruijssen – 2016-11-18T10:38:49.140

The usual practise for singing this song when I was younger was to sing it repeatedly and remove additional words each time. So second time would be "heads, shoulders, knees and _, knees and _" and so on. Would be interesting to add that in also :-D – Fogmeister – 2016-11-19T15:42:45.310

Answers

12

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).

Emigna

Posted 2016-11-17T12:21:05.630

Reputation: 50 798

4@KevinCruijssen: An explanation is ofc coming :) It's pretty mandatory for golfing languages imo. – Emigna – 2016-11-17T12:55:09.417

‡ä¾ØsÏ©s¸±s seems weird, considering that each word is 2 characters. Is it something else? – Erik the Outgolfer – 2016-11-17T15:03:44.227

2@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. – Emigna – 2016-11-17T15:09:42.750

Oh, they confused me. Thanks. – Erik the Outgolfer – 2016-11-17T15:10:19.713

31

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

Arnauld

Posted 2016-11-17T12:21:05.630

Reputation: 111 334

10

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()

Karl Napf

Posted 2016-11-17T12:21:05.630

Reputation: 4 131

1Very 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. – Kevin Cruijssen – 2016-11-17T13:31:59.127

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' :) – Kade – 2016-11-17T13:42:52.073

@Shebang Yeah, just had the same idea. – Karl Napf – 2016-11-17T13:45:32.070

@KevinCruijssen Thanks. I'm working on reducing the size. – Karl Napf – 2016-11-17T13:57:29.733

1you can just use c=int('602323'*2+'4517602323'[input()%22]) and drop the h c: – Rod – 2016-11-18T10:49:38.617

@Rod Thanks, but in total it is 1 byte longer :< – Karl Napf – 2016-11-18T11:58:55.880

@KarlNapf ??, I meant to replace the first 2 lines by that command, it's 5 bytes shorter. – Rod – 2016-11-18T12:05:12.893

@Rod h=[6,0]+[2,3]*2;c=(h*2+[4,5,1,7]+h)[i%22] = 41 bytes, c=int('602323'*2+'4517602323'[input()%22]) = 42 bytes. – Karl Napf – 2016-11-18T15:52:32.320

1[i%22] on the first, [input()%22] on the second – Rod – 2016-11-18T15:54:38.460

1@Rod Ah sorry, if you look at your code long enough you get blind. – Karl Napf – 2016-11-18T15:56:49.687

6

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.

Dom Hastings

Posted 2016-11-17T12:21:05.630

Reputation: 16 415

you can save 1 byte with x2)x2 instead of x2),@a – Adam – 2016-11-18T14:50:07.477

4

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

Kevin Cruijssen

Posted 2016-11-17T12:21:05.630

Reputation: 67 575

1String c(int i){return "head,shoulders,knees,toes,knees,toes,eyes,ears,mouth,nose".split(",")[(i+16)%22%16%10];} is only 112 bytes. – Neil – 2016-11-17T21:15:12.693

If you try to copy from the comment you get some extra invisible bytes courtesy of Stack Exchange. – Neil – 2016-11-17T22:44:24.513

@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! – Kevin Cruijssen – 2016-11-18T10:25:35.667

4

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 :)

Kade

Posted 2016-11-17T12:21:05.630

Reputation: 7 463

1I 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] – FlipTack – 2016-11-17T13:56:41.473

sorry, there should be a space after the 'nose' there :) – FlipTack – 2016-11-17T14:04:54.843

@Flp.Tkc Yeah I had just realized that :) Updating in a second! – Kade – 2016-11-17T14:07:34.033

3

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)

nmjcman101

Posted 2016-11-17T12:21:05.630

Reputation: 3 274

1You 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 – cleblanc – 2016-11-17T14:52:55.647

+1 And in addition to @cleblanc's suggestion, you can also change both && to &. – Kevin Cruijssen – 2016-11-17T14:54:34.673

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! – nmjcman101 – 2016-11-17T15:27:48.307

2

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')

Lmis

Posted 2016-11-17T12:21:05.630

Reputation: 421

1Nice! +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! – Kevin Cruijssen – 2016-11-17T13:26:55.717

1I 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]`. – Neil – 2016-11-17T15:02:51.650

2

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

CT14.IT

Posted 2016-11-17T12:21:05.630

Reputation: 231

-16 bytes: remove all ' around words, like 'head' becomes head etc. – insertusernamehere – 2016-11-17T15:31:11.170

Not sure what the rules are with this, but with a default PHP install, I get the expected undefined constant warnings when doing that – CT14.IT – 2016-11-17T15:35:11.300

1Yes, but this is absolutely fine with the site's rules. Notices and warnings can be ignored. – insertusernamehere – 2016-11-17T15:36:14.587

@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.

– manatwork – 2016-11-17T16:39:15.600

1It seems that str_split() is useless – Crypto – 2016-11-18T14:59:09.237

yes @Crypto <?=[head,shoulders,knees,toes,eyes,ears,mouth,nose]['0123230123234567012323'[$argv[1]%22]]; seems to work – Adam – 2016-11-18T23:19:36.213

2

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)

Billywob

Posted 2016-11-17T12:21:05.630

Reputation: 3 363

2

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.)

manatwork

Posted 2016-11-17T12:21:05.630

Reputation: 17 865

2

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"

milk

Posted 2016-11-17T12:21:05.630

Reputation: 3 043

1

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

Erik the Outgolfer

Posted 2016-11-17T12:21:05.630

Reputation: 38 134

1

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.

colsw

Posted 2016-11-17T12:21:05.630

Reputation: 3 195

1

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)

James Holderness

Posted 2016-11-17T12:21:05.630

Reputation: 8 298

1

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]}

Level River St

Posted 2016-11-17T12:21:05.630

Reputation: 22 049

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]} – manatwork – 2016-11-18T13:41:51.183

1

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

Pete Arden

Posted 2016-11-17T12:21:05.630

Reputation: 1 151

"it wouldn't let me do all the INSERT in one statement" why? Shouldn't something like this be possible in SQL after 2008?

– Kevin Cruijssen – 2016-11-18T13:30:19.193

@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... – Pete Arden – 2016-11-18T13:55:19.130

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. – Kevin Cruijssen – 2016-11-18T14:46:40.867

@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 :) – Pete Arden – 2016-11-18T15:17:48.823

1

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

Adam

Posted 2016-11-17T12:21:05.630

Reputation: 591

1

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.

brhfl

Posted 2016-11-17T12:21:05.630

Reputation: 1 291

0

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];

Link Ng

Posted 2016-11-17T12:21:05.630

Reputation: 593

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) – Kevin Cruijssen – 2016-11-18T15:34:48.493

0

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.

Wernisch

Posted 2016-11-17T12:21:05.630

Reputation: 2 534