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

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

9 точки общо

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

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

....FFF............................F.
======================================================================
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

======================================================================
FAIL: test_tone_subtraction_inverse (test.TestOperations.test_tone_subtraction_inverse)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 178, in test_tone_subtraction_inverse
self.assertEqual(str(perfect_4th), "perfect 4th")
AssertionError: 'perfect 5th' != 'perfect 4th'
- perfect 5th
? ^
+ perfect 4th
? ^

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

FAILED (failures=4)

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