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

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

10 точки общо

35 успешни теста
2 неуспешни теста
Код

  1class Tone:
  2    NAME_DOMAIN = ("A", "A#", "B", "C", "C#", "D",
  3                   "D#", "E", "F", "F#", "G", "G#")
  4
  5    def __init__(self, tone_name):
  6        self.name_index = Tone.NAME_DOMAIN.index(tone_name)
  7
  8    def __str__(self):
  9        return Tone.NAME_DOMAIN[self.name_index]
 10
 11    def __eq__(self, other):
 12        if isinstance(other, Tone):
 13            return self.name_index == other.name_index
 14        raise TypeError("Invalid operation")
 15
 16    def __hash__(self):
 17        return hash(self.name_index)
 18
 19    def __add__(self, other):
 20        if isinstance(other, Tone):
 21            return Chord(self, other)
 22        elif isinstance(other, Interval):
 23            return Tone(Tone.NAME_DOMAIN[(self.name_index +
 24                                          other.interval_name_index)
 25                                         % len(Tone.NAME_DOMAIN)])
 26        raise TypeError("Invalid operation")
 27
 28    def __sub__(self, other):
 29        if isinstance(other, Tone):
 30            return Interval(abs(self.name_index - other.name_index))
 31        elif isinstance(other, Interval):
 32            return Tone(Tone.NAME_DOMAIN[(self.name_index -
 33                                          other.interval_name_index)
 34                                         % len(Tone.NAME_DOMAIN)])
 35        raise TypeError("Invalid operation")
 36
 37
 38class Interval:
 39    INTERVAL_NAME_DOMAIN = ("unison", "minor 2nd", "major 2nd", "minor 3rd",
 40                            "major 3rd", "perfect 4th", "diminished 5th",
 41                            "perfect 5th", "minor 6th", "major 6th",
 42                            "minor 7th", "major 7th")
 43
 44    def __init__(self, number_of_semitones):
 45        self.interval_name_index = (number_of_semitones %
 46                                    len(Interval.INTERVAL_NAME_DOMAIN))
 47
 48    def __str__(self):
 49        return Interval.INTERVAL_NAME_DOMAIN[self.interval_name_index]
 50
 51    def __eq__(self, other):
 52        if isinstance(other, Interval):
 53            return self.interval_name_index == other.interval_name_index
 54        raise TypeError("Invalid operation")
 55
 56    def __neg__(self):
 57        return Interval(-self.interval_name_index)
 58
 59    def __add__(self, other):
 60        if isinstance(other, Interval):
 61            return Interval(self.interval_name_index +
 62                            other.interval_name_index)
 63        raise TypeError("Invalid operation")
 64
 65
 66class Chord:
 67    major_chord_interval = Interval(4)
 68    minor_chord_interval = Interval(3)
 69
 70    def __init__(self, root_tone: Tone, *additional_tones: Tone):
 71        self.tones = []
 72        self.tones.append(root_tone)
 73
 74        additional_tones = {tone for tone in additional_tones
 75                            if tone != root_tone}
 76
 77        if len(additional_tones) == 0:
 78            raise TypeError("Cannot have a chord made of only 1 unique tone")
 79
 80        temp_tones = []
 81        current_tone = self.tones[0] + Interval(1)
 82
 83        while current_tone != self.tones[0]:
 84            if current_tone in additional_tones:
 85                temp_tones.append(current_tone)
 86            current_tone = current_tone + Interval(1)
 87
 88        self.tones.extend(temp_tones)
 89
 90    def __str__(self):
 91        return "-".join([str(tone) for tone in self.tones])
 92
 93    def __add__(self, other):
 94        if isinstance(other, Tone):
 95            return Chord(*self.tones, other)
 96        elif isinstance(other, Chord):
 97            return Chord(*self.tones, *other.tones)
 98        raise TypeError("Invalid operation")
 99
