What song is playing?

33

1

Inspired by this xkcd

enter image description here

You work for Shazam and they have a project for you. Some customers are complaining about their app taking up too much space on their phone, so they want you to code a lite version of the app. Unfortunately, your existing code can only understand the word "na", and you have to ship soon. That's okay, we'll do the best with what we've got.

The Challenge

You must write a full program that takes a user input, or takes a command line argument, and print the title and artist of the song. Since we are trying to fix customers complaining about program size, your code must be as short as possible. The input will be a string consisting entirely of na's, with a single space between them. Lowercase/uppercase is arbitrary. This is considered a valid input: Na Na nA na NA This is an invalid input: nah nah NA naNa banana You must determine what song is playing and print it out in exactly this format:

Song: <trackname>
Artist: <artist>

If the input is exactly 8 na's, this matches two separate songs, so you must print both:

Song: Batman Theme
Artist: Neal Hefti

and

Song: Na Na Hey Hey Kiss Him Goodbye
Artist: Steam

If the input is exactly 10 na's, you must print:

Song: Katamari Damacy
Artist: Yuu Miyake

If the input is exactly 11 na's, you must print:

Song: Hey Jude
Artist: The Beatles

If the input is 12 or more na's, you must print

Song: Land Of 1000 Dances
Artist: Wilson Pickett

Lastly, if the input is invalid, there are less than 8 na's, or any of the words are not "na", your program fails to understand the music. So logically, there is only one other song that it could possibly be. You must print:

Song: Africa
Artist: Toto

As usual, standard loopholes apply, and the shortest answer in bytes wins.

James

Posted 2015-12-28T01:51:30.143

Reputation: 54 537

2great background story! – TanMath – 2015-12-28T02:46:54.080

Isn't Hey Jude 12 nas? I just listened to it and I thought it was (in terms of note lengths) quarter quarter quarter quarter / eighth sixteenth sixteenth quarter-quarter-quarter / eighth sixteenth quarter-quarter-quarter, which is 12 nas. – Arcturus – 2015-12-28T03:31:17.553

4@Ampora onnnnnnnnne-one-three-one-a-two-threeeeeeeeeee-one-a-two-threeeeeeee-hey-jude definitely 11 – quintopia – 2015-12-28T05:00:14.277

1Batman is na na / na na / na na / na na x2 batman. I noticed that the second time I saw the comic. – wizzwizz4 – 2015-12-28T09:33:43.000

is na na na with a space in the beginning a valid input? – TanMath – 2015-12-28T18:03:59.073

@TanMath for simplicity's sake, we'll say no, you don't have to handle leading spaces. – James – 2015-12-28T18:25:54.367

DJ MC Mayhem? You are built for this challenge, aren't you. – Addison Crump – 2016-01-01T17:25:13.290

What about 9 nas? Do I print the Africa one? – nyuszika7h – 2016-01-09T17:17:54.360

@nyuszika7h yes. – James – 2016-01-10T01:30:04.780

I'm disturbed to find that Na na hey hey goodbye was by Steam and not originally Bananarama :P – Beta Decay – 2017-07-01T08:50:11.700

2It's 3 years too late to change the challenge, but I must object that the Katamari Damacy theme is titled "Katamari on the Rocks" (or if you're a purist, it's officially "Katamari on the Rocks ~ Main Theme") and thus shouldn't just be listed as just "Katamari Damacy"! – Value Ink – 2019-08-01T23:50:55.580

Answers

7

Retina, 242

Try it online!

iG`^na( na)*$
iM`na
m`^8$
>Batman Theme,Neal Hefti$n>Na Na Hey Hey Kiss Him Goodbye,Steam
m`^10$
>Katamari Damacy,Yuu Miyake
m`^11$
>Hey Jude,The Beatles
[0-9].+
>Land Of 1000 Dances,Wilson Pickett
m`^[0-9]
>Africa,Toto
>
Song: 
,
$nArtist: 

How it works:

IgnoreCase flag + Grep mode flag + Regex ^na( na)*$. If the input is valid, print it as is. If not, print nothing.

iG`^na( na)*$

IgnoreCase flag + Match mode flag + Regex na. Count the "na"s and print the number.

iM`na

