Домашни > Pitches love the D > Решения > Решението на Юлиана Иванова

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

7 точки общо

26 успешни теста
11 неуспешни теста
Код

  1NOTE_ORDER = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
  2
  3class Tone:
  4    def __init__(self, name):
  5        if name in NOTE_ORDER:
  6            self.name = name
  7        else:
  8            raise TypeError('Invalid note')
  9    
 10    def __str__(self):
 11        return self.name
 12
 13    # We use these two methods cause apparently the set doesn't work without them
 14    def __eq__(self, other):
 15        return self.name == other.name
 16    
 17    def __hash__(self):
 18        return hash(self.name)
 19
 20    def __add__(self, other):
 21        if isinstance(other, Tone):
 22            return Chord(self, other)
 23        if isinstance(other, Interval):
 24            tone_index = (NOTE_ORDER.index(self.name) + other.number_of_semitones) % 12
 25            return Tone(NOTE_ORDER[tone_index])
 26        return 'Invalid operation'
 27
 28    def __radd__(self, other):
 29        raise TypeError('Invalid operation')
 30
 31    def __sub__(self, other):
 32        if isinstance(other, Tone):
 33            interval = Interval(abs(NOTE_ORDER.index(self.name) - NOTE_ORDER.index(other.name)))
 34            return interval
 35        if isinstance(other, Interval):
 36            tone_index = abs((NOTE_ORDER.index(self.name) - other.number_of_semitones)) % 12
 37            return Tone(NOTE_ORDER[tone_index])
 38        return 'Invalid operation'
 39    
 40    def __rsub__(self, other):
 41        raise TypeError('Invalid operation')
 42
 43
 44class Interval:
 45    result = ('unison', 'minor 2nd', 'major 2nd', 'minor 3rd',
 46              'major 3rd', 'perfect 4th', 'diminished 5th',
 47              'perfect 5th', 'minor 6th', 'major 6th',
 48              'minor 7th', 'major 7th')
 49
 50    def __init__(self, number_of_semitones):
 51        # If semitone is above 11 and in order to keep the cycle 
 52        self.number_of_semitones = number_of_semitones % 12
 53    
 54    def __str__(self):
 55        return self.result[self.number_of_semitones]
 56
 57    def __add__(self, other):
 58        return Interval(self.number_of_semitones + other.number_of_semitones)
 59    
 60    def __neg__(self):
 61        return Interval(-self.number_of_semitones)
 62
 63
 64class Chord:
 65    def __init__(self, pos_tone, *args):
 66        tone_set = set((pos_tone, *args))  
 67        self.pos_tone = pos_tone      
 68        if len(tone_set) == 1:
 69            raise TypeError('Cannot have a chord made of only 1 unique tone') 
 70        sorted_tones = [pos_tone] + sorted(tone_set - {pos_tone}, key=lambda tone: NOTE_ORDER.index(tone.name))
 71        self.tones = sorted_tones
 72
 73    def __str__(self):
 74        return '-'.join(map(str, self.tones))
 75
 76    def __add__(self, other):
 77        if isinstance(other, Tone):
 78            if other not in self.tones:
 79                new_tones = self.tones[:]
 80                new_tones.append(other)
 81                return Chord(*new_tones)
 82        if isinstance(other, Chord):
 83            new_tones = self.tones[:]
 84            for tone in other.tones:
 85               new_tones.append(tone)
 86            return Chord(*new_tones)
 87        return 'Invalid operation'
 88
 89    def __sub__(self, other):
 90        if other not in self.tones:
 91            raise TypeError(f'Cannot remove tone {other} from chord {self}')
 92        if len(self.tones) < 3:
 93            raise TypeError('Cannot have a chord made of only 1 unique tone')
 94        if other == self.tones[0]:
 95            new_tones = self.tones[1:]
 96            return Chord(*new_tones)
 97
 98        new_tones = self.tones[:]
 99        new_tones.remove(other)
100        return Chord(*new_tones)
101
102    def get_interval(self, pos_tone, other_tone):
103        tone_index = NOTE_ORDER.index(other_tone.name)
104        pos_tone_index = NOTE_ORDER.index(self.pos_tone.name)
105
106        return abs(tone_index - pos_tone_index)
107
108    def is_minor(self):
109        for tone in self.tones:
110            if tone != self.pos_tone:
111                if self.get_interval(self.pos_tone, tone) == 3:
112                    return True      
113
114        return False
115    
116    def is_major(self):
117        for tone in self.tones:
118            if tone != self.pos_tone:
119                if self.get_interval(self.pos_tone, tone) == 4:
120                    return True
121        
122        return False
123    
124    def is_power_chord(self):
125        return not self.is_major() and not self.is_minor()
126
127    def transposed(self, interval):
128        return Chord(*[tone + interval for tone in self.tones])

.F..FFF..F........E..FEF....F......F.
======================================================================
ERROR: 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 210, in test_add_interval_to_tone_left_side_error
Interval(2) + g
~~~~~~~~~~~~^~~
File "/tmp/solution.py", line 58, in __add__
return Interval(self.number_of_semitones + other.number_of_semitones)
^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Tone' object has no attribute 'number_of_semitones'

