Домашни > Pitches love the D > Решения > Решението на Стивън Александров

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

10 точки общо

36 успешни теста
1 неуспешни теста
Код (Update-нато решение, имаше неработеща функция)

  1# Updated solution: 4.11.2024, прочетох коментарите по предишното решение, някои неща са оправени, някои не
  2
  3# и с главни букви, ама вече ги бех написал така
  4interval_tuple = ("unison", "minor 2nd", "major 2nd", "minor 3rd",
  5                  "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th",
  6                  "minor 6th", "major 6th", "minor 7th", "major 7th")
  7tones_tuple = ("A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#")
  8# не е само за tuple, а за всички iterable колекции с __getitem__ или квото беше там operator[]
  9def get_position_in_tuple(element, collection):
 10    for i in range(0,len(collection)):
 11        if collection[i] == element:
 12            return i
 13    return -101 # да не ми счупи is_minor и is_major ако ми въведете невалиден тон
 14
 15
 16class Tone:
 17
 18    def __init__(self, data):
 19        # не правя проверка дали е валиден тон, но ако не е не би трябвало да счупи програмата
 20        # или поне функциите, за които го тествах
 21        self.data = data 
 22
 23    def __str__(self):
 24        return self.data
 25
 26    def __eq__(self, other): # трябва да се дефинира, иначе проверката е с is, което не е желаното поведение
 27        return self.data == other.data
 28    
 29    def __add__(self, other):
 30        if type(other) is Tone:
 31            return Chord(self, other)
 32        if type(other) is Interval:
 33            result_tone = get_position_in_tuple(self.data, tones_tuple) + other.data
 34            size_tones = len(tones_tuple)
 35            while result_tone >= size_tones:
 36                result_tone -= size_tones
 37            return Tone(tones_tuple[result_tone])
 38
 39    def __sub__(self, other):
 40        if type(other) is Tone:
 41            left_position = get_position_in_tuple(self.data, tones_tuple)
 42            right_position = get_position_in_tuple(other.data, tones_tuple)
 43            difference = left_position - right_position
 44            # G - C = 7 (perfect 5th), но C - G = 5 (perfect 4th), явно въртим окръжността наобратно?  
 45            if difference >= 0:
 46                return Interval(difference)
 47            else:
 48                return Interval(len(interval_tuple) - abs(difference))
 49        if type(other) is Interval:
 50            result_tone = get_position_in_tuple(self.data, tones_tuple) - other.data
 51            size_tones = len(tones_tuple)
 52            while result_tone < 0:
 53                result_tone += size_tones
 54            return Tone(tones_tuple[result_tone])
 55
 56class Interval:
 57
 58    def __init__(self, data):
 59        size_intervals = len(interval_tuple)
 60        while data >= size_intervals: # може би трябваше с %, чак сега виждам колко зле съм го направил 
 61            data -= size_intervals
 62        self.data = data
 63
 64    def __neg__(self):
 65        return -self.data
 66
 67    def __str__(self):
 68        return interval_tuple[self.data]
 69
 70    def __add__(self, other): # ако имаме Interval + Tone
 71        if type(other) is Tone:
 72            raise TypeError("Invalid operation")
 73        if type(other) is Interval:
 74            result_data = self.data + other.data
 75            return Interval(result_data) # __init__ ще се оправи дори с неща >= 12
 76
 77    def __sub__(self, other): # ако имаме Interval - Tone
 78        if type(other) is Tone:
 79            raise TypeError("Invalid operation")
 80    
 81
 82class Chord:
 83
 84    def __init__(self, *args):
 85        self.tones = set()
 86        self.main_tone = str(args[0])
 87        for item in args: # добавяме всички тонове, включително и main-a
 88            if type(item) is Tone:
 89                self.tones.add(str(item))
 90        if len(self.tones) == 1:
 91            raise TypeError("Cannot have a chord made of only 1 unique tone")
 92            
 93    def _fill_list_from_source(self, source, destination): # може би не е най-доброто име за функцията
 94        for item in source:
 95            if item in self.tones:
 96                destination.append(item)
 97        return destination
 98
 99    def __str__(self):
