88

The challenge

The shortest code by character count to output a part of a piano keyboard starting from input note in a given length.

Input will be composed of a note ([ACDFG]#|[A-G]) to start printing the keyboard from and a positive number representing length of keys to print including the first note.

The first key should be printed in full - if it has a left sharp key, it will be cut, same for when the start key is sharp, the left key will be cut as well.

A Sharp key is not counted, only white keys.

Test cases

Input
    C 14
Output
    |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
    |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
    |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
    |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
    |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |
    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |
    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |
    |____|____|____|____|____|____|____|____|____|____|____|____|____|____|

Input
    D# 1
Output
    ###   |
    ###   |
    ###   |
    ###   |
    ###   |
     |    |
     |    |
     |    |
    _|____|

Input
    A 7
Output
    ##  ###   |   ###  ###   |   ###  ##
    ##  ###   |   ###  ###   |   ###  ##
    ##  ###   |   ###  ###   |   ###  ##
    ##  ###   |   ###  ###   |   ###  ##
    ##  ###   |   ###  ###   |   ###  ##
    |    |    |    |    |    |    |    |
    |    |    |    |    |    |    |    |
    |    |    |    |    |    |    |    |
    |____|____|____|____|____|____|____|

Code count includes input/output (i.e full program).

LiraNuna
  • 64,916
  • 15
  • 117
  • 140
  • So it doesn't count sharp keys for displaying them, but it can start on a sharp key? – Nick Larsen Feb 04 '10 at 20:28
  • 5
    `[A-G]#*`? Does this mean we need to handle, say, `B#####` as `E`? – Anon. Feb 04 '10 at 20:29
  • 5
    For the count of keys, define "key". Why is the example "C 14" printing 24 keys? – Guffa Feb 04 '10 at 20:30
  • What Guffa said. I'd rather see a question which took the count in semitones. –  Feb 04 '10 at 20:35
  • @Anon. & @Guffa - Sorry, my bad at both. – LiraNuna Feb 04 '10 at 20:38
  • "I'd rather see a question which took the count in semitones" Then the question will get much harder... – LiraNuna Feb 04 '10 at 20:46
  • Beware of the special case where the starting note is a sharp note and the count is one. Perhaps you should add that as a test case, LiraNuna. – Guffa Feb 04 '10 at 21:22
  • @LiraNuna: Wait, perhaps there is no special case there. I was thinking of counting also black keys, then a single black key would show half white keys on both sides... – Guffa Feb 04 '10 at 23:08
  • 53
    OK, now that we got C and C# solutions, we need B, D and F#. – LiraNuna Feb 05 '10 at 00:12
  • echo "Cannot play piano nor read tunes" - there, in 37 characters including whitespace!!! :D – t0mm13b Feb 05 '10 at 01:43
  • @Austin Kelley Way, do you know J? – John La Rooy Feb 05 '10 at 19:51
  • 7
    Next code golf: Implement a MIDI interface for these pianos. – Mehrdad Afshari Feb 05 '10 at 21:48
  • No, though I probably could write it. – Catharsis Feb 06 '10 at 20:41
  • Please don't add 'summery of answers', looking at the answer list should be sufficient... – LiraNuna Feb 07 '10 at 00:38
  • 3
    Here I am back to my old tricks again. Dear close voters: I agree that code golf questions are contests, not questions. None-the-less, this topic has been discussed at length on meta and the belongs on SO side has a solid consensus: http://meta.stackexchange.com/questions/20912/so-weekly-code-golf . SO let it go. See also: http://meta.stackexchange.com/questions/24242/acceptable-level-of-code-golf-questions . – dmckee --- ex-moderator kitten Feb 07 '10 at 01:01
  • dmckee: Instead of arguing, I suggest to just let them close - I'm sure people will reopen it in less than a minute. – LiraNuna Feb 07 '10 at 01:54
  • 1
    Open fire all opening batteries! don't let this hole in their defenses get closed! ;) – RCIX Feb 08 '10 at 08:21
  • 10
    Dear closers, I salute you for managing to close this challenge after 3 days. We got it to reopen in 5 minutes. That alone should tell you something - the community likes and accepts this kind of questions, whether you like it or not. If you don't, however, please add code-golf to your list of ignored tags. – LiraNuna Feb 08 '10 at 08:23

22 Answers22

112

Perl, 133 (129) chars

Perl, 167 160 156 147 142 133 D'oh! 147 144 137 134 133 chars

    $_=shift;die grep{5>$n?y/*/#/:y/#*/ |/;$n++-8||y/ /_/}
    @Q=(substr(("*#  #".("*#  #*#   |   #")x2)x9,
    4*/#/+(7&ord)*5,1+/#/+5*pop).$/)x9

Here's a 129 char solution, borrowing several ideas from molf's Ruby solution:

    ($_,$c)=@ARGV;$j=($k=/#/)+ord;
    for$n(0..8){print$/,substr+(join'',map{8-$n?5>$n&&$_%7%4?"###  "
    :" |   ":"_|___"}$j..$j+$c),!$k,-3}

and with help from the Acme::AsciiArtinator:

                sub init_piano{$S=$";$H='#';
                (                            $
               T                              ,$P,$U)=qw(
              T                                          |
             _                                            |
            /                                              )
           ;                                                $
          d             =$T.$H.$S.$S;$t                     =
         $             d               .                   $H
        .              $               d                  . $
       S               .$P.$S.$S.$S.$H;$                t=  $
      d.$H.$t.$t;};$_=shift;-/-/;&init_piano();$Z=/#/;-/|   |
      |                                                 |   |
      |                    YAMAHA                       |  /
      ;die grep{4>$n++?y/T/#/:y/#T/ |/;$n-8||y/ /_/;}@q=(m{
     // // /// // /// // /// // /// // /// // /// // /// /   
    // // /// // /// // /// // /// // /// // /// // /// /
   }                                                   .
   substr(${t}x(9),4*${Z}+(7&ord)*5,1+$Z+5*pop).$/)x(8)
          ;   '                            \   /
           | |                              | |
           /_\                              /';
mob
  • 117,087
  • 18
  • 149
  • 283
34

Ruby - 125 chars

146 144 140 137 134 126 125 chars

a,n=$*;h=a[1]?0:1;s=a[0]-h+1
9.times{|t|puts (s..s+n.to_i).map{|i|i%7%4<1||t>4?" |   ":"###  "
}.join[h..-4].tr t>7?" ":n,"_"}

(The second newline is not necessary and added only to avoid a scrollbar on SO. Semi-colons can be replaced by newlines if desired.)

The Ruby 1.9 version is different but of equal length (replacing a[0] by a.ord and "_" by ?_):

a,n=$*;h=a[1]?0:1;s=a.ord-h+1
9.times{|t|puts (s..s+n.to_i).map{|i|i%7%4<1||t>4?" |   ":"###  "
}.join[h..-4].tr t>7?" ":n,?_}

Call with

$ ruby piano.rb C 14
Community
  • 1
  • 1
molf
  • 73,644
  • 13
  • 135
  • 118
  • Hey VIM counts 138 chars on the first one?!? – hurikhan77 Feb 05 '10 at 22:39
  • a,n=gets.split;... does the same job, -3 chars – hurikhan77 Feb 05 '10 at 22:54
  • 1
    You could even replace "gets.split" by "$*" and give the input on the command line, -8 chars – hurikhan77 Feb 05 '10 at 23:17
  • Change `i%7%4<1||t>4?"_|___":"###__"` to `i%7%4&&t<5?"###__":"_|___"` and save 2 chars. I love that `%7%4` idiom – mob Feb 06 '10 at 05:43
  • You can save 2 additional chars by replacing `"_"` by `?_` and removing the parentheses around the call to `tr` at the end (replacing the first parenthesis by a space). – JRL Feb 06 '10 at 09:51
  • @hurikhan77: awesome change! @mobrule: unfortunately (in this case) `0` is truthy in Ruby, so that won't work. @JRL: `?_` is a Fixnum (char code), and not a string in Ruby 1.8, but it does work in 1.9! Thanks! – molf Feb 06 '10 at 16:27
  • 1
    So we are down to the shortest solution, eh? Ruby rulez! :-D – hurikhan77 Feb 06 '10 at 22:30
  • My ruby answer is up if you guys like to take a look if I've missed anything :) http://stackoverflow.com/questions/2202897/code-golf-piano/2220265#2220265 – John La Rooy Feb 08 '10 at 08:20
29

LilyPond, 285 288 291 310 315 330 333 340 350 characters

In keeping with the music theme, here's a solution in a language designed for typesetting music scores, LilyPond:

x=#ly:string-substitute
u=#(x"*""###  ""|   *** |   ** ")t=#(x"###"" | "u)q=#read-char
z=#(q)v=#(if(eq?(q)#\#)1 0)y=#(iota(+(*(read)5)1 v))#(format #t"~{~{~a~}
~}"(map(lambda(s)(map(lambda(i)(string-ref s(modulo(+(*(char->integer z)5)i(* v
4))35)))y))(list u u u u u t t t(x" ""_"t))))

