Домашни > Pitches love the D > Решения > Решението на Марина Господинова

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

9 точки общо

32 успешни теста
5 неуспешни теста
Код

  1class Tone:
  2    """Describe the concept of musical tone."""
  3
  4    ORDER = ('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B')
  5    ALL_TONES = len(ORDER)
  6
  7    def __init__(self, name):
  8        self.name = name
  9
 10    def __str__(self):
 11        return self.name
 12
 13    def index(self):
 14        """Return the index of the name in tone order"""
 15        return Tone.ORDER.index(self.name)
 16    
 17    def __add__(self, other):
 18        if isinstance(other, Tone):
 19            return Chord(self, other)
 20        elif isinstance(other, Interval):
 21            semitones = Tone.ORDER.index(self.name) + other.number_of_semitones
 22            while semitones >= self.ALL_TONES:
 23                semitones -= self.ALL_TONES
 24            return Tone(self.ORDER[semitones])
 25        
 26    def __sub__(self, other):
 27        if isinstance(other, Tone):
 28            return Interval.from_tones(self, other)
 29        elif isinstance(other, Interval):
 30            semitones = Tone.ORDER.index(self.name) - other.number_of_semitones
 31            while semitones < 0:
 32                semitones += self.ALL_TONES
 33            return Tone(self.ORDER[semitones])
 34
 35
 36class Interval:
 37    """Describe the concept of an interval"""
 38
 39    @staticmethod
 40    def interval_name(number_of_semitones):
 41        """Return the name relative to the number of semitones in the interval"""
 42        names_of_intervals = ('unison', 'minor 2nd', 'major 2nd', 'minor 3rd', 'major 3rd', 'perfect 4th', 
 43                              'diminished 5th', 'perfect 5th', 'minor 6th', 'major 6th', 'minor 7th', 'major 7th')
 44        return names_of_intervals[number_of_semitones]
 45        
 46    def __init__(self, number_of_semitones):
 47        while number_of_semitones >= Tone.ALL_TONES:
 48            number_of_semitones -= Tone.ALL_TONES
 49        while number_of_semitones < 0:
 50            number_of_semitones += Tone.ALL_TONES
 51        self.name = Interval.interval_name(number_of_semitones)
 52        self.number_of_semitones = number_of_semitones
 53        self.operator = True #True for +, False for -, used for add and substract
 54
 55    def __str__(self):
 56        return self.name
 57    
 58    def __neg__(self):
 59        self.operator = False
 60        return self
 61    
 62    @classmethod
 63    def from_tones(cls, first, second):
 64        """Return a new interval by two given tones"""
 65        if first.index() >= second.index():
 66            return Interval(first.index() - second.index())
 67        else:
 68            return Interval(second.index() - first.index())
 69        
 70    def __add__(self, other):
 71        if isinstance(other, Tone):
 72            raise TypeError("Invalid operation")
 73        elif isinstance(other, Interval):
 74            semitones = self.number_of_semitones + other.number_of_semitones
 75            return Interval(semitones)
 76
 77    def __sub__(self, other):
 78        if isinstance(other, Tone):
 79            raise TypeError("Invalid operation")
 80            
 81
 82class Chord:
 83    """Describe the concept of a chord"""
 84
 85    @staticmethod
 86    def validate_chord(tones):
 87        """Check if a chord is valid - long enough to be a chord"""
 88        if len(set(tones)) < 2:
 89            raise TypeError("Cannot have a chord made of only 1 unique tone")
 90
 91    @staticmethod
 92    def ordered_name(root, tones):
 93        """Return the sorted name of the chord by the tones associated with - in between"""
 94        start_index = Tone.ORDER.index(root)
 95        custom_order = Tone.ORDER[start_index:] + Tone.ORDER[:start_index]
 96        unique_tones = list(set(tones))
 97        if root in unique_tones:
 98            unique_tones.remove(root)
 99        ordered_tones = sorted(unique_tones, key=lambda tone: custom_order.index(tone))