100    def __sub__(self, other):
101        if isinstance(other, Tone):
102            if other not in self.tones:
103                raise TypeError(f"Cannot remove tone {other} from chord "
104                                f"{self}")
105            elif len(self.tones) == 2:
106                raise TypeError("Cannot have a chord made of only 1 unique "
107                                "tone")
108
109            return Chord(*[tone for tone in self.tones if tone != other])
110        raise TypeError("Invalid operation")
111
112    def is_major(self) -> bool:
113        root_tone_index = self.tones[0].name_index
114
115        for secondary_tone in self.tones[1:]:
116            temp_interval = Interval(abs(root_tone_index -
117                                         secondary_tone.name_index))
118
119            if temp_interval == Chord.major_chord_interval:
120                return True
121
122        return False
123
124    def is_minor(self) -> bool:
125        root_tone_index = self.tones[0].name_index
126
127        for secondary_tone in self.tones[1:]:
128            temp_interval = Interval(abs(root_tone_index -
129                                         secondary_tone.name_index))
130
131            if temp_interval == Chord.minor_chord_interval:
132                return True
133
134        return False
135
136    def is_power_chord(self) -> bool:
137        root_tone_index = self.tones[0].name_index
138
139        for secondary_tone in self.tones[1:]:
140            temp_interval = Interval(abs(root_tone_index -
141                                         secondary_tone.name_index))
142
143            if (temp_interval == Chord.major_chord_interval
144                    or temp_interval == Chord.minor_chord_interval):
145                return False
146
147        return True
148
149    def transposed(self, interval: Interval):
150        return Chord(*[tone + interval for tone in self.tones])

...........................F.......F.
======================================================================
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_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=2)

Дискусия
Виктор Бечев
04.11.2024 11:46

PyCharm нещо не е наред, ако списъците не дефинират `__getitem__` - не знам какво. Нищо от това, което си споменал не променя този факт. Just PyCharm being drunk, I guess.
Димитър Танков
04.11.2024 00:37

На 81 ред PyCharm изписва "Class 'list' does not define '__getitem__', so the '[]' operator cannot be used on its instances", което ме обърка. Възможно ли е да е обвързано с факта, че използвам елемент от self.tones list-а в условието на цикъла и след това променям temp_tones, което може да е нещо като shallow copy на self.tones, поради оптимизация.
Димитър Танков
04.11.2024 00:32

Да кажем, че имам бегло понятие за теория на музиката, понеже съм свирил на китара😁
История