Usage: $ lilypond thisfile.ly <input.in >output.out 2>/dev/null

KirarinSnow
  • 1,062
  • 2
  • 9
  • 22
  • 4
    this is possibly the first and only time I've seen LilyPond used in code golf. – cobbal Feb 05 '10 at 08:19
  • 3
    @cobbal: See also http://stackoverflow.com/questions/1433263/decision-tree-code-golf/1584216#1584216, http://stackoverflow.com/questions/1575096/code-golf-musical-notes/1584160#1584160, http://stackoverflow.com/questions/383403/code-golf-print-the-entire-12-days-of-christmas-song-in-the-fewest-lines-of-co/1905327#1905327 (shorter than any other solution), http://golf.shinh.org/p.rb?Counting+adventure – KirarinSnow Feb 05 '10 at 12:17
27

GolfScript - 80 Characters

Fits in one line of #SO without the scroll bar :)

' ':s/~~5*\(7&5*\,.4*@+):k;+):c;9,{5<'#'9**' | '4*+3/4<.1>+c*s.+*k>c<n+}%)s/'_'*

GolfScript - 81 Characters

' ': /((7&\,.4*@5*+:k;\~~5*+):c;9,{5<'#'9**' | '4*+3/4<.1>+c*  +*k)>c<n+}%) /'_'*