If the string is exactly "8", replace by the second line.

m`^8$
>Batman Theme,Neal Hefti$n>Na Na Hey Hey Kiss Him Goodbye,Steam

If the string is exactly "10", replace by the second line.

m`^10$
>Katamari Damacy,Yuu Miyake

If the string is exactly "11", replace by the second line.

m`^11$
>Hey Jude,The Beatles

If the string matches [0-9].+, replace by the second line. This is neither true for single digit numbers, 10 and 11 as they already have been repaced nor any of the above replacement strings.

[0-9].+
>Land Of 1000 Dances,Wilson Pickett

If none of the above matched, the string still starts with a number. Default to Toto, Africa.

m`^[0-9]
>Africa,Toto

Replace the placeholders > and , by Song: and Artist:.

>
Song: 
,
$nArtist: 

Rainer P.

Posted 2015-12-28T01:51:30.143

Reputation: 2 457

5

JavaScript (ES6), 276 bytes

alert(`Song: `+([,`Batman Theme,Neal Hefti
Song: Na Na Hey Hey Kiss Him Goodbye,Steam`,,`Katamari Damacy,Yuu Miyake`,`Hey Jude,The Beatles`,`Land Of 1000 Dances,Wilson Pickett`][+prompt(i=0).replace(/na( |$)/gi,_=>++i)&&(i>11?4:i-7)]||`Africa,Toto`).replace(/,/g,`
Artist: `))

Explanation

Input can optionally contain one trailing space.

alert(                 // output the result
  `Song: `+([          // insert the "Song:" label
      ,                // set the first element to undefined in case input is empty

      // Songs
      `Batman Theme,Neal Hefti
Song: Na Na Hey Hey Kiss Him Goodbye,Steam`,
      ,
      `Katamari Damacy,Yuu Miyake`,
      `Hey Jude,The Beatles`,
      `Land Of 1000 Dances,Wilson Pickett`

    ][
      +                // if the input string was made up only of "na"s, the replace would
                       //     return a string containing only digits, making this return a
                       //     number (true), but if not, this would return NaN (false)
        prompt(        // get the input string
          i=0          // i = number of "na"s in input string
        ).replace(     // replace each "na" with a number
          /na( |$)/gi, // find each "na"
          _=>++i       // keep count of the "na"s and replace with a (non-zero) number
        )
      &&(i>11?4:i-7)   // select the song based on the number of "na"s
    ]
      ||`Africa,Toto`  // default to Africa
  ).replace(/,/g,`
Artist: `)             // insert the "Artist:" label
)

Test

var prompt = () => input.value;
var alert = (text) => result.textContent = text;
var solution = () => {

alert(`Song: `+([,`Batman Theme,Neal Hefti
Song: Na Na Hey Hey Kiss Him Goodbye,Steam`,,`Katamari Damacy,Yuu Miyake`,`Hey Jude,The Beatles`,`Land Of 1000 Dances,Wilson Pickett`][+prompt(i=0).replace(/na( |$)/gi,_=>++i)&&(i>11?4:i-7)]||`Africa,Toto`).replace(/,/g,`
Artist: `))

}
<input type="text" id="input" value="na na Na na NA na na nA" />
<button onclick="solution()">Go</button>
<pre id="result"></pre>

user81655

Posted 2015-12-28T01:51:30.143

Reputation: 10 181

This doesn't work for 9 na's, it outputs kamari. – Rɪᴋᴇʀ – 2015-12-28T22:57:36.567

@RikerW Fixed. I forgot a comma... – user81655 – 2015-12-28T23:35:08.417

4

PowerShell, 278 bytes

  • Can handle any amount of whitespace
  • No regex whatsoever!
  • Implicit typecasting FTW!