100        chord_name = root + '-' + '-'.join(tone for tone in ordered_tones)
101        return chord_name
102    
103    def __init__(self, root, *args):
104        self.root = root
105        self.other_tones = list(args)
106        self.other_tones_names = [str(tone) for tone in args]
107        Chord.validate_chord([str(self.root)] + self.other_tones_names)
108        self.chord_name = Chord.ordered_name(str(self.root), self.other_tones_names)
109
110    def __str__(self):
111        return self.chord_name
112    
113    def is_minor(self):
114        """Check if the chord is minor"""
115        for second_tone in self.other_tones:
116            if str(Interval.from_tones(self.root, second_tone)) == 'minor 3rd':
117                return True
118        return False
119    
120    def is_major(self):
121        """Check if the chord is major"""
122        for second_tone in self.other_tones:
123            if str(Interval.from_tones(self.root, second_tone)) == 'major 3rd':
124                return True
125        return False
126    
127    def is_power_chord(self):
128        """Check if the chord is power chord"""
129        return not self.is_minor() and not self.is_major()
130    
131    def __add__(self, other):
132        if isinstance(other, Tone):
133            tones = self.other_tones
134            tones.append(other)
135            return Chord(self.root, *tones)
136        elif isinstance(other, Chord):
137            new_root = self.root
138            new_tones = self.other_tones + [other.root] + other.other_tones
139            return Chord(new_root, *new_tones)
140
141    def __sub__(self, other):
142        if other.name != self.root.name and other.name not in self.other_tones_names:
143            raise TypeError(f"Cannot remove tone {str(other)} from chord {str(self)}")
144        elif len(self.other_tones) < 2:
145            raise TypeError("Cannot have a chord made of only 1 unique tone")
146        elif other.name is self.root.name:
147            new_root = self.other_tones_names[1]
148            new_tones = [tone for tone in self.other_tones if tone.name != new_root.name]
149            return Chord(new_root, *new_tones)
150        else:
151            new_tones = [tone for tone in self.other_tones if tone.name != other.name]
152            return Chord(self.root, *new_tones)
153        
154    def transposed(self, interval):
155        """Transpose a chord - shift each of its tones by the same interval"""
156        new_root = self.root
157        new_tones = []
158        if interval.operator:
159            new_root += interval
160            for tone in self.other_tones:
161                new_tones.append(tone+interval)
162        else:
163            new_root -= interval
164            for tone in self.other_tones:
165                new_tones.append(tone-interval)
166        return Chord(new_root, *new_tones)

....FFF....F.......................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_interval_negative (test.TestBasicIntervalFunctionality.test_interval_negative)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 51, in test_interval_negative
self.assertEqual(str(minor_2nd), "minor 2nd")
AssertionError: 'major 7th' != 'minor 2nd'
- major 7th
+ minor 2nd

======================================================================
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=5)

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