Nicely formatted version (27 x 3)

' ': /((7&\,.4*@5*+:k;\~~5*
+):c;9,{5<'#'9**' | '4*+3/4
<.1>+9*  +*k)>c<n+}%) /'_'*

GolfScript - 82 Characters

' '/((7&\,.4*@5*+:k;\~~5*+):c;9,{5<3*'###  '*' |   '4*+20<.5>+c*k)>c<n+}%)' '/'_'*

GolfScript - 85 Characters

' '/((7&\,.4*@5*+:k;\~~5*+):c;9,{.5<3*'###  '*' _'1/@8=='|'1$3*++4*+20<.5>+c*k)>c<n}%

Nicely formatted version (17 x 5)

' '/((7&\,.4*@5*+
:k;\~~5*+):c;9,{.
5<3*'###  '*' _'1
/@8=='|'1$3*++4*+
20<.5>+c*k)>c<n}%

GolfScript - 94 Characters

' ': /~~5*:c;(7&5*:^;,:&;['###  '3*' |   '+.5>+c*1>{^4&*+>&c+)<n}:f~]5*'   _'1/{'|'\4*+7*c*f}%

GolfScript - 98 Characters

' ': /~~5*:c;(7&5*:^;,:&;['###  '3*' |   '+.5>+c*^4&*+:^)>&c+):&<n]5*[   '_']{['|'\4*+7*c*^>&<n]}%

GolfScript - 101 Characters

' ': /~~5*:c;(7&5*:^;,:&;['###  '3*' |   '+.5>+c*^4&*+)>&c+)<n]5*[   '_']{['|'\4*+7*c*^4&*+>&c+)<n]}%

GolfScript - 109 Characters

' ': /~~5*:c;(7&5*:^;,:&;['##''  ###'.'   | '++.'  #'+++c*^4&*+>&c+)<n]5*[   '_']{['|'\4*+7*c*^4&*+>&c+)<n]}%

GolfScript - 120 Characters

' '/~~5*:c;(7&5*:^;,:&;['##''  ###'.'   | '++.'  #'+++c*^4&*+>&c+)<n]5*['|    '7*c*^4&*+>&c+)<n]3*'|____'7*c*^4&*+>&c+)<

GolfScript - 127 Characters

