-
Notifications
You must be signed in to change notification settings - Fork 1
/
chromosome.py
134 lines (101 loc) · 4.21 KB
/
chromosome.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import random
class Chromosome:
__map = ''
__winning_score = True
def __init__(self, string):
self.__string = string
self.__fitness = self.__calculate_fitness()
self.__fails = False
def __gt__(self, other):
if not isinstance(other, Chromosome):
raise ValueError('Operand is not type of Chromosome.')
return self.get_fitness() > other.get_fitness()
def __lt__(self, other):
if not isinstance(other, Chromosome):
raise ValueError('Operand is not type of Chromosome.')
return self.get_fitness() < other.get_fitness()
def __ge__(self, other):
if not isinstance(other, Chromosome):
raise TypeError('Operand is not type of Chromosome.')
return self.get_fitness() >= other.get_fitness()
def __le__(self, other):
if not isinstance(other, Chromosome):
raise ValueError('Operand is not type of Chromosome.')
return self.get_fitness() <= other.get_fitness()
def __str__(self):
st = '{} {} {} {}'.format(self.__string, Chromosome.__map, self.get_fitness(), not self.__fails)
return st
def get_fitness(self):
return self.__fitness
def get_string(self):
return self.__string
def create_children(self, other: 'Chromosome', a: int, b: int) -> list['Chromosome', 'Chromosome']:
a, b = min(a, b), max(a, b)
st1 = self.__string[:a] + other.__string[a:b] + self.__string[b:]
st2 = other.__string[:a] + self.__string[a:b] + other.__string[b:]
return [Chromosome(st1), Chromosome(st2)]
def mutate(self):
i = random.randint(0, len(self.__string) - 1)
while (new_value := str(random.randint(0, 2))) == self.__string[i]:
continue
st = self.__string[:i] + new_value + self.__string[i+1:]
self.__string = st
def check_fails(self) -> bool:
return self.__fails
def __calculate_fitness(self):
chromosome = self.__string
map_object = Chromosome.__map
extra_fitness = 0
largest_path = 0
path_length = 0
is_on_air = False
for j, item in enumerate(map_object):
decision = chromosome[j]
# Jumping twice which is undefined. We define it here
if j != 0:
if is_on_air and chromosome[j - 1] == '1':
extra_fitness += -1
decision = '0'
path_length += 1
if j != len(map_object) - 1: # if we are not on the last block
next_decision = chromosome[j + 1]
next_item = map_object[j + 1]
# If we lose
if ((not is_on_air) and next_item == 'G' and decision != '1') or (next_item == 'L' and decision != '2'):
if path_length > largest_path:
largest_path = path_length
path_length = 0
self.__fails = True
continue
# If we do unnecessary jump
if (next_item == '_' or next_item == 'M') and decision != '0':
extra_fitness += -1
if decision == '1' or decision == '2':
extra_fitness += -0.5
# If we eat mushroom
if next_item == 'M' and decision != '1':
extra_fitness += 3
# If we kill a Goomba
if j != len(chromosome) - 2 and map_object[j + 2] == 'G' and decision == '1':
extra_fitness += 3
else:
# If we jump on flag
if decision == '1':
extra_fitness += 2
is_on_air = decision == '1'
# If we win
if largest_path == 0:
if Chromosome.__winning_score:
largest_path = len(self.__string) * 1.25
else:
largest_path = len(self.__string)
return largest_path + extra_fitness
@staticmethod
def set_map(map_object: str):
Chromosome.__map = map_object
@staticmethod
def set_winning_score(value: bool):
Chromosome.__winning_score = value
#Chromosome.set_map('__G__G_L___')
#c = Chromosome('11010010001')
#print(c)