@{8='Batman Theme/Neal Hefti','Na Na Hey Hey Kiss Him Goodbye/Steam'
10='Katamari Damacy/Yuu Miyake'
11='Hey Jude/The Beatles'
12='Land Of 1000 Dances/Wilson Pickett'}[[math]::Min($args.Count*!($args|?{$_-ne'na'}),12)]|%{'Song: {0}
Artist: {1}'-f($_+'Africa/Toto'*!$_-split'/')}

Ungolfed

@{8='Batman Theme/Neal Hefti','Na Na Hey Hey Kiss Him Goodbye/Steam' # array
10='Katamari Damacy/Yuu Miyake'
11='Hey Jude/The Beatles'
12='Land Of 1000 Dances/Wilson Pickett'} # Hashtable of songs
[   # Get value by key from hashtable
    # If key is invalid, silently return null value

    [math]::Min( # Clamp max value to 12
        $args.Count* # Multiply count of argumens
                     # true/false will be cast to 1/0
            ! # Negate result of expression
              # Will cast empty array to 'false'
              # and non-empty array to 'true'
            (
                # Return non-empty array if input arguments
                # contain anything other than 'na'
                $args | Where-Object {$_ -ne 'na'} 
            ),
        12
    )
] | ForEach-Object { # Send value from hashtable down the pipeline,
                     # This allows to process arrays in hasthable values
    'Song: {0}
    Artist: {1}' -f ( # Format string
        $_+ # Add to current pipeline variable
            'Africa/Toto'*!$_ # If pipeline variable is empty,
                              # then add default song to it
                              # Example: 'Test'*1 = 'Test'
                              #          'Test'*0 = null
        -split '/' # Split string to array for Format operator
    )
}

Usage

PS > .\WhatSong.ps1 na na na na na na na na
Song: Batman Theme
Artist: Neal Hefti
Song: Na Na Hey Hey Kiss Him Goodbye
Artist: Steam

PS > .\WhatSong.ps1 Na na na na na na na na na Na
Song: Katamari Damacy
Artist: Yuu Miyake

PS > .\WhatSong.ps1 Na na na na na na na na na BanaNa
Song: Africa
Artist: Toto

beatcracker

Posted 2015-12-28T01:51:30.143

Reputation: 379

1

C (gcc), 403 395 370 365 bytes

-8 -5 bytes thanks to ceilingcat

Pretty much as straight-forward as can be.

f(char*s){int*a[]={"Neal Hefti","Steam","Yuu Miyake","The Beatles","Wilson Pickett","Toto","Batman Theme","Na Na Hey Hey Kiss Him Goodbye","Katamari Damacy","Hey Jude","Land Of 1000 Dances","Africa"},i=1,l=0,j=1;for(;*s;s+=s[2]?3:2)i=(*s|32)^'n'|(s[1]|32)^97|s[2]>32,l++;for(i=i?5:l^8?l^10?l^11?l>11?4:5:3:2:j++;j--;)printf("Song: %s\nArtist: %s\n",a[6+i--],a[i]);}

Try it online!

gastropner

Posted 2015-12-28T01:51:30.143

Reputation: 3 264

1

Rust, 501 477 bytes

fn main(){let(mut i,mut n)=(String::new(),0);let(s,a);std::io::stdin().read_line(&mut i);i=i.trim().to_lowercase();let o=i.split(" ");for w in o{if w!="na"{n=0;break}else{n+=1}}match n{8=>{println!("Song: Batman Theme\nArtist: Neal Hefti");s="Na Na Hey Hey Kiss Him Goodbye";a="Steam"}10=>{s="Katamari Damacy";a="Yuu Miyake"}11=>{s="Hey Jude";a="The Beatles"}_=>{if n>=12{s="Land Of 1000 Dances";a="Wilson Pickett"}else{s="Africa";a="Toto"}}}print!("Song: {}\nArtist: {}",s,a)}

Ungolfed

fn main() {
    let (mut input_string, mut na_counter) = (String::new(), 0);
    let (song_name, artist_name);

    std::io::stdin().read_line(&mut input_string);
    input_string = input_string.trim().to_lowercase();
    let output = input_string.split(" ");

    for word in output {
        if word != "na" {
            na_counter = 0;
            break;
        } else {
            na_counter += 1;
        }
    }

    match na_counter {
        8 => {
            println!("Song: Batman Theme\nArtist: Neal Hefti");
            song_name = "Na Na Hey Hey Kiss Him Goodbye";
            artist_name = "Steam";
        }
        10 => {
            song_name = "Katamari Damacy";
            artist_name = "Yuu Miyake";
        }
        11 => {
            song_name = "Hey Jude";
            artist_name = "The Beatles";
        }
        _ => {
            if na_counter >= 12 {
                song_name = "Land Of 1000 Dances";
                artist_name = "Wilson Pickett";
            } else {
                song_name = "Africa";
                artist_name = "Toto";
            }
        }
    }

    print!("Song: {}\nArtist: {}", song_name, artist_name);
}