' '/~~5*:c;(7&5*:^;,:&;['##  ###  ###   |   ###  ###   |   #'c*^4&*+>&c+)<n]5*['|    '7*c*^4&*+>&c+)<n]3*'|____'7*c*^4&*+>&c+)<

$ echo -n C 14 | ruby golfscript.rb piano.gs 
|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|____|____|____|____|____|____|____|____|____|____|____|____|____|____|
$ echo -n D# 1| ruby golfscript.rb piano.gs 
###   |
###   |
###   |
###   |
###   |
 |    |
 |    |
 |    |
_|____|
$ echo -n A 7| ruby golfscript.rb piano.gs 
##  ###   |   ###  ###   |   ###  ##
##  ###   |   ###  ###   |   ###  ##
##  ###   |   ###  ###   |   ###  ##
##  ###   |   ###  ###   |   ###  ##
##  ###   |   ###  ###   |   ###  ##
|    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |
|____|____|____|____|____|____|____|
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • I was about to submit my first golfscript entry for another challenge (http://stackoverflow.com/questions/2104556/code-golf-0-to-1-and-1-to-0-closed), but it got closed :-( – mob Feb 05 '10 at 06:33
  • 2
    I wish they taught golfscript in school. I want my money back. – Steve Tjoa Feb 05 '10 at 07:10
  • 6
    Nice. I'll post my solution in PianoScript later. It's only 6 characters. :-) – molf Feb 05 '10 at 12:31
26

RetroGolf - Applesoft BASIC: 236 239 245 249 257 245 267 285

Shown in multiple lines for readability, but should be a single line:

1K$="##   |   ###  #":K$="##  #"+K$+K$:
 FORI=1TO21:F$=F$+"|____":L$=L$+"|    ":NEXT:
 INPUTN$:S=MID$(N$,2,1)="#":O=(ASC(N$)-65)*5+1+S*4:L=VAL(RIGHT$(N$,2))*5+1+S:
 FORI=1TO5:?MID$(K$+K$+K$,O,L):NEXT:FORI=1TO3:?MID$(L$,O,L):NEXT:?MID$(F$,O,L)

Can be tested with this Applesoft BASIC Interpreter in Javascript or an emulator.

Zoe
  • 27,060
  • 21
  • 118
  • 148
Carlos Gutiérrez
  • 13,972
  • 5
  • 37
  • 47
18

C# - 315

I persist to golf in C# although it's not a very terse language...

using C=System.Console;class P{static void L(int o,int c,string s){while(c-->0)C.Write(s[(420>>o++%5*2&3)+(91>>(o+2)/5%7&1)*3]);C.WriteLine();}static void Main(string[]a){int i=0,s=a[0].Length-1,c=int.Parse(a[1])*5+1+s,o=(a[0][0]-65+s)*5-s;while(i++<5)L(o,c,"|  ## ");while(i++<8)L(o,c,"|  |  ");L(o,c,"|__|__");}}
Community
  • 1
  • 1
Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • 23
    Now for the F# solution to complete the melody. – LiraNuna Feb 04 '10 at 22:53
  • 13
    +1 for humor, -1 for corny humor, and +1 since C# and F# are concordant. – Steve Tjoa Feb 05 '10 at 02:00
  • I got an System.IndexOutOfRangeException when tried to run it. – Fitzchak Yitzchaki Feb 05 '10 at 07:52
  • @Mendy: You have to supply command line arguments when you run it. If you run it from Visual Studio, open the properties for the project, go to the debug tab and under Start Options you can enter command line arguments. If you have compiled the code into an exe, just run it from a console window with the arguments after the program name. – Guffa Feb 05 '10 at 08:31
  • +1 and I hate you. You're C# version is shorter than my F# one! – Benjol Feb 05 '10 at 12:17
  • 1
    Very nice use of the --> operator. – Kevin Feb 08 '10 at 13:52
16

Python - 164

