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

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

6 точки общо

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

  1class Tone:
  2    TONES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
  3
  4    def __init__(self, name):
  5        if name not in self.TONES:
  6            raise ValueError(f"Invalid tone: {name}")
  7        self.name = name
  8
  9    def __str__(self):
 10        return self.name
 11
 12    def __eq__(self, other):
 13        return isinstance(other, Tone) and self.name == other.name
 14
 15#използва хеш стойността на обекта, за да определи къде да го постави, ако има обекти със
 16# същата хеш стойност ги сравнява, за да реши дали тези обекти наистина са равни
 17    def __hash__(self):
 18        return hash(self.name)
 19
 20    def __add__(self, other):
 21        if isinstance(other, Interval):
 22            return self._transposed_by_interval(other)
 23        elif isinstance(other, Tone):
 24            return Chord(self, other)
 25        else:
 26            raise TypeError("Invalid operation")
 27
 28    def __sub__(self, other):
 29        if isinstance(other, Tone):
 30            return self._distance_to(other)
 31
 32        elif isinstance(other, Interval):
 33            return self._transposed_by_interval(other, subtract = True)
 34
 35        else:
 36            raise TypeError("Invalid operation")
 37
 38    def _transposed_by_interval(self, interval, subtract=False):
 39        current_index = self.TONES.index(self.name)
 40
 41        if subtract:
 42            semitone_change = -interval.semitones
 43        else:
 44            semitone_change = interval.semitones
 45
 46        new_index = (current_index + semitone_change) % 12
 47
 48        return Tone(self.TONES[new_index])
 49
 50    def _distance_to(self, other):
 51        current_index = self.TONES.index(self.name)
 52        other_index = self.TONES.index(other.name)
 53
 54        distance = (current_index - other_index) % 12
 55        return Interval(distance)
 56
 57
 58class Interval:
 59    INTERVALS = ["unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd",
 60                 "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th",
 61                 "major 6th", "minor 7th", "major 7th"]
 62
 63    def __init__(self, semitones):
 64        if not isinstance(semitones, int):
 65            raise TypeError("Semitone distance must be an integer")
 66        self.semitones = semitones % 12
 67
 68    def __str__(self):
 69        return self.INTERVALS[self.semitones]
 70
 71    def __add__(self, other):
 72        if isinstance(other, Interval):
 73            return Interval(self.semitones + other.semitones)
 74        raise TypeError("Invalid operation")
 75
 76    def __neg__(self):
 77        return Interval(-self.semitones)
 78
 79
 80class Chord:
 81    def __init__(self, *tones):
 82        if not all(isinstance(tone, Tone) for tone in tones):
 83            raise ValueError("All components must be instances of Tone")
 84
 85        unique = list(set(tones))
 86
 87        if len(unique) < 2:
 88            raise TypeError("A chord must have at least two unique tones")
 89
 90        self.tones = sorted(unique, key=lambda tone: Tone.TONES.index(tone.name))
 91
 92        self.root = self.tones[0]
 93
 94    def __str__(self):
 95        return "-".join(str(tone) for tone in self.tones)
 96
 97    def __add__(self, other):
 98        if isinstance(other, Tone):
 99            if other not in self.tones:
100                return Chord(*self.tones, other)
101            else:
102                return Chord(*self.tones)
103        elif isinstance(other, Chord):
104            combined_tones = list(set(self.tones + other.tones))
105            return Chord(*combined_tones)
106        else:
107            raise TypeError("Invalid operation")
108
109    def __sub__(self, other):
110        if isinstance(other, Tone):
111            if other in self.tones:
112                new_tones = []
113
114                for tone in self.tones:
115                    if tone != other:
116                        new_tones.append(tone)
117
118                if len(new_tones) < 2:
119                    raise TypeError("Cannot have a chord with fewer than 2 unique tones")
120
121                return Chord(*new_tones)
122            else:
123                raise TypeError(f"Tone {other} is not in this chord")
124        return None
125
126    def is_minor(self):
127        return self._has_interval(3)
128
129    def is_major(self):
130        return self._has_interval(4)
131
132    def is_power_chord(self):
133        return not self.is_minor() and not self.is_major()
134
135    def _has_interval(self, interval_semitones):
136        for tone in self.tones[1:]:
137            interval = self.root - tone
138            if interval.semitones == interval_semitones:
139                return True
140        return False
141
142    def transposed(self, interval):
143        if not isinstance(interval, Interval):
144            raise ValueError("Input must be an instance of Interval")
145
146        transposed_tones = []
147
148        for tone in self.tones:
149            transposed_tone = tone + interval
150            transposed_tones.append(transposed_tone)
151
152        return Chord(*transposed_tones)

FFFF.FF..FF..........FFF...F...F.F...
======================================================================
FAIL: test_chord_not_enough_tones (test.TestBasicChordFunctionality.test_chord_not_enough_tones)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 80, in test_chord_not_enough_tones
self.assertEqual(str(err.exception), CANNOT_CHORD_THIS_CHORD)
AssertionError: 'A chord must have at least two unique tones' != 'Cannot have a chord made of only 1 unique tone'
- A chord must have at least two unique tones
+ Cannot have a chord made of only 1 unique tone

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

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

======================================================================
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: 'C-E-A' != 'A-C-E'
- C-E-A
+ A-C-E

======================================================================
FAIL: test_is_minor (test.TestBasicChordFunctionality.test_is_minor)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 98, in test_is_minor
self.assertFalse(a_kind_of_power_chord.is_minor())
AssertionError: True is not false

======================================================================
FAIL: test_is_power_chord (test.TestBasicChordFunctionality.test_is_power_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 124, in test_is_power_chord
self.assertTrue(a_kind_of_power_chord.is_power_chord())
AssertionError: False is not true

======================================================================
FAIL: test_transposed_negative_overflow (test.TestBasicChordFunctionality.test_transposed_negative_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 152, in test_transposed_negative_overflow
self.assertEqual(str(result_chord), "G#-B-D#")
AssertionError: 'D#-G#-B' != 'G#-B-D#'
- D#-G#-B
+ G#-B-D#

======================================================================
FAIL: test_transposed_overflow (test.TestBasicChordFunctionality.test_transposed_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 145, in test_transposed_overflow
self.assertEqual(str(result_chord), "A#-D-F")
AssertionError: 'D-F-A#' != 'A#-D-F'
- D-F-A#
+ A#-D-F

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

======================================================================
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: 'C-F-G#' != 'F-G#-C'
- C-F-G#
+ F-G#-C

======================================================================
FAIL: test_add_tone_to_chord_order (test.TestOperations.test_add_tone_to_chord_order)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 261, in test_add_tone_to_chord_order
self.assertEqual(str(result_chord), "F-G-A-C")
AssertionError: 'C-F-G-A' != 'F-G-A-C'
- C-F-G-A
? --
+ F-G-A-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

======================================================================
FAIL: test_subtract_tone_from_chord_error (test.TestOperations.test_subtract_tone_from_chord_error)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 293, in test_subtract_tone_from_chord_error
self.assertEqual(str(err.exception), expected_message)
AssertionError: 'Tone A is not in this chord' != 'Cannot remove tone A from chord C-G'
- Tone A is not in this chord
+ Cannot remove tone A from chord C-G

======================================================================
FAIL: test_tone_addition_same_tone (test.TestOperations.test_tone_addition_same_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 168, in test_tone_addition_same_tone
self.assertEqual(str(err.exception), CANNOT_CHORD_THIS_CHORD)
AssertionError: 'A chord must have at least two unique tones' != 'Cannot have a chord made of only 1 unique tone'
- A chord must have at least two unique tones
+ Cannot have a chord made of only 1 unique tone

----------------------------------------------------------------------
Ran 37 tests in 0.003s

FAILED (failures=14)

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