Edit: removed an unnecessary to_string and type annotations

dragonite44

Posted 2015-12-28T01:51:30.143

Reputation: 91

1

Perl 5, 312 292 bytes

$_=lc<>;$n="(na ?)";/^(na ){7}na$|(na ){9,}na/ or$_="%Africa&Toto";s/$n{12,}/%Land Of 1000 Dances&Wilson Pickett/;s/$n{11}/%Hey Jude&The Beatles/;s/$n{10}/%Katamari Damacy&Yuu Miyake/;s/$n{8}/%Batman Theme&Neal Hefti\n%Na Na Hey Hey Kiss Him Goodbye&Steam/;s/&/\nArtist: /g;s/%/Song: /g;print

Try it online!

Ungolfed:

$_ = lc <STDIN>;
$_ =~ /^(na ){7}na$|(na ){9,}na/ or $_ = "%Africa&Toto";
$_ =~ s/(na ?){12,}/%Land Of 1000 Dances&Wilson Pickett/;
$_ =~ s/(na ?){11}/%Hey Jude&The Beatles/;
$_ =~ s/(na ?){10}/%Katamari Damacy&Yuu Miyake/;
$_ =~ s/(na ?){8}/%Batman Theme&Neal Hefti\n%Na Na Hey Hey Kiss Him Goodbye&Steam/;
$_ =~ s/&/\nArtist: /g;
$_ =~ s/%/Song: /g;
print $_

pslessard

Posted 2015-12-28T01:51:30.143

Reputation: 19

I missed some cases, working on a fix now – pslessard – 2019-08-01T20:47:20.817

1

Perl 5 -pa, 248 bytes

$_=/^(na ?)+$/&&(@F==8?",Batman Theme;Neal Hefti,Na Na Hey Hey Kiss Him Goodbye;Steam":@F==10?"Katamari Damacy;Yuu Miyake":@F==11?",Hey Jude;The Beatles":@F>11?",Land Of 1000 Dances;Wilson Pickett":0)||",Africa;Toto";s/;/
Artist: /gm;s/,/
Song: /gm

Try it online!

Xcali

Posted 2015-12-28T01:51:30.143

Reputation: 7 671

1

Python 453 440 406 380 bytes

EDIT: Thanks to Cyoce for reducing 13 bytes!

EDIT: Thanks again to Cyoce!

EDIT: Thanks to RainerP. for helping me imrpove the algorithm on certain invalid cases.

This is a rough draft of a Python program. I believe it can be definitely golfed, maybe to 300-400 bytes. But will work on that soon.

f=0
S='Song:'
A='\nArtist:'
l="Batman Theme,Neal Hefti,Na Na Hey Kiss Him Goodbye,Steam,Katamari Damacy,Yuu Miyake,Hey Jude,Beatles,Land of the 1000 Dances,Wilson Pickett,Africa,Toto".split(',')
s=raw_input().lower()+" "
n=s.count("na ")
n*=n*3==len(s)
if n>11:f=8
if n==10:f=4
if n==11:f=6
if n<8or n==9:f=10
if f:print S+l[f]+A+l[f+1]
else:print S+l[0]+A+l[1]+"\n"+S+l[2]+A+l[3]

Try here!

TanMath

Posted 2015-12-28T01:51:30.143

Reputation: 1 431

Instead of that lengthy list, use "Batman Theme,Neal Hefti,Na Na Hey Kiss Him Goodbye,Steam,Katamari Damacy,Yuu Miyake,Hey Jude,Beatles,Land of the 1000 Dances,Wilson Pickett,Africa,Toto".split(',') – Cyoce – 2015-12-28T22:48:43.860

