Домашни > Pitches love the D > Решения > Решението на Петър Бончев

Резултати
9 точки от тестове
0 точки от учител

9 точки общо

32 успешни теста
5 неуспешни теста
Код
Скрий всички коментари

 1class Tone:
 2
 3    tones = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
 4    tone_to_index = {tone: idx for idx, tone in enumerate(tones)}
 5
 6    def __init__(self, name):
 7        self.name = name
 8
 9    def __str__(self):
10        return self.name
11
12    def __sub__(self, other):
13        if isinstance(other, Tone):
14            difference = (Tone.tone_to_index[self.name] - Tone.tone_to_index[other.name]) % 12
15            return Interval(difference)
16        elif isinstance(other, Interval):
17            new_index = (Tone.tone_to_index[self.name] - other.semitones) % 12
18            return Tone(Tone.tones[new_index])
19
20    def __add__(self, other):
21        if isinstance(other, Tone):
22            return Chord(self, other)
23        elif isinstance(other, Interval):
24            new_tone_index = (Tone.tone_to_index[self.name] + other.semitones) % 12
25            return Tone(Tone.tones[new_tone_index])
26
27class Interval:
28    intervals = {
29        0: "unison", 1: "minor 2nd", 2: "major 2nd", 3: "minor 3rd", 4: "major 3rd",
30        5: "perfect 4th", 6: "tritone", 7: "perfect 5th", 8: "minor 6th", 9: "major 6th",
31        10: "minor 7th", 11: "major 7th"
32    }
33
34    def __init__(self, semitones):
35        self.semitones = semitones % 12
36
37    def __str__(self):
38        return self.intervals[self.semitones]
39
40    def __add__(self, other):
41        if isinstance(other, Interval):
42            return Interval(self.semitones + other.semitones)
43        else:
44            raise TypeError("Invalid operation")
45
46    def __neg__(self):
47        return Interval((12 - self.semitones) % 12)
48
49class Chord:
50
51    def __init__(self, root, *args):
52        self.root = root
53        tones = set(tone for tone in args if isinstance(tone, Tone) and str(tone) != str(root))
54        if not tones:
55            raise TypeError("Cannot have a chord made of only 1 unique tone")
56        self.tones = sorted(tones, key=lambda t: (Tone.tone_to_index[t.name] - Tone.tone_to_index[root.name]) % 12)
57
58    def __str__(self):
59        return str(self.root) + '-' + '-'.join(str(tone) for tone in self.tones)
60
61    def is_minor(self):
62        return any((tone - self.root).semitones == 3 for tone in self.tones)
63
64    def is_major(self):
65        return any((tone - self.root).semitones == 4 for tone in self.tones)
66
67    def is_power_chord(self):
68        return not (self.is_minor() or self.is_major())
69
70    def __add__(self, other):
71        if isinstance(other, Tone):
72            new_tones = set(self.tones) | {other}
73            return Chord(self.root, *new_tones)
74        elif isinstance(other, Chord):
75            new_root = self.root
76            new_tones = [tone for tone in {other.root} | set(other.tones) | set(self.tones)
77                         if tone.name != self.root.name]
78            return Chord(new_root, *new_tones)
79
80    def __sub__(self, other):
81        if isinstance(other, Tone):
82            if not any(tone.name == other.name for tone in self.tones) and other.name != self.root.name:
83                raise TypeError(f"Cannot remove tone {other} from chord {self}")
84            if len(self.tones) == 1:
85                raise TypeError("Cannot have a chord made of only 1 unique tone")
86            new_root = self.root
87            new_tones = list(self.tones)
88            if other.name == self.root.name:
89                new_root = new_tones[0]
90                new_tones.pop(0)
91            new_tones = [tone for tone in self.tones if tone.name != other.name]
92            return Chord(new_root, *new_tones)
93
94    def transposed(self, interval):
95        transposed_root = self.root + interval
96        transposed_tones = [tone + interval for tone in self.tones]
97        return Chord(transposed_root, *transposed_tones)

...F.........F..F.....F....F.........
======================================================================
FAIL: test_chord_tone_repetition (test.TestBasicChordFunctionality.test_chord_tone_repetition)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 74, in test_chord_tone_repetition
self.assertEqual(str(a_minor_chord), "A-C-E")
AssertionError: 'A-C-C-C-C-C-C-C-C-C-C-C-C-C-C-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E' != 'A-C-E'
- A-C-C-C-C-C-C-C-C-C-C-C-C-C-C-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E-E
+ A-C-E

======================================================================
FAIL: test_interval_str (test.TestBasicIntervalFunctionality.test_interval_str)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 42, in test_interval_str
self.assertEqual(str(Interval(index)), interval)
AssertionError: 'tritone' != 'diminished 5th'
- tritone
+ diminished 5th

======================================================================
FAIL: test_add_chords_repeating_notes (test.TestOperations.test_add_chords_repeating_notes)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 305, in test_add_chords_repeating_notes
self.assertEqual(str(result_chord), "C-G")
AssertionError: 'C-G-G' != 'C-G'
- C-G-G
? --
+ C-G

======================================================================
FAIL: test_add_tone_to_chord_existing_tone (test.TestOperations.test_add_tone_to_chord_existing_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 270, in test_add_tone_to_chord_existing_tone
self.assertEqual(str(result_chord), "F-G#-C")
AssertionError: 'F-G#-G#-C-C' != 'F-G#-C'
- F-G#-G#-C-C
+ F-G#-C

======================================================================
FAIL: test_subtract_interval_from_tone_left_side_error (test.TestOperations.test_subtract_interval_from_tone_left_side_error)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 235, in test_subtract_interval_from_tone_left_side_error
self.assertEqual(str(err.exception), INVALID_OPERATION)
AssertionError: "unsupported operand type(s) for -: 'Interval' and 'Tone'" != 'Invalid operation'
- unsupported operand type(s) for -: 'Interval' and 'Tone'
+ Invalid operation

----------------------------------------------------------------------
Ran 37 tests in 0.002s

FAILED (failures=5)

Дискусия
История
Това решение има само една версия.