24
\$\begingroup\$

Piano keys are 3 characters wide, and 7 characters tall. However, if every key was 3 charactes wide, there wouldn't be enough room for the black keys. That's why some of the white keys have parts of them cut out. There are 3 types of white keys.

Keys with the right half missing (R):

____
|  |
|  |
|  |
|  |
|   |
|   |
|___|

Keys with the left half missing (L):

 ____
 |  |
 |  |
 |  |
 |  |
|   |
|   |
|___|

And keys with the left and right halves missing (M):

 ___
 | | 
 | | 
 | | 
 | | 
|   |
|   |
|___|

On a real keyboard, the pattern of these goes like this:

RMLRMML, RMLRMML, RMLRMML...

and repeats for a total of 88 keys. Now you can't see it when the keys are shown individually, but when you shove them together, you can see the black keys.

_________________________________________________________
|  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |
|  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |
|  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |
|  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |
|___|___|___|___|___|___|___|___|___|___|___|___|___|___|

Your task

Given a positive integer N, print this ASCII-art of a piano with N white keys. You should be able to handle any N from 1 to 52 inclusive (since real 88-key pianos have 52 white keys). Here is test output from 1 to 8, and after that the pattern increases in a similar fashion.

1
____
|  |
|  |
|  |
|  |
|   |
|   |
|___|

2
________
|  | | |
|  | | |
|  | | |
|  | | |
|   |   |
|   |   |
|___|___|

3
_____________
|  | | | |  |
|  | | | |  |
|  | | | |  |
|  | | | |  |
|   |   |   |
|   |   |   |
|___|___|___|

4
________________
|  | | | |  |  | 
|  | | | |  |  | 
|  | | | |  |  | 
|  | | | |  |  | 
|   |   |   |   |
|   |   |   |   |
|___|___|___|___|

5
____________________
|  | | | |  |  | | | 
|  | | | |  |  | | | 
|  | | | |  |  | | | 
|  | | | |  |  | | | 
|   |   |   |   |   |
|   |   |   |   |   |
|___|___|___|___|___|

6
________________________
|  | | | |  |  | | | | | 
|  | | | |  |  | | | | | 
|  | | | |  |  | | | | | 
|  | | | |  |  | | | | | 
|   |   |   |   |   |   |
|   |   |   |   |   |   |
|___|___|___|___|___|___|

7
_____________________________
|  | | | |  |  | | | | | |  |
|  | | | |  |  | | | | | |  |
|  | | | |  |  | | | | | |  |
|  | | | |  |  | | | | | |  |
|   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |
|___|___|___|___|___|___|___|

8
________________________________ 
|  | | | |  |  | | | | | |  |  | 
|  | | | |  |  | | | | | |  |  | 
|  | | | |  |  | | | | | |  |  | 
|  | | | |  |  | | | | | |  |  | 
|   |   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |   |
|___|___|___|___|___|___|___|___|

And last but not least, here is a full 52 key output:

_________________________________________________________________________________________________________________________________________________________________________________________________________________
|  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |
|  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |
|  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |
|  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |  | | | | | |  |  | | | |  |
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|

Standard loopholes are banned, and the shortest answer in bytes wins!

\$\endgroup\$
  • \$\begingroup\$ What are "standard loopholes"? \$\endgroup\$ – Wildcard May 4 '16 at 1:26
  • 3
    \$\begingroup\$ @Wildcard meta.codegolf.stackexchange.com/questions/1061/… \$\endgroup\$ – James May 4 '16 at 1:27
  • \$\begingroup\$ Are trailing spaces on any/all lines permitted? How about a trailing newline? \$\endgroup\$ – Sok May 4 '16 at 11:10
  • 1
    \$\begingroup\$ @AlexL. Since real 88-key pianos have 55 white keys. \$\endgroup\$ – James May 6 '16 at 0:50
  • 1
    \$\begingroup\$ @BMac >_> I don't... <_< I have no idea what you're talking about. I said 52, see! You can clearly see it in the R̶e̶v̶i̶s̶i̶o̶n̶ ̶H̶i̶s̶t̶o̶r̶y̶ Uh, I mean the state of the post right now! Anyway, thankfully that probably won't break any existing answers, since most of them probably work to 55+ anyway. \$\endgroup\$ – James May 11 '16 at 22:20
4
\$\begingroup\$

Pyth, 68 65 63 bytes

