It's fun to stay at the Y.M.C.A

15

"Y.M.C.A." is a popular disco song by the Village People that has a well-known dance. Write the shortest program to output the capital letters "Y", "M", "C", and "A" synchronized to the song's chorus.

Generally, one letter goes on each line sent to standard output. This primarily is to simplify programs subject to the output buffering of the C standard library (printing a newline flushes the output buffer), so you may omit any or all of these newlines if such omission would make your program shorter.

Your program, which is started at the same time as the music, must output the letter "Y" within 0.125 s of each of these times after starting (in seconds; I determined these from the music video posted on YouTube).

 45.766   49.611   60.889
 64.661  109.816  113.591
124.810  128.687  173.830
177.620  188.950  192.724
204.013  207.739  219.057

The letters "M", "C", and "A" respectively come 0.930 s, 1.395 s, and 1.628 s after each "Y". For testing purposes, these relative times are converted into absolute times by adding them to the time of the preceding "Y".

I have written a test program and corresponding example program in C that assume a newline follows each letter (although this is not a rule of competition). It is written for Linux and will not work on Windows without using Cygwin. If you cannot test your submission using the test program, at least check your submission against the YouTube video.

If your submission requires a special command-line option to behave properly, that command-line option counts when calculating your score. However, any interpreter startup time does not count against you, and the test program can be modified to accommodate that if necessary.

Although I doubt one exists, I must say that using a programming language function or library designed specifically for this task is prohibited.

PleaseStand

Posted 2012-07-21T13:59:37.837

Reputation: 5 369

Answers

3

C, 161 154 chars

#define P(d,x)w(d);puts(#x);
w(n){usleep(n<<16);}
y(d){P(d,Y)P(14,M)P(7,C)P(3,A)}
b(){y(664);y(35);y(147);y(35);}
main(){b(b(b(w(34))));y(148);y(33);y(148);}

The tester passes, but only if fflush(stdout); is added after each puts. Since the question clearly states that fflush is not required, I take it as a problem in the tester.

Logic:
w sleeps, the time is given in units of 16.384 65.536 ms. This resolution allows accurate enough timing and small constants (I should perhaps try 100ms).
P waits a while and prints a character.
y prints a YMCA sequence, after an initial delay.
b prints 4 YMCA sequences - this 4*YMCA happens 3 times, with similar enough timing.
main prints the 3*4*YMCA sequences, plus the remaining 3.

ugoren

Posted 2012-07-21T13:59:37.837

Reputation: 16 527

"a problem in the tester" - You're right, as apparently pipes are not "interactive" devices :( I will make it use a PTY (which should be more realistic) instead of a pipe as soon as I get the time to.

– PleaseStand – 2012-07-23T17:53:41.100

OK, I changed the tester to use a PTY, and your program passes the test. I also found out about a utility called stdbuf that uses some LD_PRELOAD trick to override the default buffering behavior of the C standard I/O library. – PleaseStand – 2012-07-26T21:00:51.400

4

Ruby 180 135 124 118 108 104

[458,k=22,*[97,k,435,k]*2,*[98,k]*2,98].flat_map{|e|[e,9,5,2]}.zip(%w(Y M C A)*15){|a,b|sleep a/1e1;p b}

Cristian Lupascu

Posted 2012-07-21T13:59:37.837

Reputation: 8 369

I just realized there is nothing in the rules prohibiting double quotes around each letter. However, the submission seems to work perfectly :) – PleaseStand – 2012-07-22T06:19:16.930

1

The second part of http://codegolf.stackexchange.com/questions/6695/its-fun-to-stay-at-the-y-m-c-a#comment14061_6696 is relevant to you too.

– JPvdMerwe – 2012-07-22T06:42:51.347

@JPvdMerwe Thanks a lot! You'e right. Dropping two decimals does not have any significant effect. Also, after I did that I noticed that if I tweak the values ±0.1 there are some patterns that allow the array to be constructed in less chars. – Cristian Lupascu – 2012-07-22T11:40:41.093

Could you do %w(Y M C A)*15 instead of 'Y M C A'.split*15 to generate the letters? Also that each could probably be a map even though you don't need the output. Oh, and you can write 10.0 as 1e1! – Paul Prestidge – 2012-07-22T22:42:46.307

@chron Thanks! I thought there was nothing much I could do to golf this code even more, but I was obviously wrong. :-) – Cristian Lupascu – 2012-07-23T06:43:28.290

Instead of using |j|a,b=j, you can use |a,b| directly, and you can save 1 character by assigning 22 to some variable the first time you use it. – Ventero – 2012-07-23T07:22:34.683

