Домашни > Pitches love the D > Решения > Решението на Габриела Николова

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

8 точки общо

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

  1class Tone:
  2    _notes_index = {"C": 0, "C#": 1, "D": 2, "D#": 3, "E":4, "F":5, "F#":6, "G":7, "G#":8, "A":9, "A#":10, "B":11}
  3    _index_notes = {idx: note for note, idx in _notes_index.items()}
  4
  5    def __init__(self, note):
  6        if note not in self._notes_index:
  7            raise ValueError("Invalid note")
  8        self.note = note
  9        self.index = self._notes_index[note]
 10    
 11    def __str__(self):
 12        return self.note
 13    
 14    def __add__(self, other):
 15        if isinstance(other, Tone):
 16            return Chord(self, other)
 17        elif isinstance(other, Interval):
 18            newIndex = (self.index + other.semitones) % 12
 19            return Tone(self._index_notes[newIndex])
 20        else:
 21            raise TypeError("Invalid argument type")
 22
 23    def __sub__(self, other):
 24        if isinstance(other, Tone):
 25            semitones = (self.index - other.index) % 12
 26            if semitones < 0:
 27                semitones += 12
 28            return Interval(semitones)
 29        elif isinstance(other, Interval):
 30            new_index = (self.index - other.semitones) % 12
 31            return Tone(self._index_notes[new_index])
 32        else:
 33            raise TypeError("Invalid argument type")
 34    
 35    def __eq__(self, other):
 36        if isinstance(other, Tone):
 37            return self.index == other.index
 38        return False
 39
 40
 41class Interval:
 42    _intervals = { 0: "unison", 1: "minor 2nd", 2: "major 2nd", 3: "minor 3rd", 4: "major 3rd", 5: "perfect 4th", 6: "diminished 5th", 7: "perfect 5th", 8: "minor 6th", 9: "major 6th", 10: "minor 7th", 11: "major 7th"}
 43    
 44    def __init__(self, semitones):
 45        self.semitones = semitones % 12
 46    
 47    def __str__(self):
 48        return self._intervals[self.semitones]
 49    
 50    def __add__(self, other):
 51        if isinstance(other, Interval):
 52            newSemitone = (self.semitones + other.semitones) % 12
 53            return Interval(newSemitone)
 54        elif isinstance(other, Tone):
 55            raise TypeError("Invalid operation")
 56        else:
 57            raise TypeError("Invalid argument type")
 58    
 59    def __sub__(self, other):
 60        if isinstance(other, Tone):
 61            raise TypeError("Invalid operation")
 62        
 63    def __neg__(self):
 64        return Interval(-self.semitones)
 65
 66
 67class Chord:
 68    def __init__(self, root, *tones):
 69        unique_tones = []
 70        for tone in tones:
 71            if tone not in unique_tones and tone != root:
 72                unique_tones.append(tone)
 73        if len(unique_tones) < 1:
 74            raise TypeError("Cannot have a chord made of only 1 unique tone")
 75        self.root = root
 76        self.chords = sorted(unique_tones, key=lambda tone:(tone.index - self.root.index) % 12)
 77    
 78    def __str__(self):
 79        return str(self.root) + "-" + "-".join(str(tone) for tone in self.chords)
 80    
 81    def is_minor(self):
 82        intervals = [abs(self.root.index - tone.index) % 12 for tone in self.chords]
 83        return 3 in intervals
 84
 85    def is_major(self):
 86        intervals = [abs(self.root.index - tone.index) % 12 for tone in self.chords]
 87        return 4 in intervals
 88
 89    def is_power_chord(self):
 90        return not self.is_minor() and not self.is_major()
 91    
 92
 93    def __add__(self, other):
 94        if isinstance(other, Tone):
 95            return Chord(self.root, *(self.chords + [other]))
 96        elif isinstance(other, Chord):
 97            return Chord(self.root, *(self.chords + [other.root] + other.chords))
 98        elif isinstance(other, Interval):
 99            transposed_tones = [tone + other for tone in [self.root] + self.chords]
100            return Chord(*transposed_tones)
101        else:
102            raise TypeError("Invalid argument type")
103
104    def __sub__(self, other):
105        if isinstance(other, Tone):
106            if other not in self.chords:
107                raise ValueError(f"Cannot remove tone {str(other)} from chord {str(self)}")
108            if len(self.chords) + 1 < 3:
109                raise TypeError("Cannot have a chord made of only 1 unique tone")
110            if other not in self.chords:
111                raise TypeError(f"Cannot remove tone {str(other)} from chord {str(self)}")
112            if other == self.root:
113                self.root = self.chords[0]
114            new_chords = [tone for tone in self.chords if tone != other]
115            return Chord(self.root, *new_chords)
116        if isinstance(other, Interval):
117            return Chord(self + -other)
118        else:
119            raise TypeError("Invalid argument type")
120    
121    def transposed(self, interval):
122        if isinstance(interval, Interval):
123            transposed_tones = [tone + interval for tone in self.chords]
124            return Chord(self.root + interval, *transposed_tones)
125        else:
126            raise TypeError("Invalid argument type")
127        
128
129# =========================================================================================================================
130# =========================================================================================================================
131# ---------------------------------------------... ТЕСТВАНЕ ...------------------------------------------------------------
132# =========================================================================================================================
133# =========================================================================================================================

....FFF........................E.....
======================================================================
ERROR: test_subtract_tone_from_chord_error (test.TestOperations.test_subtract_tone_from_chord_error)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 292, in test_subtract_tone_from_chord_error
c5_chord - a
~~~~~~~~~^~~
File "/tmp/solution.py", line 107, in __sub__
raise ValueError(f"Cannot remove tone {str(other)} from chord {str(self)}")
ValueError: Cannot remove tone A from chord C-G

======================================================================
FAIL: test_is_major (test.TestBasicChordFunctionality.test_is_major)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 107, in test_is_major
self.assertTrue(a_major_chord.is_major())
AssertionError: False is not true

======================================================================
FAIL: test_is_minor (test.TestBasicChordFunctionality.test_is_minor)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 90, in test_is_minor
self.assertTrue(a_minor_chord.is_minor())
AssertionError: False is not true

======================================================================
FAIL: test_is_power_chord (test.TestBasicChordFunctionality.test_is_power_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 116, in test_is_power_chord
self.assertFalse(a_minor_chord.is_power_chord())
AssertionError: True is not false

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

FAILED (failures=3, errors=1)

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