k,n=raw_input().split()
m=k[1:]>""
n=int(n)*5+1
o=(ord(k[0])-65)*5+4*m
for x in["##  ###   |   ### "]*5+[n*"|    "]*3+[n*"|____"]:print((x+x[::-1][:-1])*n)[o:o+n+m]
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • Couldn't you save some characters by removing the repeated part of `t` and `u` and multiplying by 7? – Matthew Crumley Feb 04 '10 at 21:05
  • @Matthew Crumley, feel free to borrow from my solution :) – John La Rooy Feb 04 '10 at 21:20
  • @gnibbler, I'm not really a python programmer (I've played around with it some, but not extensively) so I doubt I would be able to do much with it. I didn't even know python could multiply strings like that until I saw your original solution. – Matthew Crumley Feb 04 '10 at 21:33
  • @gnibbler - nice solution, would love to run it but getting a SyntaxError.... C 14 Traceback (most recent call last): File "piano.py", line 1, in ? k,n=input().split() File "", line 1 C 14 ^ – AJ. Feb 04 '10 at 22:19
  • @AJ, looks like that error is from the Python3 solution. Not sure why you are getting that though – John La Rooy Feb 04 '10 at 22:33
  • @gnibbler - because I was being dumb and copied your p3k solution and ran it in 2.6 :p – AJ. Feb 05 '10 at 02:24
15

Octave, 153 154 155 158 159 162 172 180 186 185 188 197 199 200 206 207 209 212 214 215 219 240 244 268 characters

Why use just C or C# or F# (or B or D) when you can program with a full Octave?

(wrapped every 60 chars for clarity)