f1class Tone:f1class Tone:
n2    name_domain = ("A", "A#", "B", "C", "C#", "D",n2    NAME_DOMAIN = ("A", "A#", "B", "C", "C#", "D",
3                   "D#", "E", "F", "F#", "G", "G#")3                   "D#", "E", "F", "F#", "G", "G#")
44
5    def __init__(self, tone_name):5    def __init__(self, tone_name):
n6        self.name_index = Tone.name_domain.index(tone_name)n6        self.name_index = Tone.NAME_DOMAIN.index(tone_name)
77
8    def __str__(self):8    def __str__(self):
n9        return Tone.name_domain[self.name_index]n9        return Tone.NAME_DOMAIN[self.name_index]
1010
11    def __eq__(self, other):11    def __eq__(self, other):
12        if isinstance(other, Tone):12        if isinstance(other, Tone):
13            return self.name_index == other.name_index13            return self.name_index == other.name_index
n14        return Falsen14        raise TypeError("Invalid operation")
1515
16    def __hash__(self):16    def __hash__(self):
17        return hash(self.name_index)17        return hash(self.name_index)
1818
19    def __add__(self, other):19    def __add__(self, other):
20        if isinstance(other, Tone):20        if isinstance(other, Tone):
21            return Chord(self, other)21            return Chord(self, other)
22        elif isinstance(other, Interval):22        elif isinstance(other, Interval):
n23            return Tone(Tone.name_domain[(self.name_index +n23            return Tone(Tone.NAME_DOMAIN[(self.name_index +
24                                          other.interval_name_index)24                                          other.interval_name_index)
n25                                         % len(Tone.name_domain)])n25                                         % len(Tone.NAME_DOMAIN)])
26        raise TypeError("Invalid operation")26        raise TypeError("Invalid operation")
2727
28    def __sub__(self, other):28    def __sub__(self, other):
29        if isinstance(other, Tone):29        if isinstance(other, Tone):
30            return Interval(abs(self.name_index - other.name_index))30            return Interval(abs(self.name_index - other.name_index))
31        elif isinstance(other, Interval):31        elif isinstance(other, Interval):
n32            return Tone(Tone.name_domain[(self.name_index -n32            return Tone(Tone.NAME_DOMAIN[(self.name_index -
33                                          other.interval_name_index)33                                          other.interval_name_index)
n34                                         % len(Tone.name_domain)])n34                                         % len(Tone.NAME_DOMAIN)])
35        raise TypeError("Invalid operation")35        raise TypeError("Invalid operation")
3636
3737
38class Interval:38class Interval:
n39    interval_name_domain = ("unison", "minor 2nd", "major 2nd", "minor 3rd",n39    INTERVAL_NAME_DOMAIN = ("unison", "minor 2nd", "major 2nd", "minor 3rd",
40                            "major 3rd", "perfect 4th", "diminished 5th",40                            "major 3rd", "perfect 4th", "diminished 5th",
41                            "perfect 5th", "minor 6th", "major 6th",41                            "perfect 5th", "minor 6th", "major 6th",
42                            "minor 7th", "major 7th")42                            "minor 7th", "major 7th")
4343
44    def __init__(self, number_of_semitones):44    def __init__(self, number_of_semitones):
45        self.interval_name_index = (number_of_semitones %45        self.interval_name_index = (number_of_semitones %
n46                                    len(Interval.interval_name_domain))n46                                    len(Interval.INTERVAL_NAME_DOMAIN))
4747
48    def __str__(self):48    def __str__(self):
n49        return Interval.interval_name_domain[self.interval_name_index]n49        return Interval.INTERVAL_NAME_DOMAIN[self.interval_name_index]
5050
51    def __eq__(self, other):51    def __eq__(self, other):
52        if isinstance(other, Interval):52        if isinstance(other, Interval):
53            return self.interval_name_index == other.interval_name_index53            return self.interval_name_index == other.interval_name_index
t54        return Falset54        raise TypeError("Invalid operation")
5555
56    def __neg__(self):56    def __neg__(self):
57        return Interval(-self.interval_name_index)57        return Interval(-self.interval_name_index)
5858
59    def __add__(self, other):59    def __add__(self, other):
60        if isinstance(other, Interval):60        if isinstance(other, Interval):
61            return Interval(self.interval_name_index +61            return Interval(self.interval_name_index +
62                            other.interval_name_index)62                            other.interval_name_index)
63        raise TypeError("Invalid operation")63        raise TypeError("Invalid operation")
6464
6565
66class Chord:66class Chord:
67    major_chord_interval = Interval(4)67    major_chord_interval = Interval(4)
68    minor_chord_interval = Interval(3)68    minor_chord_interval = Interval(3)
6969
70    def __init__(self, root_tone: Tone, *additional_tones: Tone):70    def __init__(self, root_tone: Tone, *additional_tones: Tone):
71        self.tones = []71        self.tones = []
72        self.tones.append(root_tone)72        self.tones.append(root_tone)
7373
74        additional_tones = {tone for tone in additional_tones74        additional_tones = {tone for tone in additional_tones
75                            if tone != root_tone}75                            if tone != root_tone}
7676
77        if len(additional_tones) == 0:77        if len(additional_tones) == 0:
78            raise TypeError("Cannot have a chord made of only 1 unique tone")78            raise TypeError("Cannot have a chord made of only 1 unique tone")
7979
80        temp_tones = []80        temp_tones = []
81        current_tone = self.tones[0] + Interval(1)81        current_tone = self.tones[0] + Interval(1)
8282
83        while current_tone != self.tones[0]:83        while current_tone != self.tones[0]:
84            if current_tone in additional_tones:84            if current_tone in additional_tones:
85                temp_tones.append(current_tone)85                temp_tones.append(current_tone)
86            current_tone = current_tone + Interval(1)86            current_tone = current_tone + Interval(1)
8787
88        self.tones.extend(temp_tones)88        self.tones.extend(temp_tones)
8989
90    def __str__(self):90    def __str__(self):
91        return "-".join([str(tone) for tone in self.tones])91        return "-".join([str(tone) for tone in self.tones])
9292
93    def __add__(self, other):93    def __add__(self, other):
94        if isinstance(other, Tone):94        if isinstance(other, Tone):
95            return Chord(*self.tones, other)95            return Chord(*self.tones, other)
96        elif isinstance(other, Chord):96        elif isinstance(other, Chord):
97            return Chord(*self.tones, *other.tones)97            return Chord(*self.tones, *other.tones)
98        raise TypeError("Invalid operation")98        raise TypeError("Invalid operation")
9999
100    def __sub__(self, other):100    def __sub__(self, other):
101        if isinstance(other, Tone):101        if isinstance(other, Tone):
102            if other not in self.tones:102            if other not in self.tones:
103                raise TypeError(f"Cannot remove tone {other} from chord "103                raise TypeError(f"Cannot remove tone {other} from chord "
104                                f"{self}")104                                f"{self}")
105            elif len(self.tones) == 2:105            elif len(self.tones) == 2:
106                raise TypeError("Cannot have a chord made of only 1 unique "106                raise TypeError("Cannot have a chord made of only 1 unique "
107                                "tone")107                                "tone")
108108
109            return Chord(*[tone for tone in self.tones if tone != other])109            return Chord(*[tone for tone in self.tones if tone != other])
110        raise TypeError("Invalid operation")110        raise TypeError("Invalid operation")
111111
112    def is_major(self) -> bool:112    def is_major(self) -> bool:
113        root_tone_index = self.tones[0].name_index113        root_tone_index = self.tones[0].name_index
114114
115        for secondary_tone in self.tones[1:]:115        for secondary_tone in self.tones[1:]:
116            temp_interval = Interval(abs(root_tone_index -116            temp_interval = Interval(abs(root_tone_index -
117                                         secondary_tone.name_index))117                                         secondary_tone.name_index))
118118
119            if temp_interval == Chord.major_chord_interval:119            if temp_interval == Chord.major_chord_interval:
120                return True120                return True
121121
122        return False122        return False
123123
124    def is_minor(self) -> bool:124    def is_minor(self) -> bool:
125        root_tone_index = self.tones[0].name_index125        root_tone_index = self.tones[0].name_index
126126
127        for secondary_tone in self.tones[1:]:127        for secondary_tone in self.tones[1:]:
128            temp_interval = Interval(abs(root_tone_index -128            temp_interval = Interval(abs(root_tone_index -
129                                         secondary_tone.name_index))129                                         secondary_tone.name_index))
130130
131            if temp_interval == Chord.minor_chord_interval:131            if temp_interval == Chord.minor_chord_interval:
132                return True132                return True
133133
134        return False134        return False
135135
136    def is_power_chord(self) -> bool:136    def is_power_chord(self) -> bool:
137        root_tone_index = self.tones[0].name_index137        root_tone_index = self.tones[0].name_index
138138
139        for secondary_tone in self.tones[1:]:139        for secondary_tone in self.tones[1:]:
140            temp_interval = Interval(abs(root_tone_index -140            temp_interval = Interval(abs(root_tone_index -
141                                         secondary_tone.name_index))141                                         secondary_tone.name_index))
142142
143            if (temp_interval == Chord.major_chord_interval143            if (temp_interval == Chord.major_chord_interval
144                    or temp_interval == Chord.minor_chord_interval):144                    or temp_interval == Chord.minor_chord_interval):
145                return False145                return False
146146
147        return True147        return True
148148
149    def transposed(self, interval: Interval):149    def transposed(self, interval: Interval):
150        return Chord(*[tone + interval for tone in self.tones])150        return Chord(*[tone + interval for tone in self.tones])
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op