After numerous failed attempts at impressing Xoranna, the girl of his dreams, Xorin made a desperate leap of faith: he turned to the cheerful-sounding heart-stealing super-dandy-relaxed power of smooth jazz. Having bought a shiny new saxophone and his favourite songbook, Duke Silver's Jazz it up a little, Xorin encountered one unexpected problem. Due to sheer greed, the book's editors decided to simplify the musical notation, in order to cut down on printing costs.
This is where you come in. Xorin has no time to learn this new-age revolutionary musical notation, so you have to transcribe any song to the only format he knows: using a staff.
Input
You are given one song, in the following manner:
- first line of input: an integer n, equal to the number of notes in the song;
- the following n lines of input: one note on each line.
The song is in the C Major scale, so the set of all possible unaltered notes is {C, D, E, F, G, A, B, C2}. Moreover, some notes may be followed by a #, which makes them sharp. Xorin knows that E# == F, and also B# == C2. Therefore, it is guaranteed that no E# or B# notes will ever be found in the input (F and C2 will be used instead).
Output
You need to construct a musical staff which contains the same sequence of notes as the input. The staff endorses the following structure:
----|-\-----------------------------------------------------------------------------+ | } | ----|-/-----------------------------------------------------|----|------------------| |/ 4 | | | | (@) #(@) | ---/|-----------------------------------|----|----|----|----|----|--(@)--|----|-----| / | 4 | | | | | (@) #(@) | | | | -{--|-\------------------|----|----|----|----|--(@)-#(@)------------|----|----|-----| \_|_/ | | | | | (@) #(@) | | ----|\---------|----|----|----|--(@)------------------------------------------------+ |_} | | (@) #(@) (@) #(@)
This example contains all possible input notes, in ascending order: C, C#, D, D#, E, F, F#, G, G#, A, A#, B, C2, C2#.
Let us identify the position of a note by the column on which its @ lies.
The treble clef's position is the column on which its vertical line lies.
The measure is always 4/4, and its position is also the column on which both digits lie.
The staff should be constructed in the following order: firstly, it should contain the treble clef, followed by the measure, which should itself be followed by the sequence of notes. The staff always ends with a vertical bar, as seen in the example above. All elements must be placed on consecutive positions, that can be evenly divided by 5.
For clarification, check the positions used in the example - clef: 5, measure: 10, notes: 15, 20, ..., 80, final bar: 85.
Constraints
- Xoranna has got a lot of admirers to deal with (and not much time on her hands), therefore the song that Xorin chooses to play for her will never be longer than 250 notes. The song might even contain no notes at all!
Samples
Input | Output |
---|---|
3 D# C2# A | ----|-\----------------------+ | } | ----|-/------------------|---| |/ 4 #(@) | | ---/|-------------|------|---| / | 4 | (@) | -{--|-\--------|--|----------| \_|_/ | | ----|\---------|-------------+ |_} #(@) |
5 G B F# C F# | ----|-\--------------------------------+ | } | ----|-/--------------------------------| |/ 4 | | ---/|----------|--(@)----|---------|---| / | 4 | | | | | -{--|-\------(@)--|------|---------|---| \_|_/ | #(@) | #(@) | ----|\------------------------|--------+ |_} | (@) |
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).