Домашни > Pitches love the D > Решения > Решението на Стефан Табаков

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

10 точки общо

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

  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: {name}")
  7        self.name = name
  8
  9    def __str__(self):
 10        return self.name
 11
 12    def __add__(self, other):
 13        if isinstance(other, Tone):
 14            return Chord(self, other)
 15
 16        elif isinstance(other, Interval):
 17
 18            curr_index = self.TONES.index(self.name)
 19            new_index = (curr_index + other.semitones) % 12
 20            new_name = self.TONES[new_index]
 21            return Tone(new_name)
 22        else:
 23            raise TypeError("Invalid operation")
 24
 25    def __sub__(self, other):
 26        if isinstance(other, Tone):
 27            curr_index = self.TONES.index(self.name)
 28            other_index = other.TONES.index(other.name)
 29            semitones = (curr_index - other_index) % 12
 30            return Interval(semitones)
 31
 32        elif isinstance(other, Interval):
 33            curr_index = self.TONES.index(self.name)
 34            new_index = (curr_index - other.semitones) % 12
 35            new_name = self.TONES[new_index]
 36            return Tone(new_name)
 37
 38        else:
 39            raise TypeError("Invalid operation")
 40
 41    def __eq__(self, other):
 42
 43        return isinstance(other, Tone) and self.name == other.name
 44
 45    def __ne__(self, other):
 46        return not self.__eq__(other)
 47
 48
 49class Interval:
 50    INTERVALS = [
 51        "unison", "minor 2nd", "major 2nd", "minor 3rd",
 52        "major 3rd", "perfect 4th", "diminished 5th",
 53        "perfect 5th", "minor 6th", "major 6th",
 54        "minor 7th", "major 7th"
 55    ]
 56
 57    def __init__(self, number_of_semitones):
 58        if isinstance(number_of_semitones, int):
 59            self.semitones = number_of_semitones % 12
 60        else:
 61            raise ValueError(f"Invalid number of semitones")
 62
 63    def __str__(self):
 64        return self.INTERVALS[self.semitones]
 65
 66    def __add__(self, other):
 67        if isinstance(other, Interval):
 68            return Interval(self.semitones + other.semitones)
 69        raise TypeError("Invalid operation")
 70
 71    def __neg__(self):
 72        return Interval(-self.semitones)
 73
 74
 75class Chord:
 76    def __init__(self, root, *args):
 77        if isinstance(root, Tone):
 78            for tone in args:
 79                if not isinstance(tone, Tone):
 80                    raise ValueError("All arguments must of type Tone")
 81            self.root = root
 82            self.tones = []
 83            self.tones.append(root)
 84            for tone in args:
 85                if tone not in self.tones:
 86                    self.tones.append(tone)
 87        else:
 88            raise ValueError("Root must be type Tone")
 89
 90        if len(self.tones) < 2:
 91            raise TypeError("Cannot have a chord made of only 1 unique tone")
 92
 93    def __str__(self):
 94
 95        tones_no_root = [tone for tone in self.tones if tone != self.root]
 96        root_index = Tone.TONES.index(self.root.name)
 97
 98        def tone_sort_key(tone):
 99            cur_index = Tone.TONES.index(tone.name)