*lJ:+\|s@Lj;*L" |"_j4536 7*4Q" $"k\_jb+*4]J*2]K+\|*Q"   |":Kd\_

Try it online!

Test suite.

In this version, I just substituted the assignments (J and K) inside to save 2 bytes. Therefore, read the version below.

Previous 65-byte version with explanation

J:+\|s@Lj;*L" |"_j4536 7*4Q" $"kK+\|*Q"   |"*lJ\_jb+*4]J*2]K:Kd\_

Try it online!

J:+\|s@Lj;*L" |"_j4536 7*4Q" $"k    This part generates the most irregular line.

        j;*L" |"_j4536 7            Generate the whole line by black magic
      @L                *4Q         Get the first (4*input) characters of it, with wrapping.
  +\|                               Add "|" in front of it (we took away the first "|")
 :                         " $"k    Replace the ending space by nothing
J                                   Store the line to J.


K+\|*Q"   |"      This part generates the line just below the irregular line.
    *Q"   |"      Repeat "   |" input times
 +\|              Prepend "|"
K                 Store to K


*lJ\_     Now we can actually start printing

*  \_     Repeat "_" ...
 lJ                      [the length of J] times
          (and implicitly print it out)


jb+*4]J*2]K

   *4]J             Repeat J 4 times
       *2]K         Repeat K 2 times
  +                 Concatenate them together
jb                  Join with newlines
                    (and implicitly print it out)

:Kd\_

:K      Replace in K
  d                  " "
   \_                    by "_"
        (and implicitly print it out)

Black magic

We find the irregular line from input=7, and cut out the first "|":
"  | | | |  |  | | | | | |  |"
 2  1 1 1 2  2  1 1 1 1 1 2

j;*L" |"_j4536 7    Black magic.

         j4536 7    4536 converted to base 7: [1,6,1,4,0]
        _           Reverse: [0,4,1,6,1]
  *L" |"            Repeat " |" <each element> times:
                    [""," | | | |"," |"," | | | | | |"," |"]
j;                  Join by whitespace:
                    "  | | | |  |  | | | | | |  |"
\$\endgroup\$
  • \$\begingroup\$ I've only just got your joke. Groan... \$\endgroup\$ – Neil May 8 '16 at 0:17
11
\$\begingroup\$

JavaScript (ES6), 155 149 147 bytes

n=>[`_`[r=`repeat`](n*4+(9>>n%7&1)),s=[...Array(n*12/7|0)].map((_,i)=>1998>>i%12&1?` |`:`  |`).join``,s,s,s,s=`   |`[r](n),s,`___|`[r](n)].join`\n|`

Where \n represents the literal newline character. Leverages the fact that all the lines after the first start with a | character. Explanation:

f=
n=>[                        // Start by building up a list of rows
 `_`[r=`repeat`](n*4+       // 4 underscores per key
  (9>>n%7&1)),              // Third and seventh keys have one extra
 s=[...Array(n*12/7|0)]     // Calculate total of white and black keys
  .map((_,i)=>              // Process each key in turn
   1998>>i%12&1?` |`:`  |`  // Bitmap of narrow and wide keys
  ).join``,                 // Join the keys together
 s,s,s,                     // Repeated 4 times in total
 s=`   |`[r](n),            // Full width part of the white keys
 s,                         // Repeated twice in total
 `___|`[r](n)               // Base of the white keys
].join`\n|`                 // Join the rows together
<input type="number" oninput="o.textContent=f(this.value);"><pre id=o>

Edit: Saved 2 bytes by fixing my misreading of the spec on the height of the keys.

\$\endgroup\$
  • 2
    \$\begingroup\$ You, sir, just blew my mind. \$\endgroup\$ – Robbie Coyne May 4 '16 at 12:02
  • \$\begingroup\$ Oh this is good, can you add some sort of walkthrough? \$\endgroup\$ – nobe4 May 4 '16 at 13:05
  • \$\begingroup\$ You should add a runnable snippet if you can. \$\endgroup\$ – Bálint May 6 '16 at 13:35
1
\$\begingroup\$

Ruby, 119 bytes

->n{puts ?_*(1+n*4+(0<=>-n%7%4)),(0..6).map{|i|("01"+("%b"%[0xAADAAAD,13][i/4]*99)).tr('10',' |_|'[i/6*2,2])[0,1+n*4]}}

