Although it looks like a tractor kind of problem, Staff allows for some quite elegant solutions.
Observation
The ASCII staff provided in the statement can be hard-coded and used in the solution. More concisely, it can be split horizontally into a series of sections. The treble cleff and final bar each make up one section. Each note occupies a 5-character section, with the @ situated exactly in the middle. This assures the right distance between consecutive notes.
All that's left is the printing. If the series described above is constructed appropriately, then it's a simple matter of executing multiple passes across the series, with each pass printing one row of the solution staff (much like an actual computer printer stamps sentences on a piece of paper, one row at a time).
C solution (Marius Gavrilescu)
1 #include<stdio.h> 2 #include<string.h> 3 4 const char *notes = "C C#D D#E F F#G G#A A#B C2C2#"; // Notes in order. Note #i is at position i * 2 in the string 5 const char *ex[] = { // ! instead of \\ since escaped backslashes are ugly 6 "----|-!-----------------------------------------------------------------------------+", 7 " | } |", 8 "----|-/-----------------------------------------------------|----|------------------|", 9 " |/ 4 | | | | (@) #(@) |", 10 "---/|-----------------------------------|----|----|----|----|----|--(@)--|----|-----|", 11 " / | 4 | | | | | (@) #(@) | | | |", 12 "-{--|-!------------------|----|----|----|----|--(@)-#(@)------------|----|----|-----|", 13 " !_|_/ | | | | | (@) #(@) | |", 14 "----|!---------|----|----|----|--(@)------------------------------------------------+", 15 " |_} | | (@) #(@) ", 16 " (@) #(@) "}; 17 18 int v[255]; 19 20 void print(int l, int a, int b) { 21 for(int i = a ; i < b ; i++) 22 putchar(ex[l][i] == '!' ? '\\' : ex[l][i]); // Replace '!' with '\\' 23 } 24 25 int main() { 26 int n; 27 char note[10]; 28 scanf("%d ", &n); 29 for(int i = 0 ; i < n ; i++){ 30 scanf("%s ", note); 31 v[i] = (strstr(notes, note) - notes) / 2; // Index of the note 32 v[i] = 12 + v[i] * 5; // Start position of the note 33 } 34 35 for (int l = 0; l < 11; l++) { // For each line of ex... 36 print(l, 0, 12); // ... print the clef and measure 37 for(int i = 0; i < n; i++) 38 print(l, v[i], v[i] + 5); // ... print the note 39 print(l, 82, 85); // ... print the final bar 40 puts(""); // ... print a newline 41 } 42 43 return 0; 44 }
Python solution (Sergiu Puscas)
1 base = ['----|-\-----------------------------------------------------------------------------+', 2 ' | } |', 3 '----|-/-----------------------------------------------------|----|------------------|', 4 ' |/ 4 | | | | (@) #(@) |', 5 '---/|-----------------------------------|----|----|----|----|----|--(@)--|----|-----|', 6 ' / | 4 | | | | | (@) #(@) | | | |', 7 '-{--|-\------------------|----|----|----|----|--(@)-#(@)------------|----|----|-----|', 8 ' \_|_/ | | | | | (@) #(@) | |', 9 '----|\---------|----|----|----|--(@)------------------------------------------------+', 10 ' |_} | | (@) #(@) ', 11 ' (@) #(@) '] 12 13 link = {'clef': (0, 12), 14 'C': (12, 17), 15 'C#': (17, 22), 16 'D': (22, 27), 17 'D#': (27, 32), 18 'E': (32, 37), 19 'F': (37, 42), 20 'F#': (42, 47), 21 'G': (47, 52), 22 'G#': (52, 57), 23 'A': (57, 62), 24 'A#': (62, 67), 25 'B': (67, 72), 26 'C2': (72, 77), 27 'C2#': (77, 82), 28 'bar': (82, 85)} 29 30 v = ['clef'] + [raw_input() for _ in range(0, input())] + ['bar'] 31 print '\n'.join([''.join([base[line][link[element][0]:link[element][1]] for element in v]) for line in range(0, len(base))])
The entire functionality only takes up two lines of code. All else is preparation.
Perl solution (Marius Gavrilescu)
1 #!/usr/bin/perl 2 use v5.14; 3 use warnings; 4 5 my @notes = qw/C C# D D# E F F# G G# A A# B C2 C2#/; # List of notes 6 my %notes = map {; $notes[$_] => 12 + $_ * 5 } 0 .. $#notes; # Hash from note name to start index 7 8 my @ex = split "\n", <<'EOF'; 9 ----|-\-----------------------------------------------------------------------------+ 10 | } | 11 ----|-/-----------------------------------------------------|----|------------------| 12 |/ 4 | | | | (@) #(@) | 13 ---/|-----------------------------------|----|----|----|----|----|--(@)--|----|-----| 14 / | 4 | | | | | (@) #(@) | | | | 15 -{--|-\------------------|----|----|----|----|--(@)-#(@)------------|----|----|-----| 16 \_|_/ | | | | | (@) #(@) | | 17 ----|\---------|----|----|----|--(@)------------------------------------------------+ 18 |_} | | (@) #(@) 19 (@) #(@) 20 EOF 21 $_ .= ' ' x 80 for @ex; # Append 80 spaces to each line of @ex 22 23 <>; # Read the first line and ignore it 24 my @song = map { chomp; $notes{$_} } <>; # Song is an array of start indices 25 26 for my $l (@ex) { # For each line of @ex... 27 print substr $l, 0, 12; # ...print the clef and measure 28 print substr $l, $_, 5 for @song; # ...print each note 29 print substr $l, 82, 3; # ...print the final bar 30 say ''; # ...print a newline 31 }
Alternative solutions
Examples from the contest: 6930 (5.62 KB), 7208 (5.60 KB), 7390 (4.25 KB), 6655 (3.94 KB), 6924 (3.38 KB).