Also: instead of if i not in ["n","a"," "]: ... I believe you can use if i not in 'na ': .... Additionally, if f==0: somecode; else: somemorecode can be reduced to if f: somemorecode; else: somecode (0 is Falsy) – Cyoce – 2015-12-28T22:55:26.957

Even more (I should have put these all in one, oh well): you have "\nArtist:" three times. try setting a variable, e.g. A="\nArtist:", then using A in place of the string literal. The same can be done with "Song:". Also, I think that if n<8or n==9:f=10 can be moved to the top of the if statements and changed to if n!=8:f=10 – Cyoce – 2015-12-28T23:13:35.103

Your program fails to detect invalid input. Output is Batman Theme instead of Africa for na na na nan na na na na. – Rainer P. – 2015-12-29T02:22:24.993

@RainerP. Thank you... I knew I was missing something... I am now working on an updated algorithm – TanMath – 2015-12-29T03:15:37.310

You can check the input string for validity with s=raw_input().lower()+" " n=s.count("na ") (Note the space after the na) n*=n*3==len(s). n will be 0 for invalid strings. – Rainer P. – 2015-12-29T16:03:06.017

@RainerP. Thank you, but my approach is to use str.split() to create a list of n "na" 's and count them. If one of the elements is not "na", then nothing is done and n=0 as defined in the beginning. Would that cover all types of invalid input? – TanMath – 2015-12-29T16:07:15.290

You won't need to set set n and i to 0 in the first line and you can drop the loop completely when using my type of check. – Rainer P. – 2015-12-29T16:14:53.650

@RainerP. so yours is shorter? – TanMath – 2015-12-29T16:16:33.813

Yes. If we add a space to the end and count "na " groups, the number of characters is three times the number of groups for any valid string and greater for any invalid one, so we don't need any additional checks. – Rainer P. – 2015-12-29T16:22:09.857

Also, your solution fails on certain invalid input as we discussed above. – Rainer P. – 2015-12-29T16:37:10.920

Let us continue this discussion in chat.

– TanMath – 2015-12-29T16:37:26.820

@RainerP. unless you do not want to... – TanMath – 2015-12-29T16:37:49.917

You can change raw_input() to input() and request the input has quotes around it. – caird coinheringaahing – 2018-03-18T11:28:13.347

1

sh + coreutils, 290

Albeit longer than my other submission, this one is straightforward and pretty much ungolfed, so i included it anyway.

grep -Ei "^na( na)*$"|wc -w|awk '{s="Song: ";a="\nArtist: ";p=s"Africa"a"Toto"}$1==8{p=s"Batman Theme"a"Neal Hefti\n"s"Na Na Hey Hey Kiss Him Goodbye"a"Steam"}$1>9{p=s"Katamari Damacy"a"Yuu Miyake"}$1>10{p=s"Hey Jude"a"The Beatles"}$1>11{p=s"Land Of 1000 Dances"a"Wilson Pickett"}{print p}'

How it works:

If the input is valid, print it as is. If not, print nothing.

grep -Ei "^na( na)*$"

Count the words.

wc -w

Simple look up table, Song: and Artist: are kept in variables.

awk '
    {s="Song: ";a="\nArtist: ";p=s"Africa"a"Toto"}
    $1==8{p=s"Batman Theme"a"Neal Hefti\n"s"Na Na Hey Hey Kiss Him Goodbye"a"Steam"}
    $1>9{p=s"Katamari Damacy"a"Yuu Miyake"}
    $1>10{p=s"Hey Jude"a"The Beatles"}
    $1>11{p=s"Land Of 1000 Dances"a"Wilson Pickett"}
    {print p}
'

Rainer P.

Posted 2015-12-28T01:51:30.143

Reputation: 2 457

I know it's been a while, but the regex can be shortened to ^(na ?)+$. – Kevin Cruijssen – 2018-02-20T08:25:48.577

1

Julia, 325 bytes

Probably could be golfed further.