======================================================================
ERROR: 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 267, in test_add_tone_to_chord_existing_tone
result_chord = result_chord + Tone("G#")
~~~~~~~~~~~~~^~~~~~~~~~~~
File "/tmp/solution.py", line 29, in __radd__
raise TypeError('Invalid operation')
TypeError: Invalid operation

======================================================================
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: 'F-C-E-A' != 'F-A-C-E'
- F-C-E-A
? --
+ F-A-C-E
? ++

======================================================================
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_transposed_negative_overflow (test.TestBasicChordFunctionality.test_transposed_negative_overflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 152, in test_transposed_negative_overflow
self.assertEqual(str(result_chord), "G#-B-D#")
AssertionError: 'G#-D#-B' != 'G#-B-D#'
- G#-D#-B
? --
+ G#-B-D#
? ++

======================================================================
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: 'F-C-D-A' != 'F-A-C-D'
- F-C-D-A
? --
+ F-A-C-D
? ++

======================================================================
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: 'F-C-G-A' != 'F-G-A-C'
- F-C-G-A
? --
+ F-G-A-C
? ++

======================================================================
FAIL: test_subtract_interval_from_tone_oveflow (test.TestOperations.test_subtract_interval_from_tone_oveflow)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/tmp/test.py", line 229, in test_subtract_interval_from_tone_oveflow
self.assertEqual(str(g), "G")
AssertionError: 'F' != 'G'
- F
+ G

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

FAILED (failures=9, errors=2)

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

n1note_order = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']n1NOTE_ORDER = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
22
3class Tone:3class Tone:
4    def __init__(self, name):4    def __init__(self, name):
n5        if name in note_order:n5        if name in NOTE_ORDER:
6            self.name = name;6            self.name = name
7        else:
8            raise TypeError('Invalid note')
7    9    
8    def __str__(self):10    def __str__(self):
n9        return self.name;   n11        return self.name
1012
11    # We use these two methods cause apparently the set doesn't work without them13    # We use these two methods cause apparently the set doesn't work without them
12    def __eq__(self, other):14    def __eq__(self, other):
13        return self.name == other.name15        return self.name == other.name
14    16    
15    def __hash__(self):17    def __hash__(self):
16        return hash(self.name)18        return hash(self.name)
1719
18    def __add__(self, other):20    def __add__(self, other):
19        if isinstance(other, Tone):21        if isinstance(other, Tone):
20            return Chord(self, other)22            return Chord(self, other)
21        if isinstance(other, Interval):23        if isinstance(other, Interval):
n22            tone_index = (note_order.index(self.name) + other.number_of_semitones) % 12n24            tone_index = (NOTE_ORDER.index(self.name) + other.number_of_semitones) % 12
23            return Tone(note_order[tone_index])25            return Tone(NOTE_ORDER[tone_index])
24        return 'Invalid operation'26        return 'Invalid operation'
2527
26    def __radd__(self, other):28    def __radd__(self, other):
27        raise TypeError('Invalid operation')29        raise TypeError('Invalid operation')
2830
29    def __sub__(self, other):31    def __sub__(self, other):
30        if isinstance(other, Tone):32        if isinstance(other, Tone):
n31            interval = Interval(abs(note_order.index(self.name) - note_order.index(other.name)))n33            interval = Interval(abs(NOTE_ORDER.index(self.name) - NOTE_ORDER.index(other.name)))
32            return interval34            return interval
33        if isinstance(other, Interval):35        if isinstance(other, Interval):
n34            tone_index = abs((note_order.index(self.name) - other.number_of_semitones)) % 12n36            tone_index = abs((NOTE_ORDER.index(self.name) - other.number_of_semitones)) % 12
35            return Tone(note_order[tone_index])37            return Tone(NOTE_ORDER[tone_index])
36        return 'Invalid operation'38        return 'Invalid operation'
37    39    
38    def __rsub__(self, other):40    def __rsub__(self, other):
39        raise TypeError('Invalid operation')41        raise TypeError('Invalid operation')
4042
4143
42class Interval:44class Interval:
43    result = ('unison', 'minor 2nd', 'major 2nd', 'minor 3rd',45    result = ('unison', 'minor 2nd', 'major 2nd', 'minor 3rd',
44              'major 3rd', 'perfect 4th', 'diminished 5th',46              'major 3rd', 'perfect 4th', 'diminished 5th',
45              'perfect 5th', 'minor 6th', 'major 6th',47              'perfect 5th', 'minor 6th', 'major 6th',
46              'minor 7th', 'major 7th')48              'minor 7th', 'major 7th')
4749
48    def __init__(self, number_of_semitones):50    def __init__(self, number_of_semitones):
49        # If semitone is above 11 and in order to keep the cycle 51        # If semitone is above 11 and in order to keep the cycle 
50        self.number_of_semitones = number_of_semitones % 1252        self.number_of_semitones = number_of_semitones % 12
51    53    
52    def __str__(self):54    def __str__(self):
53        return self.result[self.number_of_semitones]55        return self.result[self.number_of_semitones]
5456
55    def __add__(self, other):57    def __add__(self, other):
56        return Interval(self.number_of_semitones + other.number_of_semitones)58        return Interval(self.number_of_semitones + other.number_of_semitones)
57    59    
58    def __neg__(self):60    def __neg__(self):
59        return Interval(-self.number_of_semitones)61        return Interval(-self.number_of_semitones)
6062
6163
62class Chord:64class Chord:
63    def __init__(self, pos_tone, *args):65    def __init__(self, pos_tone, *args):
64        tone_set = set((pos_tone, *args))  66        tone_set = set((pos_tone, *args))  
65        self.pos_tone = pos_tone      67        self.pos_tone = pos_tone      
n66        if(len(tone_set) == 1):n68        if len(tone_set) == 1:
67            raise TypeError('Cannot have a chord made of only 1 unique tone') 69            raise TypeError('Cannot have a chord made of only 1 unique tone') 
n68        sorted_tones = [pos_tone] + sorted(tone_set - {pos_tone}, key=lambda tone: note_order.index(tone.name))n70        sorted_tones = [pos_tone] + sorted(tone_set - {pos_tone}, key=lambda tone: NOTE_ORDER.index(tone.name))
69        self.tones = sorted_tones71        self.tones = sorted_tones
7072
71    def __str__(self):73    def __str__(self):
72        return '-'.join(map(str, self.tones))74        return '-'.join(map(str, self.tones))
7375
74    def __add__(self, other):76    def __add__(self, other):
75        if isinstance(other, Tone):77        if isinstance(other, Tone):
76            if other not in self.tones:78            if other not in self.tones:
n77                new_tones = list(self.tones)n79                new_tones = self.tones[:]
78                new_tones.append(other)80                new_tones.append(other)
n79                return Chord(new_tones[0], *new_tones[1:])n81                return Chord(*new_tones)
80        if isinstance(other, Chord):82        if isinstance(other, Chord):
n81            new_tones = list(self.tones)n83            new_tones = self.tones[:]
82            for tone in other.tones:84            for tone in other.tones:
n83                if tone not in self.tones:n
84                    new_tones.append(tone)85               new_tones.append(tone)
85            return Chord(new_tones[0], *new_tones[1:])86            return Chord(*new_tones)
86        return 'Invalid operation'87        return 'Invalid operation'
8788
88    def __sub__(self, other):89    def __sub__(self, other):
89        if other not in self.tones:90        if other not in self.tones:
90            raise TypeError(f'Cannot remove tone {other} from chord {self}')91            raise TypeError(f'Cannot remove tone {other} from chord {self}')
91        if len(self.tones) < 3:92        if len(self.tones) < 3:
92            raise TypeError('Cannot have a chord made of only 1 unique tone')93            raise TypeError('Cannot have a chord made of only 1 unique tone')
93        if other == self.tones[0]:94        if other == self.tones[0]:
94            new_tones = self.tones[1:]95            new_tones = self.tones[1:]
n95            return Chord(new_tones[0], *new_tones[1:])n96            return Chord(*new_tones)
9697
n97        new_tones = list(self.tones)n98        new_tones = self.tones[:]
98        new_tones.remove(other)99        new_tones.remove(other)
n99        return Chord(new_tones[0], *new_tones[1:])n100        return Chord(*new_tones)
100101
101    def get_interval(self, pos_tone, other_tone):102    def get_interval(self, pos_tone, other_tone):
n102        tone_index = note_order.index(other_tone.name)n103        tone_index = NOTE_ORDER.index(other_tone.name)
103        pos_tone_index = note_order.index(self.pos_tone.name)104        pos_tone_index = NOTE_ORDER.index(self.pos_tone.name)
104105
105        return abs(tone_index - pos_tone_index)106        return abs(tone_index - pos_tone_index)
106107
107    def is_minor(self):108    def is_minor(self):
108        for tone in self.tones:109        for tone in self.tones:
109            if tone != self.pos_tone:110            if tone != self.pos_tone:
110                if self.get_interval(self.pos_tone, tone) == 3:111                if self.get_interval(self.pos_tone, tone) == 3:
111                    return True      112                    return True      
112113
113        return False114        return False
114    115    
115    def is_major(self):116    def is_major(self):
116        for tone in self.tones:117        for tone in self.tones:
117            if tone != self.pos_tone:118            if tone != self.pos_tone:
118                if self.get_interval(self.pos_tone, tone) == 4:119                if self.get_interval(self.pos_tone, tone) == 4:
119                    return True120                    return True
120        121        
121        return False122        return False
122    123    
123    def is_power_chord(self):124    def is_power_chord(self):
124        return not self.is_major() and not self.is_minor()125        return not self.is_major() and not self.is_minor()
125126
126    def transposed(self, interval):127    def transposed(self, interval):
t127        new_tones = []t128        return Chord(*[tone + interval for tone in self.tones])
128        for tone in self.tones:
129            new_tones.append(tone + interval)
130        return Chord(new_tones[0], *new_tones[1:])
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op