100        self.tones = list(self.tones)
101        position_of_main_tone = 0
102        # тъй като въртенето започва от main тона, правя два tuple-a, за тези след него в окръжността
103        # е за тези преди него
104        # целта е да се създаде сортиран лист, който в последствие да join-нем с "-"
105        for i in range(0, len(tones_tuple)):
106            if self.main_tone == tones_tuple[i]:
107                position_of_main_tone = i
108        after_tuple = tones_tuple[position_of_main_tone:]
109        before_tuple = tones_tuple[:position_of_main_tone]
110        to_return = list()
111        to_return = self._fill_list_from_source(after_tuple, to_return)
112        to_return = self._fill_list_from_source(before_tuple, to_return)
113        return "-".join(to_return)
114        
115    def check_for_specific_chord(self, chord_string):
116        main_position = get_position_in_tuple(str(self.main_tone), tones_tuple)
117        wanted_position = get_position_in_tuple(chord_string, interval_tuple)
118        for item in self.tones:
119            curr_position = get_position_in_tuple(str(item), tones_tuple)
120            # ако са на позиции 3 и 6 примерно, ще има minor 3rd
121            # но трябва да проверим и случая ако са на позиции 11 и 2 примерно, разликата м/у тях пак е 3
122            # тогава пак ще има minor 3rd, но за целта трябва 12 - (11-2)
123            current_diff = abs(curr_position - main_position)
124            if current_diff == wanted_position or len(tones_tuple) - current_diff == wanted_position:
125                return True
126        return False
127
128    def is_minor(self):
129        return self.check_for_specific_chord("minor 3rd")
130    
131    def is_major(self):
132        return self.check_for_specific_chord("major 3rd")
133
134    def is_power_chord(self):
135        return not self.is_minor() and not self.is_major()
136
137    def __add__(self, other):
138        if type(other) is Tone:
139            result_chord = Chord(self.main_tone)
140            result_chord.tones.update(self.tones)
141            result_chord.tones.add(other.data)
142            return result_chord
143        if type(other) is Chord:
144            result_chord = Chord(self.main_tone)
145            result_chord.tones.update(self.tones)
146            result_chord.tones.add(other.main_tone)
147            result_chord.tones.update(other.tones)
148            return result_chord
149        
150    def __sub__(self, other):
151        if (not other.data in self.tones) and other.data != self.main_tone:
152            raise TypeError(f"Cannot remove tone {other.data} from chord {self}")
153        if len(self.tones) < 3:
154            raise TypeError("Cannot have a chord made of only 1 unique tone")
155        if type(other) is Tone:
156            result_chord = Chord(self.main_tone)
157            if other.data == self.main_tone: # fix, не работеше правилно
158                main_tone_pos = get_position_in_tuple(self.main_tone, tones_tuple)
159                for item in tones_tuple[main_tone_pos+1:]: # гледаме първо тия след него до края на tuple-a
160                    if item in tuple(self.tones):
161                        result_chord.main_tone = item
162                        break
163                if result_chord.main_tone == other.data: # ако не сме променили main_tone с тези след него
164                    for item in tones_tuple[:main_tone_pos]:
165                        if item in tuple(self.tones):
166                            result_chord.main_tone = item
167                            break
168                result_chord.tones.update(self.tones)
169                result_chord.tones.remove(self.main_tone)
170            else: # и тук пак fix
171                result_chord.tones.update(self.tones)
172                result_chord.tones.remove(other.data)
173            return result_chord
174    
175    def transposed(self, interval):
176        # можеше да използвам и събирането, което дефинирах за тоновете...
177        position = 0
178        if type(interval) is int:
179            position = interval
180        else:
181            position = interval.data
182        result_chord = Chord(self.main_tone)
183        main_tone_pos = get_position_in_tuple(self.main_tone, tones_tuple) + position
184        # имаше някакви бъгове, които всеки път даваха различен main_tone, затова main тона е отделно, нищо че може да се сложи и в долния цикъл
185        if main_tone_pos < 0:
186            main_tone_pos += len(tones_tuple)
187        elif main_tone_pos >= len(tones_tuple):
188            main_tone_pos -= len(tones_tuple)
189        result_chord.main_tone = tones_tuple[main_tone_pos]
190        # а иначе цикъла, в който пак си го има main тона попринцип, ама програмата си прави каквото си иска и всеки път дава различен резултат
191        for item in self.tones:
192            curr_position = get_position_in_tuple(item, tones_tuple) + position
193            if curr_position < 0:
194                curr_position += len(tones_tuple)
195            elif curr_position >= len(tones_tuple):
196                curr_position -= len(tones_tuple)
197            result_chord.tones.add(tones_tuple[curr_position])
198        return result_chord

...........F.........................
======================================================================
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: '-11' != 'minor 2nd'
- -11
+ minor 2nd

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

FAILED (failures=1)

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