Additionally, using [458,k=22,*[97,k,435,k]*2,*[98,k]*2,98] to build the initial array saves another two characters. And flat_map{} is shorter than map{}.flatten. – Ventero – 2012-07-23T07:29:45.750

@Ventero Wow. The k=22 trick is much like GolfScript :. – Cristian Lupascu – 2012-07-23T08:19:32.803

Thanks everyone for the tips. I guess it's true what they say in the song: "No man does it all by himself". :-) – Cristian Lupascu – 2012-07-23T08:20:15.937

One last thing: You can pass a block to zip, so no need for the map. – Ventero – 2012-07-23T08:50:42.030

@Ventero edited. – Cristian Lupascu – 2012-07-23T09:31:10.733

0

Python2.6 (82)(214)(219)(196)(185)(152)

Fixed. Ran against the video & seems accurate. Saved quiet a few characters by reducing the precision from 3 to 2 in most of the cases(thanks for the tip @JPvdMerwe).

The only problem is that the tester shows a huge discrepancy in the timings. It starts out of sync & tries to come back into sync. In the two test cases it was more than 175 seconds out of sync at the beginning and came back to within 0.342 and 0.451 seconds of being back in sync.

import time;s=time.sleep
for t in[45.8,2.1,9.5,2,43.4,2,9.5,2.1,43.4,2,9.6,2,9.5,2,9.6]*15:
 i=0;s(t)
 while i<4:s([.1,.9,.5,.2][i]);print'YMCA'[i];i+=1

elssar

Posted 2012-07-21T13:59:37.837

Reputation: 579

Can you make it run at each of the fifteen times listed above? It also seems that on my machine, you will need to include the -u command line option in the count. – PleaseStand – 2012-07-21T15:22:20.463

@PleaseStand done, now it runs 15 times. I don't know about adding -u, don't need it on mine. I have Python2.6, if that helps – elssar – 2012-07-21T15:42:49.107

To clarify, your program should print the first "Y" after approximately 45.766 s, and -u is necessary for the tester program (which uses a pipe), not for output directly to a terminal. – PleaseStand – 2012-07-21T15:50:55.153

@PleaseStand Yeah, I was wondering about the timing. Was gonna ask you, but you already answered before I had a chance. And about the tester program, is it a requirement that the program runs on your tester as it is, or will you accept submissions that need to be modified to run on the tester, but run fine standalone? – elssar – 2012-07-21T16:27:32.703

Humm, I can pass my code to the tester without having to use any options – elssar – 2012-07-21T16:55:21.200

Interesting. I have Python 2.7, and the program (at least when run with -u) loses sync following the first "YMCA". https://gist.github.com/3156422

– PleaseStand – 2012-07-21T17:21:14.247

let us continue this discussion in chat

– PleaseStand – 2012-07-21T17:28:47.230

It's not just you. Mine is losing sync too. I must've fucked something up. Could swear it was working earlier. Back to the drawing board – elssar – 2012-07-21T17:33:25.783

You can replace 0.930 with 0.93 . Also you can make this quite a bit shorter by only having 2 digits after the decimal point. Doing this will only make a relative change of 0.009 at most which is far less than 0.125 . On this point you can sometimes remove 2 digits say 11.219 to 11.2, because that has a relative difference of 0.019 . The only thing you have to watch for is that you don't compound the differences to too much because of the fact that you have a second delay after the first one. – JPvdMerwe – 2012-07-22T06:38:08.077

Thanks @JPvdMerwe. It turns out that with you losing a few miliseconds in some cases and gaining a few in others, it pretty much balances out in the end. – elssar – 2012-07-22T09:11:57.173

import time followed by s=time.sleep is a bit shorter. – ugoren – 2012-07-23T14:18:09.427

@elssar: I will not count -u against you, as it is only necessary because of a "bug" in the test program. – PleaseStand – 2012-07-23T18:00:11.840

@uroren didn't know that, thanks! – elssar – 2012-07-24T06:50:20.077

0

Mathematica, 157

p=Print[Pause@#;#2]&

(#~p~"Y";.93~p~"M";.465~p~"C";.233~p~"A")&/@{45.766,2.217,9.65,2.144,43.527,2.147,9.591,2.249,43.515,2.162,9.702,2.146,9.661,2.098,9.69}

I watched the entire video to confirm the timing. Y M C A.... Y M C A...

It could be shorter with less precision, but then I'd have to watch the video again to confirm that it was not off by more than .125 at the end. lol

Mr.Wizard

Posted 2012-07-21T13:59:37.837

Reputation: 2 481