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

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

5 точки общо

19 успешни теста
18 неуспешни теста
Код (омазах го :))
Скрий всички коментари

  1# -*- coding: utf-8 -*-
  2"""
  3Created on Sun Nov  3 17:03:13 2024
  4
  5@author: User
  6    """    
  7intervals = [
  8        "unison", "minor 2nd", "major 2nd", "minor 3rd", "major 3rd",
  9           "perfect 4th", "diminished 5th", "perfect 5th", "minor 6th",
 10           "major 6th", "minor 7th", "major 7th", "octave"
 11    ]
 12
 13scale = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
 14
 15
 16def sort_tones(root, unique_elements):
 17    l = []
 18    if root.name in scale:
 19        ind = scale.index(root.name)
 20        
 21        for i in range(ind, 11):
 22            if scale[i] in [ul.name for ul in unique_elements]:
 23                l.append(scale[i])  # Process the element as needed
 24        
 25        # Then, wrap around and iterate from the beginning to start_index - 1
 26        for i in range(0, ind):
 27            if scale[i] in [ul.name for ul in unique_elements]:
 28                l.append(scale[i])  # Process the element as needed
 29        return l
 30
 31    else:
 32        return []
 33
 34
 35class Tone:
 36    def __init__(self, name):
 37        if name in scale:
 38            self.name = name 
 39        else:
 40            raise ValueError("Wrong tone!")
 41            
 42    def __str__(self):
 43        return self.name  
 44
 45    def __add__(self, other):
 46        if isinstance(other, Tone):
 47            return Chord(self, other)  # Връща нов обект Chord
 48        elif isinstance(other, Interval):
 49            start_index = scale.index(self.name)
 50            new_index = (start_index + other.semitones) % 12
 51            return Tone(scale[new_index])
 52        raise TypeError("Invalid operation")
 53    
 54    def __sub__(self, other):
 55        if isinstance(other, Tone):
 56            index_self = scale.index(self.name)
 57            index_other = scale.index(other.name)
 58            interval_semitones = abs(index_other - index_self) % 12
 59            return Interval(interval_semitones)  # Връща нов обект Interval
 60        elif isinstance(other, Interval):
 61           start_index = scale.index(self.name)
 62           new_index = (start_index - other.semitones) % 12
 63           return Tone(scale[new_index])
 64        raise TypeError("Operand must be an instance of Tone")
 65        
 66    def transposed(self, interval):
 67        start_index = scale.index(self.name)
 68        new_index = (start_index + interval.semitones) % 12
 69        return Tone(scale[new_index])
 70    
 71    
 72class Interval:
 73    def __init__(self, semitones):
 74        self.semitones = semitones % 12
 75
 76    def __str__(self):
 77        return intervals[self.semitones]
 78
 79    def __add__(self, other):
 80        if isinstance(other, Interval):
 81            combined_semitones = (self.semitones + other.semitones) % 12
 82            return Interval(combined_semitones)
 83        raise TypeError("Can only add Interval to Interval")
 84        
 85    def __neg__(self):
 86        return Interval(-self.semitones)
 87
 88
 89class Chord:
 90    def __init__(self, root, *tones):
 91        other_tones = [tone.name for tone in tones]
 92        unique_tones = {root, *tones}
 93        other_tones.append(root.name)
 94        if len(other_tones) < 2:
 95            raise TypeError("Cannot have a chord made of only 1 unique tone")
 96
 97        self.root = root
 98        # self.tones = sorted(unique_tones, key=lambda tone: scale.index(tone.name))
 99        self.tones = sort_tones(root, unique_tones)
100    
101    def __add__(self, other):
102        if isinstance(other, Tone):
103            if other.name in self.tones:
104                return self  
105            
106            return Chord( *(Tone(tone.name) for tone in self.tones), other)
107        # else:
108        #     raise TypeError("Can only add a Tone to a Chord")
109        if isinstance(other, Chord):
110            combined_tones = set([tone.name for tone in self.tones]) | set([tone.name for tone in other.tones])
111            return Chord(*(Tone(tone) for tone in combined_tones))
112        # else:
113        #     raise TypeError("Can only add a Chord to another Chord")
114        
115    
116    def __sub__(self, other):
117        if isinstance(other, Tone):
118            if other.name not in [tone.name for tone in self.tones]:
119                raise TypeError(f"Cannot remove tone {other} from chord {self}")
120            remaining_tones = [tone.name for tone in self.tones if tone.name != other.name]
121            if len(remaining_tones) < 2:
122                raise TypeError("Cannot have a chord made of only 1 unique tone")
123            return Chord( *(Tone(tone) for tone in remaining_tones))
124        raise TypeError("Can only subtract a Tone from a Chord")
125    
126    def is_minor(self):
127        for tone in self.tones:
128            if tone != self.root:
129                interval = (scale.index(tone.name) - scale.index(self.root.name)) % 12
130                if interval == 3:  # Minor 3rd
131                    return True
132        return False
133
134    def is_major(self):
135        for tone in self.tones:
136            if tone != self.root:
137                interval = (scale.index(tone.name) - scale.index(self.root.name)) % 12
138                if interval == 4:  # Major 3rd
139                    return True
140        return False
141
142    def is_power_chord(self):
143        return not self.is_minor() and not self.is_major()
144
145    def __str__(self):
146        return "-".join(str(tone) for tone in self.tones)
147    
148    def transposed(self, interval):
149        if not isinstance(interval, Interval):
150            raise TypeError("Interval expected")
151
152        transposed_tones = [Tone(tone.name).transposed(interval) for tone in self.tones]
153
154        return Chord(transposed_tones[0], *transposed_tones[1:])