n1# коментарите ги пиша след като съм готов с целия код, има доста тъпотии из кода, нема ги оправямn1# Updated solution: 4.11.2024, прочетох коментарите по предишното решение, някои неща са оправени, някои не
22
n3# може би трябваше да са сетовеn
4# и с главни букви, ама вече ги бех написал така3# и с главни букви, ама вече ги бех написал така
5interval_tuple = ("unison", "minor 2nd", "major 2nd", "minor 3rd",4interval_tuple = ("unison", "minor 2nd", "major 2nd", "minor 3rd",
6                  "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th",5                  "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th",
7                  "minor 6th", "major 6th", "minor 7th", "major 7th")6                  "minor 6th", "major 6th", "minor 7th", "major 7th")
8tones_tuple = ("A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#")7tones_tuple = ("A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#")
9# не е само за tuple, а за всички iterable колекции с __getitem__ или квото беше там operator[]8# не е само за tuple, а за всички iterable колекции с __getitem__ или квото беше там operator[]
n10def get_position_in_tuple(element, tuple):n9def get_position_in_tuple(element, collection):
11    for i in range(0,len(tuple)):10    for i in range(0,len(collection)):
12        if tuple[i] == element:11        if collection[i] == element:
13            return i12            return i
14    return -101 # да не ми счупи is_minor и is_major ако ми въведете невалиден тон13    return -101 # да не ми счупи is_minor и is_major ако ми въведете невалиден тон
1514
1615
17class Tone:16class Tone:
1817
19    def __init__(self, data):18    def __init__(self, data):
20        # не правя проверка дали е валиден тон, но ако не е не би трябвало да счупи програмата19        # не правя проверка дали е валиден тон, но ако не е не би трябвало да счупи програмата
21        # или поне функциите, за които го тествах20        # или поне функциите, за които го тествах
22        self.data = data 21        self.data = data 
2322
24    def __str__(self):23    def __str__(self):
25        return self.data24        return self.data
2625
27    def __eq__(self, other): # трябва да се дефинира, иначе проверката е с is, което не е желаното поведение26    def __eq__(self, other): # трябва да се дефинира, иначе проверката е с is, което не е желаното поведение
28        return self.data == other.data27        return self.data == other.data
29    28    
30    def __add__(self, other):29    def __add__(self, other):
31        if type(other) is Tone:30        if type(other) is Tone:
32            return Chord(self, other)31            return Chord(self, other)
33        if type(other) is Interval:32        if type(other) is Interval:
34            result_tone = get_position_in_tuple(self.data, tones_tuple) + other.data33            result_tone = get_position_in_tuple(self.data, tones_tuple) + other.data
35            size_tones = len(tones_tuple)34            size_tones = len(tones_tuple)
36            while result_tone >= size_tones:35            while result_tone >= size_tones:
37                result_tone -= size_tones36                result_tone -= size_tones
38            return Tone(tones_tuple[result_tone])37            return Tone(tones_tuple[result_tone])
3938
40    def __sub__(self, other):39    def __sub__(self, other):
41        if type(other) is Tone:40        if type(other) is Tone:
42            left_position = get_position_in_tuple(self.data, tones_tuple)41            left_position = get_position_in_tuple(self.data, tones_tuple)
43            right_position = get_position_in_tuple(other.data, tones_tuple)42            right_position = get_position_in_tuple(other.data, tones_tuple)
44            difference = left_position - right_position43            difference = left_position - right_position
45            # G - C = 7 (perfect 5th), но C - G = 5 (perfect 4th), явно въртим окръжността наобратно?  44            # G - C = 7 (perfect 5th), но C - G = 5 (perfect 4th), явно въртим окръжността наобратно?  
46            if difference >= 0:45            if difference >= 0:
47                return Interval(difference)46                return Interval(difference)
48            else:47            else:
49                return Interval(len(interval_tuple) - abs(difference))48                return Interval(len(interval_tuple) - abs(difference))
50        if type(other) is Interval:49        if type(other) is Interval:
51            result_tone = get_position_in_tuple(self.data, tones_tuple) - other.data50            result_tone = get_position_in_tuple(self.data, tones_tuple) - other.data
52            size_tones = len(tones_tuple)51            size_tones = len(tones_tuple)
53            while result_tone < 0:52            while result_tone < 0:
54                result_tone += size_tones53                result_tone += size_tones
55            return Tone(tones_tuple[result_tone])54            return Tone(tones_tuple[result_tone])
5655
57class Interval:56class Interval:
5857
59    def __init__(self, data):58    def __init__(self, data):
60        size_intervals = len(interval_tuple)59        size_intervals = len(interval_tuple)
61        while data >= size_intervals: # може би трябваше с %, чак сега виждам колко зле съм го направил 60        while data >= size_intervals: # може би трябваше с %, чак сега виждам колко зле съм го направил 
62            data -= size_intervals61            data -= size_intervals
63        self.data = data62        self.data = data
6463
65    def __neg__(self):64    def __neg__(self):
66        return -self.data65        return -self.data
6766
68    def __str__(self):67    def __str__(self):
69        return interval_tuple[self.data]68        return interval_tuple[self.data]
7069
71    def __add__(self, other): # ако имаме Interval + Tone70    def __add__(self, other): # ако имаме Interval + Tone
72        if type(other) is Tone:71        if type(other) is Tone:
73            raise TypeError("Invalid operation")72            raise TypeError("Invalid operation")
74        if type(other) is Interval:73        if type(other) is Interval:
75            result_data = self.data + other.data74            result_data = self.data + other.data
76            return Interval(result_data) # __init__ ще се оправи дори с неща >= 1275            return Interval(result_data) # __init__ ще се оправи дори с неща >= 12
7776
78    def __sub__(self, other): # ако имаме Interval - Tone77    def __sub__(self, other): # ако имаме Interval - Tone
79        if type(other) is Tone:78        if type(other) is Tone:
80            raise TypeError("Invalid operation")79            raise TypeError("Invalid operation")
n81        passn
82    80    
8381
84class Chord:82class Chord:
8583
86    def __init__(self, *args):84    def __init__(self, *args):
87        self.tones = set()85        self.tones = set()
88        self.main_tone = str(args[0])86        self.main_tone = str(args[0])
89        for item in args: # добавяме всички тонове, включително и main-a87        for item in args: # добавяме всички тонове, включително и main-a
90            if type(item) is Tone:88            if type(item) is Tone:
91                self.tones.add(str(item))89                self.tones.add(str(item))
92        if len(self.tones) == 1:90        if len(self.tones) == 1:
93            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")
94            92            
95    def _fill_list_from_source(self, source, destination): # може би не е най-доброто име за функцията93    def _fill_list_from_source(self, source, destination): # може би не е най-доброто име за функцията
96        for item in source:94        for item in source:
97            if item in self.tones:95            if item in self.tones:
98                destination.append(item)96                destination.append(item)
99        return destination97        return destination
10098
101    def __str__(self):99    def __str__(self):
102        self.tones = list(self.tones)100        self.tones = list(self.tones)
103        position_of_main_tone = 0101        position_of_main_tone = 0
104        # тъй като въртенето започва от main тона, правя два tuple-a, за тези след него в окръжността102        # тъй като въртенето започва от main тона, правя два tuple-a, за тези след него в окръжността
105        # е за тези преди него103        # е за тези преди него
106        # целта е да се създаде сортиран лист, който в последствие да join-нем с "-"104        # целта е да се създаде сортиран лист, който в последствие да join-нем с "-"
n107        for i in range(0,len(tones_tuple)):n105        for i in range(0, len(tones_tuple)):
108            if self.main_tone == tones_tuple[i]:106            if self.main_tone == tones_tuple[i]:
109                position_of_main_tone = i107                position_of_main_tone = i
110        after_tuple = tones_tuple[position_of_main_tone:]108        after_tuple = tones_tuple[position_of_main_tone:]
111        before_tuple = tones_tuple[:position_of_main_tone]109        before_tuple = tones_tuple[:position_of_main_tone]
112        to_return = list()110        to_return = list()
113        to_return = self._fill_list_from_source(after_tuple, to_return)111        to_return = self._fill_list_from_source(after_tuple, to_return)
114        to_return = self._fill_list_from_source(before_tuple, to_return)112        to_return = self._fill_list_from_source(before_tuple, to_return)
115        return "-".join(to_return)113        return "-".join(to_return)
116        114        
117    def check_for_specific_chord(self, chord_string):115    def check_for_specific_chord(self, chord_string):
118        main_position = get_position_in_tuple(str(self.main_tone), tones_tuple)116        main_position = get_position_in_tuple(str(self.main_tone), tones_tuple)
119        wanted_position = get_position_in_tuple(chord_string, interval_tuple)117        wanted_position = get_position_in_tuple(chord_string, interval_tuple)
120        for item in self.tones:118        for item in self.tones:
121            curr_position = get_position_in_tuple(str(item), tones_tuple)119            curr_position = get_position_in_tuple(str(item), tones_tuple)
122            # ако са на позиции 3 и 6 примерно, ще има minor 3rd120            # ако са на позиции 3 и 6 примерно, ще има minor 3rd
123            # но трябва да проверим и случая ако са на позиции 11 и 2 примерно, разликата м/у тях пак е 3121            # но трябва да проверим и случая ако са на позиции 11 и 2 примерно, разликата м/у тях пак е 3
124            # тогава пак ще има minor 3rd, но за целта трябва 12 - (11-2)122            # тогава пак ще има minor 3rd, но за целта трябва 12 - (11-2)
125            current_diff = abs(curr_position - main_position)123            current_diff = abs(curr_position - main_position)
126            if current_diff == wanted_position or len(tones_tuple) - current_diff == wanted_position:124            if current_diff == wanted_position or len(tones_tuple) - current_diff == wanted_position:
127                return True125                return True
128        return False126        return False
129127
130    def is_minor(self):128    def is_minor(self):
131        return self.check_for_specific_chord("minor 3rd")129        return self.check_for_specific_chord("minor 3rd")
132    130    
133    def is_major(self):131    def is_major(self):
134        return self.check_for_specific_chord("major 3rd")132        return self.check_for_specific_chord("major 3rd")
135133
136    def is_power_chord(self):134    def is_power_chord(self):
137        return not self.is_minor() and not self.is_major()135        return not self.is_minor() and not self.is_major()
138136
139    def __add__(self, other):137    def __add__(self, other):
140        if type(other) is Tone:138        if type(other) is Tone:
141            result_chord = Chord(self.main_tone)139            result_chord = Chord(self.main_tone)
142            result_chord.tones.update(self.tones)140            result_chord.tones.update(self.tones)
143            result_chord.tones.add(other.data)141            result_chord.tones.add(other.data)
144            return result_chord142            return result_chord
145        if type(other) is Chord:143        if type(other) is Chord:
146            result_chord = Chord(self.main_tone)144            result_chord = Chord(self.main_tone)
147            result_chord.tones.update(self.tones)145            result_chord.tones.update(self.tones)
148            result_chord.tones.add(other.main_tone)146            result_chord.tones.add(other.main_tone)
149            result_chord.tones.update(other.tones)147            result_chord.tones.update(other.tones)
150            return result_chord148            return result_chord
151        149        
152    def __sub__(self, other):150    def __sub__(self, other):
153        if (not other.data in self.tones) and other.data != self.main_tone:151        if (not other.data in self.tones) and other.data != self.main_tone:
154            raise TypeError(f"Cannot remove tone {other.data} from chord {self}")152            raise TypeError(f"Cannot remove tone {other.data} from chord {self}")
155        if len(self.tones) < 3:153        if len(self.tones) < 3:
156            raise TypeError("Cannot have a chord made of only 1 unique tone")154            raise TypeError("Cannot have a chord made of only 1 unique tone")
157        if type(other) is Tone:155        if type(other) is Tone:
158            result_chord = Chord(self.main_tone)156            result_chord = Chord(self.main_tone)
t159            if other.data == self.main_tone:t157            if other.data == self.main_tone: # fix, не работеше правилно
158                main_tone_pos = get_position_in_tuple(self.main_tone, tones_tuple)
159                for item in tones_tuple[main_tone_pos+1:]: # гледаме първо тия след него до края на tuple-a
160                    if item in tuple(self.tones):
160                result_chord.main_tone = self.tones[0]161                        result_chord.main_tone = item
162                        break
163                if result_chord.main_tone == other.data: # ако не сме променили main_tone с тези след него
164                    for item in tones_tuple[:main_tone_pos]:
165                        if item in tuple(self.tones):
166                            result_chord.main_tone = item
167                            break
161                result_chord.tones.update(list(self.tones)[1:])168                result_chord.tones.update(self.tones)
162            else:169                result_chord.tones.remove(self.main_tone)
163                position = get_position_in_tuple(other.data, tuple(self.tones))170            else: # и тук пак fix
164                result_chord.tones.update(list(self.tones)[:position])171                result_chord.tones.update(self.tones)
165                result_chord.tones.update(list(self.tones)[position+1:])172                result_chord.tones.remove(other.data)
166            return result_chord173            return result_chord
167    174    
168    def transposed(self, interval):175    def transposed(self, interval):
169        # можеше да използвам и събирането, което дефинирах за тоновете...176        # можеше да използвам и събирането, което дефинирах за тоновете...
170        position = 0177        position = 0
171        if type(interval) is int:178        if type(interval) is int:
172            position = interval179            position = interval
173        else:180        else:
174            position = interval.data181            position = interval.data
175        result_chord = Chord(self.main_tone)182        result_chord = Chord(self.main_tone)
176        main_tone_pos = get_position_in_tuple(self.main_tone, tones_tuple) + position183        main_tone_pos = get_position_in_tuple(self.main_tone, tones_tuple) + position
177        # имаше някакви бъгове, които всеки път даваха различен main_tone, затова main тона е отделно, нищо че може да се сложи и в долния цикъл184        # имаше някакви бъгове, които всеки път даваха различен main_tone, затова main тона е отделно, нищо че може да се сложи и в долния цикъл
178        if main_tone_pos < 0:185        if main_tone_pos < 0:
179            main_tone_pos += len(tones_tuple)186            main_tone_pos += len(tones_tuple)
180        elif main_tone_pos >= len(tones_tuple):187        elif main_tone_pos >= len(tones_tuple):
181            main_tone_pos -= len(tones_tuple)188            main_tone_pos -= len(tones_tuple)
182        result_chord.main_tone = tones_tuple[main_tone_pos]189        result_chord.main_tone = tones_tuple[main_tone_pos]
183        # а иначе цикъла, в който пак си го има main тона попринцип, ама програмата си прави каквото си иска и всеки път дава различен резултат190        # а иначе цикъла, в който пак си го има main тона попринцип, ама програмата си прави каквото си иска и всеки път дава различен резултат
184        for item in self.tones:191        for item in self.tones:
185            curr_position = get_position_in_tuple(item, tones_tuple) + position192            curr_position = get_position_in_tuple(item, tones_tuple) + position
186            if curr_position < 0:193            if curr_position < 0:
187                curr_position += len(tones_tuple)194                curr_position += len(tones_tuple)
188            elif curr_position >= len(tones_tuple):195            elif curr_position >= len(tones_tuple):
189                curr_position -= len(tones_tuple)196                curr_position -= len(tones_tuple)
190            result_chord.tones.add(tones_tuple[curr_position])197            result_chord.tones.add(tones_tuple[curr_position])
191        return result_chord198        return result_chord
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op