x=5*scanf("%2c%d");for k=-8:0disp((s={[t="|   ###  ###  ","#
##   ",t" "]"|    ","|____"}{(k>-4)+!k+1})(1+mod(5*(y=x(2)>1
60)+(-y:x(3))+x(1),rows(s'))))end

Yes ... this solution really does compute the complex conjugate transpose of a string.

Usage: $ octave -q thisfile.m <input.in >output.out

KirarinSnow
  • 1,062
  • 2
  • 9
  • 22
13

C — 197 203 207 216 224 232 240 characters

#define S"#   |   ###  ###  ##"
main(i,j,l,h,t){char*X[]={"____|","    |",S S,S S},s[i=11];for(scanf("%s%n%d",s,&h,&l);--i>1;puts(""))for(j=t=*s%7*5+h*4;j<t+l*5+h;putchar(X[i/3][j++%(i>5?35:5)]));}

This equivalent 194-character version assumes buffer overflow is fine.

#define S"#   |   ###  ###  ##"
i=11;main(j,l,h,t){char*X[]={"____|","    |",S S,S S},s;for(scanf("%s%n%d",&s,&h,&l);--i>1;puts(""))for(j=t=s%7*5+h*4;j<t+l*5+h;putchar(X[i/3][j++%(i>5?35:5)]));}
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
Chris Dodd
  • 2,920
  • 15
  • 10
  • 1
    `for(j=0; j<=l*5+h; j++)` <- useless spaces, and you seem to have included them in the character count too – Nicolás Feb 05 '10 at 00:27
12

PostScript: 239 245 293 312 (regular); 219 224 225 231 (ASCII85)

/r{(%stdin)(r)file token pop}def[(]){mul add}/z r(:-)cvs dup length 1
sub/v exch/p r/s(|   ###  ###  ###   |   ###  ###   )([){0 1 v p 5]{s
exch z 0 get 5]v 4]s length mod 1 getinterval print}for/
=}>>begin[[[[[/s(|    )def[[[/s(|____)def[

Binary version expanded through ASCII85 encoding into a 219-character program with only ASCII printable characters:

/(|____)/(|    )[/r/(|   ###  ###  ###   |   ###  ###   )<~Ou%G5-$+0=Bl5@JE[d/;P,jagI?HCK@<*JGP,4<rOuSV60p8LhG*5%O8oc=a.=3b)!HsVu23Md=!IHJ_A<K->@5*j;23Md=!HoSBP&-9^09Tk/@ZkI\P"_$^I?I,S+?b-:5*?@Z>?b<9Ou$<H>EUc~>cvx
exec[

Usage: $ gs -q -dNOPROMPT -dNODISPLAY -dBATCH thisfile.ps <input.in >output.out

KirarinSnow
  • 1,062
  • 2
  • 9
  • 22
12

F#: 224 225, 226, 248, 252, 270, 276, 299, 306 Chars

let x,(/)=System.Console.ReadLine(),String.replicate
let t,p=(int x.[0]-60)%7*5,int x.[1]%2
let g s i=printf"%s"(i/((99/s).[t+4*p..t+int x.[2..]*5+5*p]+"\n"))
g"|   ###  ###   |   ###  ###  ###   "5 
g"|    "3
g"|____"1

I used modules of 2 to detect for a space or pound. ' ' is 32 % 2 = 0 '#' is 35 % 2 = 1 and since my conditional returned zeros for false I just multiplied the modules result.

Used the <| operator to shave off one space char. Used operator overloading to save another char.

original

let piano_long (input:string) = 
    let sharp, flat = if input.[1] = '#' then 4, 1 else 0, 0

    let note = (int input.[0] - 60) % 7
    let num = int (input.Substring 2)

    let start = note * 5 + sharp
    let stop = num * 5 + 1 + flat

    let top    = "|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |"
    let middle = "|    |    |    |    |    |    |    |    |    |    |    |    |    |    |"
    let bottom = "|____|____|____|____|____|____|____|____|____|____|____|____|____|____|"


    let mutable piano = ""

    for i in 1..5 do 
        piano <- piano + top.Substring(start, stop) + "\n"

    for i in 1..3 do 
        piano <- piano + middle.Substring(start, stop) + "\n"

    piano <- piano + bottom.Substring(start, stop)

    printf "%s\n\n" piano
gradbot
  • 13,732
  • 5
  • 36
  • 69
11

sed, 231 235 234 235 237 238 244 268 269 270 276 279 280 282 287 300 307 314 329 338 characters

Works for up to 99 keys. The standard piano has 52 white keys, so this should be sufficient.

s/.*/CDEFGABC&=0123456789-/
s/(.).=(.*)\1.*/&\2\2\2\2\2\2\2\2\2\2/
s/ .?(.)=(.*)\1.*-/\2/
s/.*#/%&/
:
s/((.)(.).*\2)[#-9]/\1  \3/
t
s/[^ %CF]/###/g
s/C|F/ | /g
s/(%....)?.{25}(.*)./\2/p
p
p
p
p
s/## /|  /g
s/#[|#]/ |/g
p
p
p
y/ /_/

Examples:

$ echo C 14 | sed -rf piano.sed
|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
|   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|____|____|____|____|____|____|____|____|____|____|____|____|____|____|
$ echo D# 1 | sed -rf piano.sed
###   |
###   |
###   |
###   |
###   |
 |    |
 |    |
 |    |
_|____|
$ echo A 7 | sed -rf piano.sed
##  ###   |   ###  ###   |   ###  ##
##  ###   |   ###  ###   |   ###  ##
##  ###   |   ###  ###   |   ###  ##
##  ###   |   ###  ###   |   ###  ##
##  ###   |   ###  ###   |   ###  ##
|    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |
|____|____|____|____|____|____|____|
$ echo A 52 | sed -rf piano.sed
##  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ##
##  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ##
##  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ##
##  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ##
##  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ###   |   ###  ###  ###   |   ##
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |
|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|____|

The last example prints the standard keyboard, along with imaginary black keys on either end.

KirarinSnow
  • 1,062
  • 2
  • 9
  • 22
10

JavaScript - 195 chars

Hey, golf is a game where you only compete against yourself right? :)

k=readFile(0).split(' ')
q=!k[0][1]
r=k[1]
o=''
for(x=10;x--;){p=k[0].charCodeAt(0)-65+!q
s=''
for(j=+r+1;j--;){p=++p%7
s+=x>4&&!p|p%3?'###  ':x?' |   ':'_|___'}o+=s.substring(q,r*5+2)+'\n'}print(o)

Solution by gnarf; ported to Rhino (with a minor fix and formatting changes) by KirarinSnow; further chipped away by gnarf; error corrected by KirarinSnow. cache k[1] by cwallenpoole

Usage: $ cp input.in 0; rhino thisfile.js

Quick HTML Demo Version: Golf Test - Adds readFile=prompt;print=function(a) {document.write("<pre>"+a);}

cwallenpoole
  • 79,954
  • 26
  • 128
  • 166
gnarf
  • 105,192
  • 25
  • 127
  • 161
  • Well, you also compete against the specification... and I think that you lost. ;) It doesn't even pass the test cases. It seems that it starts one off. – Guffa Feb 04 '10 at 22:29
  • You only have 1 reference to b. change readFile(b) to just readFile('substring') – Ponkadoodle Feb 05 '10 at 06:30
  • @wallacoloo - needed later, the part at the bottom: `s=s[b](1-q,p=s.length-3)` – gnarf Feb 05 '10 at 06:36
10

PianoScript - 2 characters

It's a one-liner:

go

Usage:

PianoScript piano.ps G# 11

Output:

###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ##
###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ##
###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ##
###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ##
###  ###   |   ###  ###   |   ###  ###  ###   |   ###  ##
 |    |    |    |    |    |    |    |    |    |    |    |
 |    |    |    |    |    |    |    |    |    |    |    |
_|____|____|____|____|____|____|____|____|____|____|____|

More information on the PianoScript language can be found here.

Clueless
  • 3,984
  • 1
  • 20
  • 27
6

Python3 - 158

Save on input vs raw_input. Lose on () for print

k,n=input().split()
o=(ord(k[0])-65)*5
n=int(n)*5+1
for x in["##  ###   |   ### "]*5+[n*"|    "]*3+[n*"|____"]:print(((x+x[::-1][:-1])*n)[o+3*len(k[1:]):o+n])
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
5

F#: 355 significant chars

All on one line:

let[|x;y|]=System.Console.ReadLine().Split([|' '|])in[for i in 1..9->let r (a:string) b j (s:string)=s.Replace(a,if i>j then b else a)in((String.replicate(int y+1)"23012123012121").Substring(int(x.[0])-65,int y*2+x.Length).Replace("0","|   ")|>r"1""#"0|>r"2""##  "0|>r"3"" "0).TrimEnd()|>r"###"" | "5|>r"##""| "5|>r" ""_"8]|>String.concat"\n"|>printfn "%s"

Expanded:

let piano() =
    let[|x;y|]=System.Console.ReadLine().Split([|' '|])in
    [for i in 1..9->
        let r (a:string) b j (s:string) = s.Replace(a,if i>j then b else a) in
        ((String.replicate (int y+1) "23012123012121")
            .Substring(int(x.[0])-65,int y*2+x.Length).Replace("0","|   ")
            |> r "1" "#" 0
            |> r "2" "##  " 0
            |> r "3" " " 0)
            .TrimEnd()|> r "###" " | " 5|> r "##" "| " 5|> r " " "_" 8]
    |> String.concat "\n"
    |> printfn "%s"
Juliet
  • 80,494
  • 45
  • 196
  • 228
3

SETL

165 characters; Translation of gribblers Python solution.

get(l);[k,n]:=split(l);o:=(abs k(1)-65)*5;n:=1+5*val n;(for x in['##  ###   |   ### ']*5+[n*'|    ']*3+[n*'|____'])print(((x+reverse x(2..))*n)(o+4*#k-3..o+n));end;
finnw
  • 47,861
  • 24
  • 143
  • 221
3

D2 (templates): 331 370 400 + 17 characters

(based on the Ruby solution.)

Compressed:

template J(alias T,int b,int e,r...){static if(e)enum J=T!(b,r)~J!(T,b+1,e-1,r);else enum J="";}template K(int i,int t){enum K=t>7?"_|___":t<5&&3&i%7?"###  ":" |   ";}template R(int t,int s,int l,int h){enum R=J!(K,s-h,l,t)[h..$-3]~"\n";}template M(alias k){enum M=J!(R,0,9,k[0]+1,k[$-2]>32?k[$-1]+10*k[$-2]-527:k[$-1]-47,k[0]&1);}

Explained:

/**
    Macros:
        D = <tt>$0</tt>
 */
 ;

/**
    $(D_PSYMBOL J) (short for "join") will evaluate $(D T!(i,r)) for
    $(D_PARAM i) in $(D [b..b+e]). Then, these compile-time strings will be
    concatenated.
 */
template J(alias T,int b,int e,r...){
    static if(e)
        enum J=T!(b,r)~J!(T,b+1,e-1,r);
    else
        enum J="";
}

/**
    $(D_PSYMBOL K) (short for "key") will generate 5 characters as a row of
    key $(D_PARAM i) at row $(D_PARAM t).
 */
template K(int i,int t){
    enum K=t>7?"_|___":t<5&&3&i%7?"###  ":" |   ";
}

/**
    $(D_PSYMBOL R) (short for "row") will generate the keyboard at row
    $(D_PARAM t), from key $(D_PARAM s) and sharpness $(D_PARAM h) with a
    length of $(D_PARAM l) keys.
 */
template R(int t,int s,int l,int h){
    enum R=J!(K,s-h,l,t)[h..$-3]~"\n";
}

/**
    $(D_PSYMBOL M) (short for "main") results in the whole keyboard as a string.

    Example:
    -----
    pragma(msg,M!("C 14"));
    pragma(msg,M!("D# 1"));
    pragma(msg,M!("A 7"));
    -----
 */
template M(alias k){
    enum M=J!(R,0,9,k[0]+1,k[$-2]>32?k[$-1]+10*k[$-2]-527:k[$-1]-47,k[0]&1);
}

Since we can't pass parameters from dmd the input must be done in the code. Supports only up to 99 keys.

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • 2
    Can you make the input a single string? Part of the challenge is parsing the line into a note, an optional sharp, and a duration. The parsing itself can take quite a few characters in some languages... – KirarinSnow Feb 06 '10 at 22:04
2

Haskell: 212 211 208 characters

a="  |  "
b=" ### "
d=concat.cycle
e=d[b,b,a,b,b,a,b]
f=d[a]
t x s m n=map(take(5*read s+m).drop(5*length['@'..x]-n))[e,e,e,e,e,f,f,f,d["__|__"]]
u(x:'#':s)=t x s 2 4 
u(x:s)=t x s 1 8
main=interact$unlines.u

It still assumes ascii-compatible letters (specifically, the sequence "@ABCDEFG"), but no longer requires Char.ord

comingstorm
  • 25,557
  • 3
  • 43
  • 67
2

Ruby - 113 chars

Runs with command line arguments

$ ruby piano.rb A 7

k,c=$*
9.times{|x|puts (((b=x<8?'  |  ':'__|__')+(a=x<5?' ### ':b)*3+b+a*2)*j=k[0]*5-2+4*s=k.size)[j,c.to_i*5+s]}

Ruby - 118 chars

k,c=$*
9.times{|x|puts (((b=x<8?'  |  ':'__|__')+(a=x<5?' ### ':b)*3+b+a*2)*j=2+k[0]*5+4*s=k.size-1)[j..c.to_i*5+s+j]}
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
2

PHP - 208 chars

<?$e=45*substr($a=PIANO,2+$d=!($a[1]^~ì))+9+$d*45;$j=9*$c=4*$d;for($b=ord($a[0])-65,--$c;$j<$e;$f[$i=$j++%9].=($c=($c+!$i)%5)%4<2&$i>3&$b%3!=2?Ü:($c?$i?ß: :))$j%45-36?:$b=++$b%7;for(;$a=$f[$i--];)echo~$a,~õ;

Shall have to be improved.

The input has to be delivered in the constant named PIANO.

1

F# 414 386 372 significant characters:

//wins me 2 characters
open System

//String.replicate, didn't know this existed before reading Juliet
let r=String.replicate  

//print s n times, each time on a newline
let P n s=printf"%s"(r n (s+"\n"))  

//define top rows
let t="##  ###   |   ###  ###   |   ###  #" 

//middle and bottom rows can be defined using 'r'
let m,b=r 7"|    ",r 7"|____" 

//pick of chars from O to n+O from string, wrap round if we go beyond s.Length
let L(s:string)O n=String([|5*O..5*(n+O)|]|>Array.map(fun i->s.[i%35]))

//match input string into two halves
let[|k;n|]=Console.ReadLine().Split([|' '|])

//work out start pos and length (in chars, not keys)
let O,N=
 let K=int k.[0]-65                    //'A'=65, this is why t starts at A
 if k.[0]='#'then(K+3,int n+2)else(K,int n) 

//Print 5 top rows, 3 middle rows and the bottom row
P 5(L t O N)
P 3(L m O N)
P 1(L b O N)

Oh, and one bonus, this script will actually handle "F# 372" correctly - I won't annoy you by pasting it here though...

System.Console.ReadLine() is such a bummer...

Benjol
  • 63,995
  • 54
  • 186
  • 268