1class Tone:
2 CHROMATIC_SCALE = [ "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" ]
3
4 def __init__(self, name):
5 self.name = name
6
7 def __str__(self):
8 return self.name
9
10 def __eq__(self, other):
11 if isinstance(other, Tone):
12 return self.name == other.name
13 return False
14
15 def __add__(self, other):
16 if isinstance(other, Tone):
17 return Chord(self, other)
18 if isinstance(other, Interval):
19 new_index = (self._get_chromatic_index() + other.number_of_semitones) % 12
20 return Tone(Tone.CHROMATIC_SCALE[new_index])
21 else:
22 raise TypeError("Invalid operation")
23
24 def __sub__(self, other):
25 if isinstance(other, Tone):
26 semitone_diff = (self._get_chromatic_index() - other._get_chromatic_index()) % 12
27 return Interval(semitone_diff)
28 if isinstance(other, Interval):
29 new_index = (self._get_chromatic_index() - other.number_of_semitones) % 12
30 return Tone(Tone.CHROMATIC_SCALE[new_index])
31 else:
32 raise TypeError("Invalid operation")
33
34 def _get_chromatic_index(self):
35 return Tone.CHROMATIC_SCALE.index(self.name)
36
37class Interval:
38 INTERVAL_NAMES = {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"}
39
40 def __init__(self, number_of_semitones):
41 self.number_of_semitones = number_of_semitones % 12
42
43 def __str__(self):
44 return self.INTERVAL_NAMES.get(self.number_of_semitones, "unknown interval")
45
46 def __add__(self, other):
47 if isinstance(other, Interval):
48 new_semitones = (self.number_of_semitones + other.number_of_semitones) % 12
49 return Interval(new_semitones)
50 else:
51 raise TypeError("Invalid operation")
52
53class Chord:
54 def __init__(self, root_tone, *tones):
55 if not isinstance(root_tone, Tone):
56 raise TypeError("The root tone must be an instance of class Tone")
57 self.root_tone = root_tone
58 unique_tones = []
59 unique_tone_names = set()
60 for tone in (root_tone, *tones):
61 if isinstance(tone, Tone) and tone.name not in unique_tone_names:
62 unique_tones.append(tone)
63 unique_tone_names.add(tone.name)
64 if len(unique_tones) < 2:
65 raise TypeError("Cannot have a chord made of only 1 unique tone")
66 self.tones = unique_tones
67
68 def is_minor(self):
69 root_index = self.root_tone._get_chromatic_index()
70 for tone in self.tones:
71 if tone != self.root_tone:
72 interval_semitones = (tone._get_chromatic_index() - root_index) % 12
73 if interval_semitones == 3:
74 return True
75 return False
76
77 def is_major(self):
78 root_index = self.root_tone._get_chromatic_index()
79 for tone in self.tones:
80 if tone != self.root_tone:
81 interval_semitones = (tone._get_chromatic_index() - root_index) % 12
82 if interval_semitones == 4:
83 return True
84 return False
85
86 def is_power_chord(self):
87 root_index = self.root_tone._get_chromatic_index()
88 for tone in self.tones:
89 if tone != self.root_tone:
90 interval_semitones = (tone._get_chromatic_index() - root_index) % 12
91 if interval_semitones != 3 and interval_semitones != 4:
92 return True
93 return False
94
95 def __add__(self, other):
96 if isinstance(other, Tone):
97 if other not in self.tones:
98 new_chord = Chord(self.root_tone, *self.tones, other)
99 return new_chord
100 else:
101 return self
102 if isinstance(other, Chord):
103 combined_tones = list(self.tones) + list(other.tones)
104 return Chord(self.root_tone, *combined_tones)
105 else:
106 raise TypeError("Invalid operation")
107
108 def __sub__(self, other):
109 if isinstance(other, Tone):
110 if other not in self.tones:
111 raise TypeError(f"Cannot remove tone {other} from chord {self}")
112 new_tones = [tone for tone in self.tones if tone != other]
113 if len(new_tones) < 2:
114 raise TypeError("Cannot have a chord made of only 1 unique tone")
115 return Chord(self.root_tone, *new_tones)
116 else:
117 raise TypeError("Invalid operation")
118
119 def __str__(self):
120 sorted_tones = sorted(self.tones, key=lambda tone: tone._get_chromatic_index())
121 return '-'.join(str(tone) for tone in sorted_tones)
122
123 def transposed(self, interval):
124 if isinstance(interval, Interval):
125 transposed_tones = []
126 for tone in self.tones:
127 transposed_tone = tone + interval
128 transposed_tones.append(transposed_tone)
129 return Chord(transposed_tones[0], *transposed_tones)
130 else:
131 raise TypeError("Invalid operation")
.FFF..F.EEFE.........FFF...F.........
======================================================================
ERROR: test_transposed_negative (test.TestBasicChordFunctionality.test_transposed_negative)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 136, in test_transposed_negative
result_chord = e_minor_chord.transposed(-Interval(2))
^^^^^^^^^^^^
TypeError: bad operand type for unary -: 'Interval'
======================================================================
ERROR: test_transposed_negative_overflow (test.TestBasicChordFunctionality.test_transposed_negative_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 150, in test_transposed_negative_overflow
result_chord = e_minor_chord.transposed(-Interval(8))
^^^^^^^^^^^^
TypeError: bad operand type for unary -: 'Interval'
======================================================================
ERROR: test_interval_negative (test.TestBasicIntervalFunctionality.test_interval_negative)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 50, in test_interval_negative
minor_2nd = -major_7th
^^^^^^^^^^
TypeError: bad operand type for unary -: 'Interval'
======================================================================
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_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_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
----------------------------------------------------------------------
Ran 37 tests in 0.003s
FAILED (failures=9, errors=3)
Георги Кунчев
06.11.2024 20:23Решението е предадено след крайния срок.
Качено е от мен, ръчно, за да дадем обратна връзка, но не получава точки.
|
07.11.2024 12:16
07.11.2024 12:17
07.11.2024 12:17
07.11.2024 12:19
07.11.2024 12:18
07.11.2024 12:19
07.11.2024 12:20
07.11.2024 12:20
07.11.2024 12:22
07.11.2024 12:23
07.11.2024 12:23
07.11.2024 12:24