f1# коментарите ги пиша след като съм готов с целия код, има доста тъпотии из кода, нема ги оправямf1# коментарите ги пиша след като съм готов с целия код, има доста тъпотии из кода, нема ги оправям
22
3# може би трябваше да са сетове3# може би трябваше да са сетове
4# и с главни букви, ама вече ги бех написал така4# и с главни букви, ама вече ги бех написал така
5interval_tuple = ("unison", "minor 2nd", "major 2nd", "minor 3rd",5interval_tuple = ("unison", "minor 2nd", "major 2nd", "minor 3rd",
6                  "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th",6                  "major 3rd", "perfect 4th", "diminished 5th", "perfect 5th",
7                  "minor 6th", "major 6th", "minor 7th", "major 7th")7                  "minor 6th", "major 6th", "minor 7th", "major 7th")
8tones_tuple = ("A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#")8tones_tuple = ("A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#")
9# не е само за tuple, а за всички iterable колекции с __getitem__ или квото беше там operator[]9# не е само за tuple, а за всички iterable колекции с __getitem__ или квото беше там operator[]
10def get_position_in_tuple(element, tuple):10def get_position_in_tuple(element, tuple):
11    for i in range(0,len(tuple)):11    for i in range(0,len(tuple)):
12        if tuple[i] == element:12        if tuple[i] == element:
13            return i13            return i
14    return -101 # да не ми счупи is_minor и is_major ако ми въведете невалиден тон14    return -101 # да не ми счупи is_minor и is_major ако ми въведете невалиден тон
1515
1616
17class Tone:17class Tone:
1818
19    def __init__(self, data):19    def __init__(self, data):
20        # не правя проверка дали е валиден тон, но ако не е не би трябвало да счупи програмата20        # не правя проверка дали е валиден тон, но ако не е не би трябвало да счупи програмата
21        # или поне функциите, за които го тествах21        # или поне функциите, за които го тествах
22        self.data = data 22        self.data = data 
2323
24    def __str__(self):24    def __str__(self):
25        return self.data25        return self.data
2626
27    def __eq__(self, other): # трябва да се дефинира, иначе проверката е с is, което не е желаното поведение27    def __eq__(self, other): # трябва да се дефинира, иначе проверката е с is, което не е желаното поведение
28        return self.data == other.data28        return self.data == other.data
29    29    
30    def __add__(self, other):30    def __add__(self, other):
31        if type(other) is Tone:31        if type(other) is Tone:
32            return Chord(self, other)32            return Chord(self, other)
33        if type(other) is Interval:33        if type(other) is Interval:
34            result_tone = get_position_in_tuple(self.data, tones_tuple) + other.data34            result_tone = get_position_in_tuple(self.data, tones_tuple) + other.data
35            size_tones = len(tones_tuple)35            size_tones = len(tones_tuple)
36            while result_tone >= size_tones:36            while result_tone >= size_tones:
37                result_tone -= size_tones37                result_tone -= size_tones
38            return Tone(tones_tuple[result_tone])38            return Tone(tones_tuple[result_tone])
3939
40    def __sub__(self, other):40    def __sub__(self, other):
41        if type(other) is Tone:41        if type(other) is Tone:
42            left_position = get_position_in_tuple(self.data, tones_tuple)42            left_position = get_position_in_tuple(self.data, tones_tuple)
43            right_position = get_position_in_tuple(other.data, tones_tuple)43            right_position = get_position_in_tuple(other.data, tones_tuple)
44            difference = left_position - right_position44            difference = left_position - right_position
45            # G - C = 7 (perfect 5th), но C - G = 5 (perfect 4th), явно въртим окръжността наобратно?  45            # G - C = 7 (perfect 5th), но C - G = 5 (perfect 4th), явно въртим окръжността наобратно?  
46            if difference >= 0:46            if difference >= 0:
47                return Interval(difference)47                return Interval(difference)
48            else:48            else:
49                return Interval(len(interval_tuple) - abs(difference))49                return Interval(len(interval_tuple) - abs(difference))
50        if type(other) is Interval:50        if type(other) is Interval:
51            result_tone = get_position_in_tuple(self.data, tones_tuple) - other.data51            result_tone = get_position_in_tuple(self.data, tones_tuple) - other.data
52            size_tones = len(tones_tuple)52            size_tones = len(tones_tuple)
53            while result_tone < 0:53            while result_tone < 0:
54                result_tone += size_tones54                result_tone += size_tones
55            return Tone(tones_tuple[result_tone])55            return Tone(tones_tuple[result_tone])
5656
57class Interval:57class Interval:
5858
59    def __init__(self, data):59    def __init__(self, data):
60        size_intervals = len(interval_tuple)60        size_intervals = len(interval_tuple)
61        while data >= size_intervals: # може би трябваше с %, чак сега виждам колко зле съм го направил 61        while data >= size_intervals: # може би трябваше с %, чак сега виждам колко зле съм го направил 
62            data -= size_intervals62            data -= size_intervals
63        self.data = data63        self.data = data
6464
65    def __neg__(self):65    def __neg__(self):
66        return -self.data66        return -self.data
6767
68    def __str__(self):68    def __str__(self):
69        return interval_tuple[self.data]69        return interval_tuple[self.data]
7070
71    def __add__(self, other): # ако имаме Interval + Tone71    def __add__(self, other): # ако имаме Interval + Tone
72        if type(other) is Tone:72        if type(other) is Tone:
73            raise TypeError("Invalid operation")73            raise TypeError("Invalid operation")
74        if type(other) is Interval:74        if type(other) is Interval:
75            result_data = self.data + other.data75            result_data = self.data + other.data
76            return Interval(result_data) # __init__ ще се оправи дори с неща >= 1276            return Interval(result_data) # __init__ ще се оправи дори с неща >= 12
7777
78    def __sub__(self, other): # ако имаме Interval - Tone78    def __sub__(self, other): # ако имаме Interval - Tone
79        if type(other) is Tone:79        if type(other) is Tone:
80            raise TypeError("Invalid operation")80            raise TypeError("Invalid operation")
81        pass81        pass
82    82    
8383
84class Chord:84class Chord:
8585
86    def __init__(self, *args):86    def __init__(self, *args):
87        self.tones = set()87        self.tones = set()
88        self.main_tone = str(args[0])88        self.main_tone = str(args[0])
89        for item in args: # добавяме всички тонове, включително и main-a89        for item in args: # добавяме всички тонове, включително и main-a
90            if type(item) is Tone:90            if type(item) is Tone:
91                self.tones.add(str(item))91                self.tones.add(str(item))
92        if len(self.tones) == 1:92        if len(self.tones) == 1:
t93            raise AttributeError("Cannot have a chord made of only 1 unique tone")t93            raise TypeError("Cannot have a chord made of only 1 unique tone")
94            94            
95    def _fill_list_from_source(self, source, destination): # може би не е най-доброто име за функцията95    def _fill_list_from_source(self, source, destination): # може би не е най-доброто име за функцията
96        for item in source:96        for item in source:
97            if item in self.tones:97            if item in self.tones:
98                destination.append(item)98                destination.append(item)
99        return destination99        return destination
100100
101    def __str__(self):101    def __str__(self):
102        self.tones = list(self.tones)102        self.tones = list(self.tones)
103        position_of_main_tone = 0103        position_of_main_tone = 0
104        # тъй като въртенето започва от main тона, правя два tuple-a, за тези след него в окръжността104        # тъй като въртенето започва от main тона, правя два tuple-a, за тези след него в окръжността
105        # е за тези преди него105        # е за тези преди него
106        # целта е да се създаде сортиран лист, който в последствие да join-нем с "-"106        # целта е да се създаде сортиран лист, който в последствие да join-нем с "-"
107        for i in range(0,len(tones_tuple)):107        for i in range(0,len(tones_tuple)):
108            if self.main_tone == tones_tuple[i]:108            if self.main_tone == tones_tuple[i]:
109                position_of_main_tone = i109                position_of_main_tone = i
110        after_tuple = tones_tuple[position_of_main_tone:]110        after_tuple = tones_tuple[position_of_main_tone:]
111        before_tuple = tones_tuple[:position_of_main_tone]111        before_tuple = tones_tuple[:position_of_main_tone]
112        to_return = list()112        to_return = list()
113        to_return = self._fill_list_from_source(after_tuple, to_return)113        to_return = self._fill_list_from_source(after_tuple, to_return)
114        to_return = self._fill_list_from_source(before_tuple, to_return)114        to_return = self._fill_list_from_source(before_tuple, to_return)
115        return "-".join(to_return)115        return "-".join(to_return)
116        116        
117    def check_for_specific_chord(self, chord_string):117    def check_for_specific_chord(self, chord_string):
118        main_position = get_position_in_tuple(str(self.main_tone), tones_tuple)118        main_position = get_position_in_tuple(str(self.main_tone), tones_tuple)
119        wanted_position = get_position_in_tuple(chord_string, interval_tuple)119        wanted_position = get_position_in_tuple(chord_string, interval_tuple)
120        for item in self.tones:120        for item in self.tones:
121            curr_position = get_position_in_tuple(str(item), tones_tuple)121            curr_position = get_position_in_tuple(str(item), tones_tuple)
122            # ако са на позиции 3 и 6 примерно, ще има minor 3rd122            # ако са на позиции 3 и 6 примерно, ще има minor 3rd
123            # но трябва да проверим и случая ако са на позиции 11 и 2 примерно, разликата м/у тях пак е 3123            # но трябва да проверим и случая ако са на позиции 11 и 2 примерно, разликата м/у тях пак е 3
124            # тогава пак ще има minor 3rd, но за целта трябва 12 - (11-2)124            # тогава пак ще има minor 3rd, но за целта трябва 12 - (11-2)
125            current_diff = abs(curr_position - main_position)125            current_diff = abs(curr_position - main_position)
126            if current_diff == wanted_position or len(tones_tuple) - current_diff == wanted_position:126            if current_diff == wanted_position or len(tones_tuple) - current_diff == wanted_position:
127                return True127                return True
128        return False128        return False
129129
130    def is_minor(self):130    def is_minor(self):
131        return self.check_for_specific_chord("minor 3rd")131        return self.check_for_specific_chord("minor 3rd")
132    132    
133    def is_major(self):133    def is_major(self):
134        return self.check_for_specific_chord("major 3rd")134        return self.check_for_specific_chord("major 3rd")
135135
136    def is_power_chord(self):136    def is_power_chord(self):
137        return not self.is_minor() and not self.is_major()137        return not self.is_minor() and not self.is_major()
138138
139    def __add__(self, other):139    def __add__(self, other):
140        if type(other) is Tone:140        if type(other) is Tone:
141            result_chord = Chord(self.main_tone)141            result_chord = Chord(self.main_tone)
142            result_chord.tones.update(self.tones)142            result_chord.tones.update(self.tones)
143            result_chord.tones.add(other.data)143            result_chord.tones.add(other.data)
144            return result_chord144            return result_chord
145        if type(other) is Chord:145        if type(other) is Chord:
146            result_chord = Chord(self.main_tone)146            result_chord = Chord(self.main_tone)
147            result_chord.tones.update(self.tones)147            result_chord.tones.update(self.tones)
148            result_chord.tones.add(other.main_tone)148            result_chord.tones.add(other.main_tone)
149            result_chord.tones.update(other.tones)149            result_chord.tones.update(other.tones)
150            return result_chord150            return result_chord
151        151        
152    def __sub__(self, other):152    def __sub__(self, other):
153        if (not other.data in self.tones) and other.data != self.main_tone:153        if (not other.data in self.tones) and other.data != self.main_tone:
154            raise TypeError(f"Cannot remove tone {other.data} from chord {self}")154            raise TypeError(f"Cannot remove tone {other.data} from chord {self}")
155        if len(self.tones) < 3:155        if len(self.tones) < 3:
156            raise TypeError("Cannot have a chord made of only 1 unique tone")156            raise TypeError("Cannot have a chord made of only 1 unique tone")
157        if type(other) is Tone:157        if type(other) is Tone:
158            result_chord = Chord(self.main_tone)158            result_chord = Chord(self.main_tone)
159            if other.data == self.main_tone:159            if other.data == self.main_tone:
160                result_chord.main_tone = self.tones[0]160                result_chord.main_tone = self.tones[0]
161                result_chord.tones.update(list(self.tones)[1:])161                result_chord.tones.update(list(self.tones)[1:])
162            else:162            else:
163                position = get_position_in_tuple(other.data, tuple(self.tones))163                position = get_position_in_tuple(other.data, tuple(self.tones))
164                result_chord.tones.update(list(self.tones)[:position])164                result_chord.tones.update(list(self.tones)[:position])
165                result_chord.tones.update(list(self.tones)[position+1:])165                result_chord.tones.update(list(self.tones)[position+1:])
166            return result_chord166            return result_chord
167    167    
168    def transposed(self, interval):168    def transposed(self, interval):
169        # можеше да използвам и събирането, което дефинирах за тоновете...169        # можеше да използвам и събирането, което дефинирах за тоновете...
170        position = 0170        position = 0
171        if type(interval) is int:171        if type(interval) is int:
172            position = interval172            position = interval
173        else:173        else:
174            position = interval.data174            position = interval.data
175        result_chord = Chord(self.main_tone)175        result_chord = Chord(self.main_tone)
176        main_tone_pos = get_position_in_tuple(self.main_tone, tones_tuple) + position176        main_tone_pos = get_position_in_tuple(self.main_tone, tones_tuple) + position
177        # имаше някакви бъгове, които всеки път даваха различен main_tone, затова main тона е отделно, нищо че може да се сложи и в долния цикъл177        # имаше някакви бъгове, които всеки път даваха различен main_tone, затова main тона е отделно, нищо че може да се сложи и в долния цикъл
178        if main_tone_pos < 0:178        if main_tone_pos < 0:
179            main_tone_pos += len(tones_tuple)179            main_tone_pos += len(tones_tuple)
180        elif main_tone_pos >= len(tones_tuple):180        elif main_tone_pos >= len(tones_tuple):
181            main_tone_pos -= len(tones_tuple)181            main_tone_pos -= len(tones_tuple)
182        result_chord.main_tone = tones_tuple[main_tone_pos]182        result_chord.main_tone = tones_tuple[main_tone_pos]
183        # а иначе цикъла, в който пак си го има main тона попринцип, ама програмата си прави каквото си иска и всеки път дава различен резултат183        # а иначе цикъла, в който пак си го има main тона попринцип, ама програмата си прави каквото си иска и всеки път дава различен резултат
184        for item in self.tones:184        for item in self.tones:
185            curr_position = get_position_in_tuple(item, tones_tuple) + position185            curr_position = get_position_in_tuple(item, tones_tuple) + position
186            if curr_position < 0:186            if curr_position < 0:
187                curr_position += len(tones_tuple)187                curr_position += len(tones_tuple)
188            elif curr_position >= len(tones_tuple):188            elif curr_position >= len(tones_tuple):
189                curr_position -= len(tones_tuple)189                curr_position -= len(tones_tuple)
190            result_chord.tones.add(tones_tuple[curr_position])190            result_chord.tones.add(tones_tuple[curr_position])
191        return result_chord191        return result_chord
Legends
Colors
 Added 
Changed
Deleted
Links
(f)irst change
(n)ext change
(t)op