Ungolfed in test program

f=->n{
  puts ?_*(1+n*4+(0<=>-n%7%4)),           #Draw 1+n*4 _'s for top row (one less if -n%7%4>0, black note), then...
  (0..6).map{|i|                          #Cycle through remaining 7 rows
    ("01"+("%b"%[0xAADAAAD,13][i/4]*99)).   #Generate string version of binary number corresponding to pattern, repeat 99 times.
    tr('10',' |_|'[i/6*2,2]                 #Binary 1-> space or underscore. Binary 0 -> | (These choices ensured no leading 0)
    )[0,1+n*4]                              #truncate to the right amount of keys.
  }
}


10.times{|j|f[j]}
\$\endgroup\$
1
\$\begingroup\$

><>, 188 182 bytes

&0"_"o011.
.\:7%8g95*-"_"o1-:a1@@?.~~~1+:&:&=1+1$
.v~:7=?;ao"|"o1+:0$0$
.>:7%8g"0"-4*:9go1+:9go1+:9go1+9go1+:&:&=3$-1$
 ^
.>"| _"{:}7=?$~::oooo1+:&:&(3*2+1$
>^
^
0120112
  | | | |  |

The number of white keys to display should be present on the stack at program start.

Edit: I managed to shave off a few bytes through combining the output for lines 5/6 and 7. Previous version:

&0"_"o011.
.\:7%8g95*-"_"o1-:a1@@?.~~~1+:&:&=1+1$
.v~ao"|"o1+:0$0$.
.>:7%8g"0"-4*:9go1+:9go1+:9go1+9go1+:&:&=3$-1$
 ^
.>"|   "oooo1+:&:&(3*2+1$
 ^
 "|___"oooo1+:&:&=?;
0120112
  | | | |  |
\$\endgroup\$
1
\$\begingroup\$

PHP, 238 bytes

$n=$argv[1];$s=str_repeat;echo'_'.$s($a=$s('_',28),$m=($n-$r=$n%7)/7).substr($a,0,$k=4*$r-($r&&$r!=3))."\n",$g='|'.$s($b='  | | | |  |  | | | | | |  |',$m).substr($b,0,$k)."\n",$g,$g,$g,$h='|'.$s('   |',$n)."\n",$h,'|'.$s('___|',$n)."\n";

As usual, prepend the code with <?php, put it into a PHP file (let's name it keyboard.php) and run it using:

$ php -d error_reporting=0 keyboard.php 55

Two more bytes can be saved on PHP7 by squeezing the initialization of $n and $s into their first use:

echo'_'.($s=str_repeat)($a=$s('_',28),$m=($n-$r=($n=$argv[1])%7)/7).substr($a,0,$k=4*$r-($r&&$r!=3))."\n",$g='|'.$s($b='  | | | |  |  | | | | | |  |',$m).substr($b,0,$k)."\n",$g,$g,$g,$h='|'.$s('   |',$n)."\n",$h,'|'.$s('___|',$n)."\n";

The ungolfed code, a test suite and other goodies can be found on github.

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

Python 3 2, 191 185 180 182 171 145 144 133 132 bytes

def k(n):print"\n|".join(["_"*(4*n+(9>>n%7&1))]+[''.join("   ||"[1998>>j%12&1::2]for j in range(n*12/7))]*4+["   |"*n]*2+["___|"*n])

This could use some golfing but I've fiddled with the code so much already that I may not see where the golfable spots are. Any golfing suggestions are welcome.

Edit: Misread the spec on the height of the keys. This bug has been fixed.

Edit: Borrowed Neil's 12 key idea from his Javascript answer, removed some parentheses, and switched to Python 2 to save 11 bytes.

Edit: Lots of changes to get the function down to one for loop.

Edit: Now a program instead of a function.

Edit: Now using print"\n|".join() as suggested by Neil to save 11 bytes. Turned the program back into a function to save a byte.

\$\endgroup\$
  • \$\begingroup\$ I think you could save another 10 bytes by using my "\n|".join trick. \$\endgroup\$ – Neil May 8 '16 at 0:23
  • \$\begingroup\$ Ah, I'd forgotten to remove the space between print and "\n|"! \$\endgroup\$ – Neil May 8 '16 at 17:35
0
\$\begingroup\$

C# 1683 bytes

So....after seeing Neil's answer above this is pretty embarrassing, but I'll post it anyway 'cause it took me a while (bless). I used C# to create mine. Inside the "Fncs" class I created an array of the typical order of keys. Then, I created a function which can allow the user to get an appropriate index for this array based on a given integer. In order to edit individual lines, I created a "PianoKeyboard" class which contains a dictionary storing multiple strings representing the individual lines. Finally, I created the "DrawKey" function which appends the appropriate text to the individual lines and the "GetKeys" function which returns the overall string value.

namespace ASCIIPiano{public enum WhiteKeyType{Left,Middle,Right}public static class Fncs{public static WhiteKeyType[] Order{get{return new WhiteKeyType[]{WhiteKeyType.Left,WhiteKeyType.Middle,WhiteKeyType.Right,WhiteKeyType.Left,WhiteKeyType.Middle,WhiteKeyType.Middle,WhiteKeyType.Right};}}public static PianoKeyboard DrawKey(this PianoKeyboard keyboard, WhiteKeyType type){keyboard.Append(1,"_____");if (type == WhiteKeyType.Left){keyboard.Append( 2,"|  | ");keyboard.Append( 3,"|  | ");keyboard.Append( 4,"|  | ");keyboard.Append( 5, "|  | ");}else if (type == WhiteKeyType.Middle){keyboard.Append(2, " | | ");keyboard.Append(3," | | ");keyboard.Append( 4," | | ");keyboard.Append(5," | | ");}else{keyboard.Append( 2," |  |");keyboard.Append(3, " |  |");keyboard.Append(4," |  |");keyboard.Append(5, " |  |");}keyboard.Append(6,"|   |");keyboard.Append(7,"|   |");keyboard.Append(8,"|___|");return keyboard;}public static int GetWhiteKeyIndex(this int number){return number % 7;}public static string GetKeys(this int quantityofwhitekeys){PianoKeyboard keyboard = new PianoKeyboard();for (int i = 0; i < quantityofwhitekeys; i++){WhiteKeyType key=Fncs.Order[i.GetWhiteKeyIndex()];keyboard.DrawKey(key);}return keyboard.TOTALSTRING;}}public class PianoKeyboard{public PianoKeyboard(){}private Dictionary<int, string> lines = new Dictionary<int, string>();public void Append(int index,string value){if (index > 8 || index < 1){throw new Exception("URGH!");}else{if (lines.Keys.Contains(index)){lines[index] += value;}else{lines.Add(index, value);}}}public string TOTALSTRING{get{string returner = "";foreach (int key in lines.Keys){returner += lines[key] + "\n";}return returner;}}}}
\$\endgroup\$
  • 1
    \$\begingroup\$ Hi, welcome to PPCG! As you might have noticed, code-golf challenges are about writing the shortest code possible. Languages like C#, Java and basically any OO language are therefor most often a bad choice. However, it can be a great practise to write short code so I'm not trying to discourage you from doing so :) As for your answer, it's a nice way to solve this problem if you wouldn't keep the length of code in mind! Have fun, and good luck trying to write small C# code :) \$\endgroup\$ – Bassdrop Cumberwubwubwub May 4 '16 at 12:36
  • \$\begingroup\$ @BassdropCumberwubwubwub Thanks, I'm actually new to this site (of course). Kinda new to programming too but I'll do my best ^_^ \$\endgroup\$ – Robbie Coyne May 4 '16 at 12:38
  • \$\begingroup\$ Funny to see a 4KB answer between all the <200 byte answers. I personally also like to write Java code in as short as possible for these Codegolf challenges, since I never used any codegolf language at all. Of course Java and C# can never compete with other answers, but it's fun to try and create code as short as possible. Here is a post you might find interesting: Tips for code-golfing in C#. PS: I've copied your code to a file to see the exact amount of bytes, which is: 4,052. ;) Anyway, welcome to PPCG! \$\endgroup\$ – Kevin Cruijssen May 4 '16 at 12:59
  • 2
    \$\begingroup\$ Welcome to PPCG, but this answer needs to be fully golfed. I see whitespace and comments that can be removed. \$\endgroup\$ – Rɪᴋᴇʀ May 4 '16 at 14:04
  • 1
    \$\begingroup\$ 1.: Rename your variables, so they're 1 character long 2.: Always add a proper byte count, it needs tk be byte precise \$\endgroup\$ – Bálint May 6 '16 at 13:37

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.