F...EEEEEEE....EE.F..E.E...F..EE.F.F.
======================================================================
ERROR: test_is_major (test.TestBasicChordFunctionality.test_is_major)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 103, in test_is_major
self.assertFalse(a_minor_chord.is_major())
^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 137, in is_major
interval = (scale.index(tone.name) - scale.index(self.root.name)) % 12
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
ERROR: 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())
^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 129, in is_minor
interval = (scale.index(tone.name) - scale.index(self.root.name)) % 12
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
ERROR: 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())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 143, in is_power_chord
return not self.is_minor() and not self.is_major()
^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 129, in is_minor
interval = (scale.index(tone.name) - scale.index(self.root.name)) % 12
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
ERROR: test_transposed (test.TestBasicChordFunctionality.test_transposed)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 129, in test_transposed
result_chord = d_major_chord.transposed(Interval(2))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 152, in transposed
transposed_tones = [Tone(tone.name).transposed(interval) for tone in self.tones]
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
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))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 152, in transposed
transposed_tones = [Tone(tone.name).transposed(interval) for tone in self.tones]
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
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))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 152, in transposed
transposed_tones = [Tone(tone.name).transposed(interval) for tone in self.tones]
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
ERROR: test_transposed_overflow (test.TestBasicChordFunctionality.test_transposed_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 143, in test_transposed_overflow
result_chord = d_major_chord.transposed(Interval(8))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 152, in transposed
transposed_tones = [Tone(tone.name).transposed(interval) for tone in self.tones]
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
ERROR: test_add_chords (test.TestOperations.test_add_chords)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 298, in test_add_chords
result_chord = c5_chord + this_other_chord
~~~~~~~~~^~~~~~~~~~~~~~~~~~
File "/tmp/solution.py", line 110, in __add__
combined_tones = set([tone.name for tone in self.tones]) | set([tone.name for tone in other.tones])
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
ERROR: test_add_chords_repeating_notes (test.TestOperations.test_add_chords_repeating_notes)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 304, in test_add_chords_repeating_notes
result_chord = c5_chord + inverted_c5_chord
~~~~~~~~~^~~~~~~~~~~~~~~~~~~
File "/tmp/solution.py", line 110, in __add__
combined_tones = set([tone.name for tone in self.tones]) | set([tone.name for tone in other.tones])
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
ERROR: test_add_tone_to_chord (test.TestOperations.test_add_tone_to_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 252, in test_add_tone_to_chord
result_chord = f_major_chord + Tone("D")
~~~~~~~~~~~~~~^~~~~~~~~~~
File "/tmp/solution.py", line 106, in __add__
return Chord( *(Tone(tone.name) for tone in self.tones), other)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 106, in <genexpr>
return Chord( *(Tone(tone.name) for tone in self.tones), other)
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
ERROR: test_add_tone_to_chord_order (test.TestOperations.test_add_tone_to_chord_order)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 259, in test_add_tone_to_chord_order
result_chord = f_major_chord + Tone("G")
~~~~~~~~~~~~~~^~~~~~~~~~~
File "/tmp/solution.py", line 106, in __add__
return Chord( *(Tone(tone.name) for tone in self.tones), other)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/tmp/solution.py", line 106, in <genexpr>
return Chord( *(Tone(tone.name) for tone in self.tones), other)
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
ERROR: test_subtract_tone_from_chord (test.TestOperations.test_subtract_tone_from_chord)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 275, in test_subtract_tone_from_chord
result_chord = f_minor_chord - Tone("C")
~~~~~~~~~~~~~~^~~~~~~~~~~
File "/tmp/solution.py", line 118, in __sub__
if other.name not in [tone.name for tone in self.tones]:
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
ERROR: test_subtract_tone_from_chord_error (test.TestOperations.test_subtract_tone_from_chord_error)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 292, in test_subtract_tone_from_chord_error
c5_chord - a
~~~~~~~~~^~~
File "/tmp/solution.py", line 118, in __sub__
if other.name not in [tone.name for tone in self.tones]:
^^^^^^^^^
AttributeError: 'str' object has no attribute 'name'

======================================================================
FAIL: test_chord_not_enough_tones (test.TestBasicChordFunctionality.test_chord_not_enough_tones)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 83, in test_chord_not_enough_tones
with self.assertRaises(TypeError) as err:
AssertionError: TypeError not raised

======================================================================
FAIL: test_add_interval_to_tone_left_side_error (test.TestOperations.test_add_interval_to_tone_left_side_error)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 211, in test_add_interval_to_tone_left_side_error
self.assertEqual(str(err.exception), INVALID_OPERATION)
AssertionError: 'Can only add Interval to Interval' != 'Invalid operation'
- Can only add Interval to Interval
+ Invalid operation

======================================================================
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_addition_same_tone (test.TestOperations.test_tone_addition_same_tone)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 166, in test_tone_addition_same_tone
with self.assertRaises(TypeError) as err:
AssertionError: TypeError not raised

======================================================================
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.006s

FAILED (failures=5, errors=13)

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