100            return (cur_index - root_index) % 12
101
102        sorted_tones = [self.root] + sorted(tones_no_root, key=tone_sort_key)
103        return '-'.join(str(tone) for tone in sorted_tones)
104
105    def is_minor(self):
106        root_index = Tone.TONES.index(self.root.name)
107        for tone in self.tones:
108            if tone == self.root:
109                continue
110            cur_index = Tone.TONES.index(tone.name)
111            interval = (cur_index - root_index) % 12
112            if interval == 3:
113                return True
114        return False
115
116    def is_major(self):
117        root_index = Tone.TONES.index(self.root.name)
118        for tone in self.tones:
119            if tone == self.root:
120                continue
121            cur_index = Tone.TONES.index(tone.name)
122            interval = (cur_index - root_index) % 12
123            if interval == 4:
124                return True
125        return False
126
127    def is_power_chord(self):
128        return not self.is_minor() and not self.is_major()
129
130    def __add__(self, other):
131        if isinstance(other, Tone):
132            new_tones = self.tones.copy()
133            if other not in new_tones:
134                new_tones.append(other)
135            return Chord(self.root, *[tone for tone in new_tones if tone != self.root])
136        elif isinstance(other, Chord):
137            new_tones = list(self.tones)
138            for tone in other.tones:
139                if tone not in self.tones:
140                    new_tones.append(tone)
141            return Chord(self.root, *[tone for tone in new_tones if tone != self.root])
142        else:
143            raise TypeError("Invalid operation")
144
145    def __sub__(self, other):
146        if isinstance(other, Tone):
147            if other not in self.tones:
148                raise TypeError(f"Cannot remove tone {other} from chord {self}")
149            if other == self.root:
150                raise TypeError(f"Cannot remove tone {other} from chord {self}")
151            new_tones = [tone for tone in self.tones if tone != other]
152            if len(new_tones) <= 1:
153                raise TypeError("Cannot have a chord made of only 1 unique tone")
154            return Chord(self.root, *[tone for tone in new_tones if tone != self.root])
155        else:
156            raise TypeError("Invalid operation")
157
158    def transposed(self, interval):
159        if not isinstance(interval, Interval):
160            raise TypeError("Interval expected")
161        new_tones = []
162        root_index = Tone.TONES.index(self.root.name)
163        for tone in self.tones:
164            cur_index = Tone.TONES.index(tone.name)
165            new_index = (cur_index + interval.semitones) % 12
166            new_name = Tone.TONES[new_index]
167            new_tone = Tone(new_name)
168            if new_tone not in new_tones:
169                new_tones.append(new_tone)
170        new_root_index = (root_index + interval.semitones) % 12
171        new_root_name = Tone.TONES[new_root_index]
172        new_root = Tone(new_root_name)
173        return Chord(new_root, *[tone for tone in new_tones if tone != new_root])

...........................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

----------------------------------------------------------------------
Ran 37 tests in 0.001s

FAILED (failures=1)

Дискусия
История

