Every note of a melody is to be moved by k semitones. A note is written as a note name followed by an octave digit, such as C4, F#3 or Bb5. The note name is one uppercase letter among C, D, E, F, G, A, B, and it may be followed directly by one sharp # or one flat b (lowercase). A sharp or a flat may follow any of the seven letters, so E#, Fb, B# and Cb also appear in the input. Each letter has a fixed semitone count: C 0, D 2, E 4, F 5, G 7, A 9, B 11. The pitch of a note is (octave digit) × 12 + (semitone count of the letter); a sharp adds 1 to this and a flat subtracts 1. So B#4 and C5 both have pitch 60, and Cb4 and B3 both have pitch 47. For each note, add k to its pitch to get the new pitch, and print the note of that pitch written by the following rule. The remainder of the new pitch divided by 12, which is 0, 1, 2, …, 11, selects the note name C, C#, D, D#, E, F, F#, G, G#, A, A#, B in that order. The quotient of the new pitch divided by 12 is appended as the octave digit. Flats are never used in the output.
Input
The first line gives the number of notes n and the shift k, separated by one space. The second line gives the n notes, separated by one space. 1 ≤ n ≤ 1000 and -12 ≤ k ≤ 12; a negative k lowers the pitch. Octave digits in the input are from 2 to 6. The new pitch is therefore always between 11 and 96.
Output
Print the n moved notes in input order on one line, separated by one space.
Example 1 · stdin
5 3
C4 B4 F#3 Bb5 E2
stdout
D#4 D5 A3 C#6 G2
Example 2 · stdin
3 0
B#4 Cb4 Fb3
stdout
C5 B3 E3
main.py
Error List00F8 ↓ · ⇧F8 ↑
Input (stdin)
When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).
$ Ready
Open this on a computer to write and run code. On mobile you can read the problem and the solutions.
In other languagesShow solutions by language · 8 languages
The seven-way branch that turns a letter into a number is the switch of this problem. In C and C++ a switch takes only integers and characters, so you write case 'C':; giving it a string is a compile error. JS and TS can compare strings with case "C":. Java has the arrow form case 'C' -> 0;, C# the switch expression 'C' => 0,, Python match/case "C": since 3.10, and Craykon switch (letter) { case "C": … break; }. Trap one: leaving out break. In C, C++, Java (colon form), JS and TS a switch falls through to the next case when there is no break. Drop the break after case 'E': s = 4; and E gets F's value 5, so E2 in example 1 comes out as G#2 instead of G2. The C solution here writes break in every branch; the C++, JS and TS solutions leave each branch with return. In C# a non-empty case that falls through is a compile error (CS0163), and Java's arrow form, C#'s switch expression, Python's match and Craykon's switch do not fall through. Trap two: keeping the octave apart and computing only the name index. If you take s = the letter's semitone count plus the accidental plus k and use NAMES[s % 12] and octave + s / 12, then s is -1 for Cb4 in example 2. In C, C++, Java, C#, JS, TS and Craykon -1 % 12 is -1, which points outside the list. In JS NAMES[-1] is undefined, and adding a number to it prints NaN. Only in Python is -1 % 12 equal to 11 and -1 // 12 equal to -1, so the same formula still gives B3. Every solution here computes with one pitch number that includes octave × 12. The pitch is always at least 11, so the remainder and the quotient are never negative in any of the languages. The quotient is integer / in C, C++, Java and C#, // in Python, Math.floor(p / 12) in JS and TS, and Mathf.Quot(p, 12) in Craykon. Trap three: forgetting that an accidental can cross into another octave. If the name is chosen with the accidental but the octave is decided from the letter and k alone, B#4 in example 2 comes out as C4 instead of C5, and Cb4 as B4 instead of B3.
Pythonmain.py · 31 lines
NAMES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]def semitone(letter): # 음이름 글자가 C에서 반음 몇 개 위인지 (match는 다음 case로 이어 내려가지 않는다) match letter: case "C": return 0 case "D": return 2 case "E": return 4 case "F": return 5 case "G": return 7 case "A": return 9 case _: return 11 # Bn, k = map(int, input().split())out = []for note in input().split(): p = int(note[-1]) * 12 + semitone(note[0]) # 음 번호: 옥타브와 음이름을 한 수로 if len(note) == 3: p += 1 if note[1] == "#" else -1 p += k out.append(NAMES[p % 12] + str(p // 12))print(" ".join(out))
JavaScriptmain.js · 25 lines
const NAMES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];// 음이름 글자가 C에서 반음 몇 개 위인지function semitone(letter) { switch (letter) { case "C": return 0; case "D": return 2; case "E": return 4; case "F": return 5; case "G": return 7; case "A": return 9; default: return 11; // B }}const lines = require("fs").readFileSync(0, "utf8").split("\n");const k = Number(lines[0].trim().split(/\s+/)[1]);const out = lines[1].trim().split(/\s+/).map((note) => { // 음 번호: 옥타브와 음이름을 한 수로 합친다 let p = Number(note[note.length - 1]) * 12 + semitone(note[0]); if (note.length === 3) p += note[1] === "#" ? 1 : -1; p += k; return NAMES[p % 12] + Math.floor(p / 12);});console.log(out.join(" "));
TypeScriptmain.ts · 27 lines
import { readFileSync } from "node:fs";const NAMES: string[] = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];// 음이름 글자가 C에서 반음 몇 개 위인지function semitone(letter: string): number { switch (letter) { case "C": return 0; case "D": return 2; case "E": return 4; case "F": return 5; case "G": return 7; case "A": return 9; default: return 11; // B }}const lines: string[] = readFileSync(0, "utf8").split("\n");const k: number = Number(lines[0].trim().split(/\s+/)[1]);const out: string[] = lines[1].trim().split(/\s+/).map((note: string): string => { // 음 번호: 옥타브와 음이름을 한 수로 합친다 let p: number = Number(note[note.length - 1]) * 12 + semitone(note[0]); if (note.length === 3) p += note[1] === "#" ? 1 : -1; p += k; return NAMES[p % 12] + Math.floor(p / 12);});console.log(out.join(" "));
JavaMain.java · 35 lines
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class Main { static final String[] NAMES = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"}; // 음이름 글자가 C에서 반음 몇 개 위인지 (화살표 switch는 이어 내려가지 않는다) static int semitone(char letter) { return switch (letter) { case 'C' -> 0; case 'D' -> 2; case 'E' -> 4; case 'F' -> 5; case 'G' -> 7; case 'A' -> 9; default -> 11; // B }; } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int k = Integer.parseInt(in.readLine().trim().split("\\s+")[1]); StringBuilder out = new StringBuilder(); for (String note : in.readLine().trim().split("\\s+")) { // 음 번호: 옥타브와 음이름을 한 수로 합친다 int p = (note.charAt(note.length() - 1) - '0') * 12 + semitone(note.charAt(0)); if (note.length() == 3) p += note.charAt(1) == '#' ? 1 : -1; p += k; if (out.length() > 0) out.append(' '); out.append(NAMES[p % 12]).append(p / 12); } System.out.println(out); }}
C#Main.cs · 34 lines
using System;using System.Collections.Generic;class Program{ static readonly string[] Names = { "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" }; // 음이름 글자가 C에서 반음 몇 개 위인지 static int Semitone(char letter) => letter switch { 'C' => 0, 'D' => 2, 'E' => 4, 'F' => 5, 'G' => 7, 'A' => 9, _ => 11, // B }; static void Main() { int k = int.Parse(Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries)[1]); var result = new List<string>(); foreach (string note in Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries)) { // 음 번호: 옥타브와 음이름을 한 수로 합친다 int p = (note[note.Length - 1] - '0') * 12 + Semitone(note[0]); if (note.Length == 3) p += note[1] == '#' ? 1 : -1; p += k; result.Add(Names[p % 12] + (p / 12)); } Console.WriteLine(string.Join(" ", result)); }}
C++main.cpp · 35 lines
#include <iostream>#include <string>using namespace std;const string NAMES[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};// 음이름 글자가 C에서 반음 몇 개 위인지int semitone(char letter) { switch (letter) { case 'C': return 0; case 'D': return 2; case 'E': return 4; case 'F': return 5; case 'G': return 7; case 'A': return 9; default: return 11; // B }}int main() { int n, k; cin >> n >> k; for (int i = 0; i < n; i++) { string note; cin >> note; // 음 번호: 옥타브와 음이름을 한 수로 합친다 int p = (note.back() - '0') * 12 + semitone(note[0]); if (note.size() == 3) p += note[1] == '#' ? 1 : -1; p += k; if (i) cout << ' '; cout << NAMES[p % 12] << p / 12; } cout << '\n'; return 0;}
Cmain.c · 36 lines
#include <stdio.h>#include <string.h>static const char *NAMES[12] = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};/* 음이름 글자가 C에서 반음 몇 개 위인지 */static int semitone(char letter) { int s; switch (letter) { case 'C': s = 0; break; case 'D': s = 2; break; case 'E': s = 4; break; case 'F': s = 5; break; case 'G': s = 7; break; case 'A': s = 9; break; default: s = 11; break; /* B */ } return s;}int main(void) { int n, k; char note[8]; scanf("%d %d", &n, &k); for (int i = 0; i < n; i++) { scanf("%7s", note); size_t len = strlen(note); /* 음 번호: 옥타브와 음이름을 한 수로 합친다 */ int p = (note[len - 1] - '0') * 12 + semitone(note[0]); if (len == 3) p += note[1] == '#' ? 1 : -1; p += k; printf("%s%s%d", i ? " " : "", NAMES[p % 12], p / 12); } printf("\n"); return 0;}
Craykonmain.cray · 53 lines
names = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];// 음이름 글자가 C에서 반음 몇 개 위인지반음(letter){ s = 11; // B switch (letter) { case "C": s = 0; break; case "D": s = 2; break; case "E": s = 4; break; case "F": s = 5; break; case "G": s = 7; break; case "A": s = 9; break; } return s;}first = Console.ReadNumbers();k = first[1];notes = Console.ReadLine().Trim().Split(" ");out = [];foreach (note in notes){ // 음 번호: 옥타브와 음이름을 한 수로 합친다 p = note[note.Length - 1].ToNumber() * 12 + 반음(note[0]); if (note.Length == 3) { if (note[1] == "#") { p = p + 1; } else { p = p - 1; } } p = p + k; out.Add(names[p % 12] + Mathf.Quot(p, 12));}Console.WriteLine(out.Join(" "));