p(s,a)=println("Song: $s\nArtist: $a");ismatch(r"^(na )*na$",ARGS[1])&&(c=length(split(ARGS[1],"na"))-1)==8?(p("Batman Theme","Neal Hefti"),p("Na Na Hey Hey Kiss Him Goodbye","Steam")):c==10?p("Katamari Damacy","Yuu Miyake"):c==11?p("Hey Jude","The Beatles"):c>=12?p("Land Of 1000 Dances","Wilson Pickett"):p("Africa","Toto")

nyuszika7h

Posted 2015-12-28T01:51:30.143

Reputation: 1 624

I know it's been a while, but the regex can be shortened to ^(na ?)+$. – Kevin Cruijssen – 2018-02-20T08:25:45.313

Also, the checks can be shortened a bit by using < and > instead of ==: &&(c=length(split(ARGS[1],"na"))-1)<9?(p("Batman Theme","Neal Hefti"),p("Na Na Hey Hey Kiss Him Goodbye","Steam"))c>11?p("Land Of 1000 Dances","Wilson Pickett"):c>10?p("Hey Jude","The Beatles"):c>9?p("Katamari Damacy","Yuu Miyake"):p("Africa","Toto"). Off-topic: I like your Avatar. Finished watching SAO last week. ;) – Kevin Cruijssen – 2018-02-20T08:32:06.737

0

Java 8, 353 bytes

s->{int n=s.split(" ").length,b=s.matches("(na ?)+")?1:0;s="Africa";return"Song: "+(b>0?n<8?s:n<9?"Batman Theme\nArtist: Neal Hefti\nSong: Na Na Hey Hey Kiss Him Goodbye":n>11?"Land of 1000 Dances":n>10?"Hey Jude":n>9?"Katamari Damacy":"":s)+"\nArtist: "+(b>0?n<8?"Toto":n<9?"Steam":n>11?"Wilson Pickett":n>10?"The Beatles":n>9?"Yuu Miyake":"":"Toto");}

Explanation:

Try it online.

s->{                             // Method with String as both parameter and return-type
  int n=s.split(" ").length,     //  The amount of words when split by spaces
      b=s.matches("(na ?)+")?1:0;//  Whether the input matches the regex "^(na ?)+$"
  s="Africa";                    //  Set the input we no longer need to "Africa"
  return"Song: "                 //  Return "Song: "
    +(b>0?                       //   +If the input matched the regex:
       n<8?                      //     If there are less than 8 "na"'s: 
        s                        //      Append "Africa"
       :n<9?                     //     Else-if there are exactly 8 "na"'s:
        "Batman Theme\nArtist: Neal Hefti\nSong: Na Na Hey Hey Kiss Him Goodbye"
                                 //      Append the String above
       :n>11?                    //     Else-if there are 12 or more "na"'s:
        "Land of 1000 Dances"    //      Append "Land of 1000 Dances"
       :n>10?                    //     Else-if there are exactly 11 "na"'s:
        "Hey Jude"               //      Append "Hey Jude"
       :n>9?                     //     Else-if there are exactly 10 "na"'s:
        "Katamari Damacy"        //      Append "Katamari Damacy"
       :                         //     Else (there are exactly 9 "na"'s):
        ""                       //      Append nothing
      :                          //    Else:
       s)                        //     Append "Africa"
    +"\nArtist: "                //   +Append a new-line and "Artist: "
    +(b>0?                       //   +If the input matched the regex:
       n<8?                      //     If there are less than 8 "na"'s:
        "Toto"                   //      Append "Toto"
       :n<9?                     //     Else-if there are exactly 8 "na"'s:
        "Steam"                  //      Append "Steam"
       :n>11?                    //     Else-if there are 12 or more "na"'s:
        "Wilson Pickett"         //      Append "Wilson Pickett"
       :n>10?                    //     Else-if there are exactly 11 "na"'s:
        "The Beatles"            //      Append "The Beatles"
       :n>9?                     //     Else-if there are exactly 10 "na"'s:
        "Yuu Miyake"             //      Append "Yuu Miyake"
       :                         //     Else (there are exactly 9 "na"'s):
        ""                       //      Append nothing
      :                          //    Else:
       "Toto");}                 //     Append "Toto"

Kevin Cruijssen

Posted 2015-12-28T01:51:30.143

Reputation: 67 575