f1class Tone:f1class Tone:
2    """Describe the concept of musical tone."""2    """Describe the concept of musical tone."""
n3    ALL_TONES = 12n3 
4    ORDER = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']4    ORDER = ('C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B')
5    ALL_TONES = len(ORDER)
6 
5    def __init__(self, name):7    def __init__(self, name):
6        self.name = name8        self.name = name
79
8    def __str__(self):10    def __str__(self):
9        return self.name11        return self.name
1012
11    def index(self):13    def index(self):
12        """Return the index of the name in tone order"""14        """Return the index of the name in tone order"""
13        return Tone.ORDER.index(self.name)15        return Tone.ORDER.index(self.name)
14    16    
15    def __add__(self, other):17    def __add__(self, other):
16        if isinstance(other, Tone):18        if isinstance(other, Tone):
17            return Chord(self, other)19            return Chord(self, other)
18        elif isinstance(other, Interval):20        elif isinstance(other, Interval):
19            semitones = Tone.ORDER.index(self.name) + other.number_of_semitones21            semitones = Tone.ORDER.index(self.name) + other.number_of_semitones
20            while semitones >= self.ALL_TONES:22            while semitones >= self.ALL_TONES:
21                semitones -= self.ALL_TONES23                semitones -= self.ALL_TONES
22            return Tone(self.ORDER[semitones])24            return Tone(self.ORDER[semitones])
23        25        
24    def __sub__(self, other):26    def __sub__(self, other):
25        if isinstance(other, Tone):27        if isinstance(other, Tone):
n26            return Interval.fromTones(self, other)n28            return Interval.from_tones(self, other)
27        elif isinstance(other, Interval):29        elif isinstance(other, Interval):
28            semitones = Tone.ORDER.index(self.name) - other.number_of_semitones30            semitones = Tone.ORDER.index(self.name) - other.number_of_semitones
29            while semitones < 0:31            while semitones < 0:
30                semitones += self.ALL_TONES32                semitones += self.ALL_TONES
31            return Tone(self.ORDER[semitones])33            return Tone(self.ORDER[semitones])
3234
3335
34class Interval:36class Interval:
35    """Describe the concept of an interval"""37    """Describe the concept of an interval"""
nn38 
36    @staticmethod39    @staticmethod
37    def interval_name(number_of_semitones):40    def interval_name(number_of_semitones):
38        """Return the name relative to the number of semitones in the interval"""41        """Return the name relative to the number of semitones in the interval"""
n39        if number_of_semitones == 0:n42        names_of_intervals = ('unison', 'minor 2nd', 'major 2nd', 'minor 3rd', 'major 3rd', 'perfect 4th', 
40            return 'unison'43                              'diminished 5th', 'perfect 5th', 'minor 6th', 'major 6th', 'minor 7th', 'major 7th')
41        elif number_of_semitones == 1:44        return names_of_intervals[number_of_semitones]
42            return 'minor 2nd'45        
43        elif number_of_semitones == 2:
44            return 'major 2nd'
45        elif number_of_semitones == 3:
46            return 'minor 3rd'
47        elif number_of_semitones == 4:
48            return 'major 3rd'
49        elif number_of_semitones == 5:
50            return 'perfect 4th'
51        elif number_of_semitones == 6:
52            return 'diminished 5th'
53        elif number_of_semitones == 7:
54            return 'perfect 5th'
55        elif number_of_semitones == 8:
56            return 'minor 6th'
57        elif number_of_semitones == 9:
58            return 'major 6th'
59        elif number_of_semitones == 10:
60            return 'minor 7th'
61        elif number_of_semitones == 11:
62            return 'major 7th'
63   
64    def __init__(self, number_of_semitones):46    def __init__(self, number_of_semitones):
65        while number_of_semitones >= Tone.ALL_TONES:47        while number_of_semitones >= Tone.ALL_TONES:
66            number_of_semitones -= Tone.ALL_TONES48            number_of_semitones -= Tone.ALL_TONES
67        while number_of_semitones < 0:49        while number_of_semitones < 0:
68            number_of_semitones += Tone.ALL_TONES50            number_of_semitones += Tone.ALL_TONES
69        self.name = Interval.interval_name(number_of_semitones)51        self.name = Interval.interval_name(number_of_semitones)
70        self.number_of_semitones = number_of_semitones52        self.number_of_semitones = number_of_semitones
71        self.operator = True #True for +, False for -, used for add and substract53        self.operator = True #True for +, False for -, used for add and substract
7254
73    def __str__(self):55    def __str__(self):
74        return self.name56        return self.name
75    57    
76    def __neg__(self):58    def __neg__(self):
77        self.operator = False59        self.operator = False
78        return self60        return self
79    61    
80    @classmethod62    @classmethod
n81    def fromTones(cls, first, second):n63    def from_tones(cls, first, second):
82        """Return a new interval by two given tones"""64        """Return a new interval by two given tones"""
83        if first.index() >= second.index():65        if first.index() >= second.index():
84            return Interval(first.index() - second.index())66            return Interval(first.index() - second.index())
85        else:67        else:
86            return Interval(second.index() - first.index())68            return Interval(second.index() - first.index())
87        69        
88    def __add__(self, other):70    def __add__(self, other):
89        if isinstance(other, Tone):71        if isinstance(other, Tone):
90            raise TypeError("Invalid operation")72            raise TypeError("Invalid operation")
91        elif isinstance(other, Interval):73        elif isinstance(other, Interval):
92            semitones = self.number_of_semitones + other.number_of_semitones74            semitones = self.number_of_semitones + other.number_of_semitones
93            return Interval(semitones)75            return Interval(semitones)
9476
95    def __sub__(self, other):77    def __sub__(self, other):
96        if isinstance(other, Tone):78        if isinstance(other, Tone):
97            raise TypeError("Invalid operation")79            raise TypeError("Invalid operation")
98            80            
9981
100class Chord:82class Chord:
101    """Describe the concept of a chord"""83    """Describe the concept of a chord"""
nn84 
102    @staticmethod85    @staticmethod
n103    def check_valid_chord(tones):n86    def validate_chord(tones):
104        """Check if a chord is valid - long enough to be a chord"""87        """Check if a chord is valid - long enough to be a chord"""
105        if len(set(tones)) < 2:88        if len(set(tones)) < 2:
106            raise TypeError("Cannot have a chord made of only 1 unique tone")89            raise TypeError("Cannot have a chord made of only 1 unique tone")
10790
108    @staticmethod91    @staticmethod
109    def ordered_name(root, tones):92    def ordered_name(root, tones):
110        """Return the sorted name of the chord by the tones associated with - in between"""93        """Return the sorted name of the chord by the tones associated with - in between"""
111        start_index = Tone.ORDER.index(root)94        start_index = Tone.ORDER.index(root)
112        custom_order = Tone.ORDER[start_index:] + Tone.ORDER[:start_index]95        custom_order = Tone.ORDER[start_index:] + Tone.ORDER[:start_index]
113        unique_tones = list(set(tones))96        unique_tones = list(set(tones))
114        if root in unique_tones:97        if root in unique_tones:
115            unique_tones.remove(root)98            unique_tones.remove(root)
116        ordered_tones = sorted(unique_tones, key=lambda tone: custom_order.index(tone))99        ordered_tones = sorted(unique_tones, key=lambda tone: custom_order.index(tone))
117        chord_name = root + '-' + '-'.join(tone for tone in ordered_tones)100        chord_name = root + '-' + '-'.join(tone for tone in ordered_tones)
118        return chord_name101        return chord_name
119    102    
120    def __init__(self, root, *args):103    def __init__(self, root, *args):
121        self.root = root104        self.root = root
122        self.other_tones = list(args)105        self.other_tones = list(args)
123        self.other_tones_names = [str(tone) for tone in args]106        self.other_tones_names = [str(tone) for tone in args]
n124        Chord.check_valid_chord([str(self.root)] + self.other_tones_names)n107        Chord.validate_chord([str(self.root)] + self.other_tones_names)
125        self.chord_name = Chord.ordered_name(str(self.root), self.other_tones_names)108        self.chord_name = Chord.ordered_name(str(self.root), self.other_tones_names)
126109
127    def __str__(self):110    def __str__(self):
128        return self.chord_name111        return self.chord_name
129    112    
130    def is_minor(self):113    def is_minor(self):
131        """Check if the chord is minor"""114        """Check if the chord is minor"""
132        for second_tone in self.other_tones:115        for second_tone in self.other_tones:
n133            if str(Interval.fromTones(self.root, second_tone)) == 'minor 3rd':n116            if str(Interval.from_tones(self.root, second_tone)) == 'minor 3rd':
134                return True117                return True
135        return False118        return False
136    119    
137    def is_major(self):120    def is_major(self):
138        """Check if the chord is major"""121        """Check if the chord is major"""
139        for second_tone in self.other_tones:122        for second_tone in self.other_tones:
n140            if str(Interval.fromTones(self.root, second_tone)) == 'major 3rd':n123            if str(Interval.from_tones(self.root, second_tone)) == 'major 3rd':
141                return True124                return True
142        return False125        return False
143    126    
144    def is_power_chord(self):127    def is_power_chord(self):
145        """Check if the chord is power chord"""128        """Check if the chord is power chord"""
n146        if not self.is_minor() and not self.is_major():n129        return not self.is_minor() and not self.is_major()
147            return True
148        return False
149    130    
150    def __add__(self, other):131    def __add__(self, other):
151        if isinstance(other, Tone):132        if isinstance(other, Tone):
152            tones = self.other_tones133            tones = self.other_tones
153            tones.append(other)134            tones.append(other)
154            return Chord(self.root, *tones)135            return Chord(self.root, *tones)
155        elif isinstance(other, Chord):136        elif isinstance(other, Chord):
156            new_root = self.root137            new_root = self.root
157            new_tones = self.other_tones + [other.root] + other.other_tones138            new_tones = self.other_tones + [other.root] + other.other_tones
158            return Chord(new_root, *new_tones)139            return Chord(new_root, *new_tones)
159140
160    def __sub__(self, other):141    def __sub__(self, other):
161        if other.name != self.root.name and other.name not in self.other_tones_names:142        if other.name != self.root.name and other.name not in self.other_tones_names:
162            raise TypeError(f"Cannot remove tone {str(other)} from chord {str(self)}")143            raise TypeError(f"Cannot remove tone {str(other)} from chord {str(self)}")
163        elif len(self.other_tones) < 2:144        elif len(self.other_tones) < 2:
164            raise TypeError("Cannot have a chord made of only 1 unique tone")145            raise TypeError("Cannot have a chord made of only 1 unique tone")
165        elif other.name is self.root.name:146        elif other.name is self.root.name:
166            new_root = self.other_tones_names[1]147            new_root = self.other_tones_names[1]
167            new_tones = [tone for tone in self.other_tones if tone.name != new_root.name]148            new_tones = [tone for tone in self.other_tones if tone.name != new_root.name]
168            return Chord(new_root, *new_tones)149            return Chord(new_root, *new_tones)
169        else:150        else:
170            new_tones = [tone for tone in self.other_tones if tone.name != other.name]151            new_tones = [tone for tone in self.other_tones if tone.name != other.name]
171            return Chord(self.root, *new_tones)152            return Chord(self.root, *new_tones)
172        153        
173    def transposed(self, interval):154    def transposed(self, interval):
174        """Transpose a chord - shift each of its tones by the same interval"""155        """Transpose a chord - shift each of its tones by the same interval"""
175        new_root = self.root156        new_root = self.root
t176        new_tones = list()t157        new_tones = []
177        if interval.operator:158        if interval.operator:
178            new_root += interval159            new_root += interval
179            for tone in self.other_tones:160            for tone in self.other_tones:
180                new_tones.append(tone+interval)161                new_tones.append(tone+interval)
181        else:162        else:
182            new_root -= interval163            new_root -= interval
183            for tone in self.other_tones:164            for tone in self.other_tones:
184                new_tones.append(tone-interval)165                new_tones.append(tone-interval)
185        return Chord(new_root, *new_tones)166        return Chord(new_root, *new_tones)
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op