t1class Tone:t1class Tone:
2    TONES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]2    TONES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
33
4    def __init__(self, name):4    def __init__(self, name):
5        if name not in self.TONES:5        if name not in self.TONES:
6            raise ValueError(f"Invalid tone name: {name}")6            raise ValueError(f"Invalid tone name: {name}")
7        self.name = name7        self.name = name
88
9    def __str__(self):9    def __str__(self):
10        return self.name10        return self.name
1111
12    def __add__(self, other):12    def __add__(self, other):
13        if isinstance(other, Tone):13        if isinstance(other, Tone):
14            return Chord(self, other)14            return Chord(self, other)
1515
16        elif isinstance(other, Interval):16        elif isinstance(other, Interval):
1717
18            curr_index = self.TONES.index(self.name)18            curr_index = self.TONES.index(self.name)
19            new_index = (curr_index + other.semitones) % 1219            new_index = (curr_index + other.semitones) % 12
20            new_name = self.TONES[new_index]20            new_name = self.TONES[new_index]
21            return Tone(new_name)21            return Tone(new_name)
22        else:22        else:
23            raise TypeError("Invalid operation")23            raise TypeError("Invalid operation")
2424
25    def __sub__(self, other):25    def __sub__(self, other):
26        if isinstance(other, Tone):26        if isinstance(other, Tone):
27            curr_index = self.TONES.index(self.name)27            curr_index = self.TONES.index(self.name)
28            other_index = other.TONES.index(other.name)28            other_index = other.TONES.index(other.name)
29            semitones = (curr_index - other_index) % 1229            semitones = (curr_index - other_index) % 12
30            return Interval(semitones)30            return Interval(semitones)
3131
32        elif isinstance(other, Interval):32        elif isinstance(other, Interval):
33            curr_index = self.TONES.index(self.name)33            curr_index = self.TONES.index(self.name)
34            new_index = (curr_index - other.semitones) % 1234            new_index = (curr_index - other.semitones) % 12
35            new_name = self.TONES[new_index]35            new_name = self.TONES[new_index]
36            return Tone(new_name)36            return Tone(new_name)
3737
38        else:38        else:
39            raise TypeError("Invalid operation")39            raise TypeError("Invalid operation")
4040
41    def __eq__(self, other):41    def __eq__(self, other):
4242
43        return isinstance(other, Tone) and self.name == other.name43        return isinstance(other, Tone) and self.name == other.name
4444
45    def __ne__(self, other):45    def __ne__(self, other):
46        return not self.__eq__(other)46        return not self.__eq__(other)
4747
4848
49class Interval:49class Interval:
50    INTERVALS = [50    INTERVALS = [
51        "unison", "minor 2nd", "major 2nd", "minor 3rd",51        "unison", "minor 2nd", "major 2nd", "minor 3rd",
52        "major 3rd", "perfect 4th", "diminished 5th",52        "major 3rd", "perfect 4th", "diminished 5th",
53        "perfect 5th", "minor 6th", "major 6th",53        "perfect 5th", "minor 6th", "major 6th",
54        "minor 7th", "major 7th"54        "minor 7th", "major 7th"
55    ]55    ]
5656
57    def __init__(self, number_of_semitones):57    def __init__(self, number_of_semitones):
58        if isinstance(number_of_semitones, int):58        if isinstance(number_of_semitones, int):
59            self.semitones = number_of_semitones % 1259            self.semitones = number_of_semitones % 12
60        else:60        else:
61            raise ValueError(f"Invalid number of semitones")61            raise ValueError(f"Invalid number of semitones")
6262
63    def __str__(self):63    def __str__(self):
64        return self.INTERVALS[self.semitones]64        return self.INTERVALS[self.semitones]
6565
66    def __add__(self, other):66    def __add__(self, other):
67        if isinstance(other, Interval):67        if isinstance(other, Interval):
68            return Interval(self.semitones + other.semitones)68            return Interval(self.semitones + other.semitones)
69        raise TypeError("Invalid operation")69        raise TypeError("Invalid operation")
7070
71    def __neg__(self):71    def __neg__(self):
72        return Interval(-self.semitones)72        return Interval(-self.semitones)
7373
7474
75class Chord:75class Chord:
76    def __init__(self, root, *args):76    def __init__(self, root, *args):
77        if isinstance(root, Tone):77        if isinstance(root, Tone):
78            for tone in args:78            for tone in args:
79                if not isinstance(tone, Tone):79                if not isinstance(tone, Tone):
80                    raise ValueError("All arguments must of type Tone")80                    raise ValueError("All arguments must of type Tone")
81            self.root = root81            self.root = root
82            self.tones = []82            self.tones = []
83            self.tones.append(root)83            self.tones.append(root)
84            for tone in args:84            for tone in args:
85                if tone not in self.tones:85                if tone not in self.tones:
86                    self.tones.append(tone)86                    self.tones.append(tone)
87        else:87        else:
88            raise ValueError("Root must be type Tone")88            raise ValueError("Root must be type Tone")
8989
90        if len(self.tones) < 2:90        if len(self.tones) < 2:
91            raise TypeError("Cannot have a chord made of only 1 unique tone")91            raise TypeError("Cannot have a chord made of only 1 unique tone")
9292
93    def __str__(self):93    def __str__(self):
9494
95        tones_no_root = [tone for tone in self.tones if tone != self.root]95        tones_no_root = [tone for tone in self.tones if tone != self.root]
96        root_index = Tone.TONES.index(self.root.name)96        root_index = Tone.TONES.index(self.root.name)
9797
98        def tone_sort_key(tone):98        def tone_sort_key(tone):
99            cur_index = Tone.TONES.index(tone.name)99            cur_index = Tone.TONES.index(tone.name)
100            return (cur_index - root_index) % 12100            return (cur_index - root_index) % 12
101101
102        sorted_tones = [self.root] + sorted(tones_no_root, key=tone_sort_key)102        sorted_tones = [self.root] + sorted(tones_no_root, key=tone_sort_key)
103        return '-'.join(str(tone) for tone in sorted_tones)103        return '-'.join(str(tone) for tone in sorted_tones)
104104
105    def is_minor(self):105    def is_minor(self):
106        root_index = Tone.TONES.index(self.root.name)106        root_index = Tone.TONES.index(self.root.name)
107        for tone in self.tones:107        for tone in self.tones:
108            if tone == self.root:108            if tone == self.root:
109                continue109                continue
110            cur_index = Tone.TONES.index(tone.name)110            cur_index = Tone.TONES.index(tone.name)
111            interval = (cur_index - root_index) % 12111            interval = (cur_index - root_index) % 12
112            if interval == 3:112            if interval == 3:
113                return True113                return True
114        return False114        return False
115115
116    def is_major(self):116    def is_major(self):
117        root_index = Tone.TONES.index(self.root.name)117        root_index = Tone.TONES.index(self.root.name)
118        for tone in self.tones:118        for tone in self.tones:
119            if tone == self.root:119            if tone == self.root:
120                continue120                continue
121            cur_index = Tone.TONES.index(tone.name)121            cur_index = Tone.TONES.index(tone.name)
122            interval = (cur_index - root_index) % 12122            interval = (cur_index - root_index) % 12
123            if interval == 4:123            if interval == 4:
124                return True124                return True
125        return False125        return False
126126
127    def is_power_chord(self):127    def is_power_chord(self):
128        return not self.is_minor() and not self.is_major()128        return not self.is_minor() and not self.is_major()
129129
130    def __add__(self, other):130    def __add__(self, other):
131        if isinstance(other, Tone):131        if isinstance(other, Tone):
132            new_tones = self.tones.copy()132            new_tones = self.tones.copy()
133            if other not in new_tones:133            if other not in new_tones:
134                new_tones.append(other)134                new_tones.append(other)
135            return Chord(self.root, *[tone for tone in new_tones if tone != self.root])135            return Chord(self.root, *[tone for tone in new_tones if tone != self.root])
136        elif isinstance(other, Chord):136        elif isinstance(other, Chord):
137            new_tones = list(self.tones)137            new_tones = list(self.tones)
138            for tone in other.tones:138            for tone in other.tones:
139                if tone not in self.tones:139                if tone not in self.tones:
140                    new_tones.append(tone)140                    new_tones.append(tone)
141            return Chord(self.root, *[tone for tone in new_tones if tone != self.root])141            return Chord(self.root, *[tone for tone in new_tones if tone != self.root])
142        else:142        else:
143            raise TypeError("Invalid operation")143            raise TypeError("Invalid operation")
144144
145    def __sub__(self, other):145    def __sub__(self, other):
146        if isinstance(other, Tone):146        if isinstance(other, Tone):
147            if other not in self.tones:147            if other not in self.tones:
148                raise TypeError(f"Cannot remove tone {other} from chord {self}")148                raise TypeError(f"Cannot remove tone {other} from chord {self}")
149            if other == self.root:149            if other == self.root:
150                raise TypeError(f"Cannot remove tone {other} from chord {self}")150                raise TypeError(f"Cannot remove tone {other} from chord {self}")
151            new_tones = [tone for tone in self.tones if tone != other]151            new_tones = [tone for tone in self.tones if tone != other]
152            if len(new_tones) <= 1:152            if len(new_tones) <= 1:
153                raise TypeError("Cannot have a chord made of only 1 unique tone")153                raise TypeError("Cannot have a chord made of only 1 unique tone")
154            return Chord(self.root, *[tone for tone in new_tones if tone != self.root])154            return Chord(self.root, *[tone for tone in new_tones if tone != self.root])
155        else:155        else:
156            raise TypeError("Invalid operation")156            raise TypeError("Invalid operation")
157157
158    def transposed(self, interval):158    def transposed(self, interval):
159        if not isinstance(interval, Interval):159        if not isinstance(interval, Interval):
160            raise TypeError("Interval expected")160            raise TypeError("Interval expected")
161        new_tones = []161        new_tones = []
162        root_index = Tone.TONES.index(self.root.name)162        root_index = Tone.TONES.index(self.root.name)
163        for tone in self.tones:163        for tone in self.tones:
164            cur_index = Tone.TONES.index(tone.name)164            cur_index = Tone.TONES.index(tone.name)
165            new_index = (cur_index + interval.semitones) % 12165            new_index = (cur_index + interval.semitones) % 12
166            new_name = Tone.TONES[new_index]166            new_name = Tone.TONES[new_index]
167            new_tone = Tone(new_name)167            new_tone = Tone(new_name)
168            if new_tone not in new_tones:168            if new_tone not in new_tones:
169                new_tones.append(new_tone)169                new_tones.append(new_tone)
170        new_root_index = (root_index + interval.semitones) % 12170        new_root_index = (root_index + interval.semitones) % 12
171        new_root_name = Tone.TONES[new_root_index]171        new_root_name = Tone.TONES[new_root_index]
172        new_root = Tone(new_root_name)172        new_root = Tone(new_root_name)
173        return Chord(new_root, *[tone for tone in new_tones if tone != new_root])173        return Chord(new_root, *[tone for tone in new_tones if tone != new_root])
174174
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op