过去几天我一直在尝试实现所谓的“智能点”游戏。我第一次在Code Bullet的YouTube频道上看到它:https://www.youtube.com/watch?v=BOZfhUcNiqk。不幸的是,它是用Processing语言编写的,而我唯一勉强熟悉的语言是Python。我完成了游戏的Python版本,但出现了一些错误。
问题是,在第二代被选为最佳的点几乎立即停止移动。我认为这与我在面向对象编程方面的不足以及错误复制Brain类有关。步骤(我用来移动的)从开始设置的零跳到最大值(200),在主循环的第一次或第二次循环时。但问题不止于此。在下一代,当我试图将大脑步骤设置为零时,它就崩溃了,显示如下错误:
AttributeError: 'NoneType' object has no attribute 'brain'
我尝试手动设置新的大脑,但仍然得到相同的错误。如果有已经完成这个项目或有时间帮助我解决这个错误或整个项目的人,我将不胜感激。
我知道代码中有很多未使用的内容,但那只是我尝试修复它时的产物:(
注释掉的代码是我之前使用的一些旧代码。
main2.py(主循环):
import pygameimport klase2pygame.init()def main(): win = pygame.display.set_mode((klase2.WIN_W, klase2.WIN_H)) clock = pygame.time.Clock() population = klase2.Population() dots = population.return_dots(1000) goal = klase2.Goal() run = True while run: clock.tick(30) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False win.fill((255, 255, 255)) goal.draw_goal(win) for dot in dots: dot.draw_dot(win) dot.update_dot() if population.all_dots_dead(): # 自然选择 population.natural_selection() # 变异 dots = population.mutate_dots() population.gen += 1 print(population.gen) pygame.display.update()main()
kase2(处理所有函数和类):
import pygameimport numpy as npfrom pygame import gfxdrawimport mathimport randompygame.init()WIN_W = 500WIN_H = 500class Brain: def __init__(self, size): self.step = 0 self.size = size self.directionsx = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.size / 2))) self.directionsy = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.size / 2))) def clone(self): self.size = self.size self.directionsx = self.directionsx self.directionsy = self.directionsy self.step = 0class Goal: def __init__(self): self.x = WIN_W / 2 self.y = 10 self.color = (255, 20, 20) self.r = 5 def draw_goal(self, win): pygame.gfxdraw.aacircle(win, int(self.x), int(self.y), self.r, self.color) pygame.gfxdraw.filled_circle(win, int(self.x), int(self.y), self.r, self.color)class Dot: goal = Goal() def __init__(self): self.tick = 0 self.goal = Goal() self.brain = Brain(400) self.velx = 0 self.vely = 0 self.accx = 0 self.accy = 0 self.x = WIN_W / 2 self.y = WIN_H - 10 self.r = 3 self.color = (0, 0, 0) self.alive = True self.velLimit = 5 self.fitness = 0 def draw_dot(self, win): pygame.gfxdraw.aacircle(win, int(self.x), int(self.y), self.r, self.color) pygame.gfxdraw.filled_circle(win, int(self.x), int(self.y), self.r, self.color) def move_dot(self): if self.brain.size / 2 > self.brain.step: self.accx = self.brain.directionsx[self.brain.step] self.accy = self.brain.directionsy[self.brain.step] self.brain.step += 1 else: self.alive = False self.velx += self.accx self.vely += self.accy if self.velx > self.velLimit: self.velx = self.velLimit elif self.velx < -self.velLimit: self.velx = -self.velLimit if self.vely > self.velLimit: self.vely = self.velLimit elif self.vely < -self.velLimit: self.vely = -self.velLimit self.x += self.velx self.y += self.vely def update_dot(self): if not self.reached_goal(): self.tick += 1 if self.alive: self.move_dot() if self.x < 0 + self.r or self.x > WIN_W - self.r or self.y < 0 + self.r or self.y > WIN_H - self.r or self.reached_goal(): self.alive = False def distance_to_goal(self): a = abs(self.x - self.goal.x) b = abs(self.y - self.goal.y) return math.sqrt(a**2 + b**2) def reached_goal(self): if self.distance_to_goal() <= self.r + self.goal.r: return True return False def fitness_dot(self): if self.reached_goal(): self.fitness = 1 / (self.brain.step) else: self.fitness = 1 / (self.distance_to_goal()**2) return self.fitnessclass Population: def __init__(self): self.dots = [] self.newDots = [] self.gen = 0 self.mutateChance = 800 self.size = 0 self.fitness_sum = 0 def return_dots(self, size): self.size = size for _ in range(size): self.dots.append(Dot()) return self.dots def all_dots_dead(self): for i in range(len(self.dots)): if self.dots[i].alive: return False return True def sort_dots(self): self.dots = sorted(self.dots, key=lambda dot: dot.fitness, reverse=True) def sum_fitness(self): for dot in self.dots: self.fitness_sum += dot.fitness_dot() return self.fitness_sum def get_parent(self): rand = random.uniform(0, self.fitness_sum) running_sum = 0 for dot in self.dots: running_sum += dot.fitness if running_sum >= rand: return dot def natural_selection(self): for dot in self.dots: dot.fitness_dot() self.sort_dots() self.newDots.append(self.dots[0]) self.sum_fitness() for i in range(1, len(self.dots)): parent = self.get_parent() self.newDots.append(Dot()) self.newDots[i].brain = parent.brain self.newDots[i].brain.step = 0 self.dots = self.newDots def mutate_dots(self): for i in range(1, len(self.dots)): rand = random.randint(0, 1000) if rand > self.mutateChance: self.dots[i].brain.directionsx = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.dots[i].brain.size / 2))) self.dots[i].brain.directionsy = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.dots[i].brain.size / 2))) return self.dots # def natural_selection(self): # self.selectedDots = [] # for dot in self.dots: # dot.fitness_dot() # self.sort_dots() # for i in range(0, int(len(self.dots) / 3)): # self.selectedDots.append(self.dots[i]) # self.selectedDots[i].tick = 0 # self.selectedDots[i].velx = 0 # self.selectedDots[i].vely = 0 # self.selectedDots[i].accx = 0 # self.selectedDots[i].accy = 0 # self.selectedDots[i].x = WIN_W / 2 # self.selectedDots[i].y = WIN_H - 10 # self.selectedDots[i].alive = True # self.selectedDots[i].fitness = 0 # self.selectedDots[i].brain.step = 0 # self.selectedDots[i].goal = Goal() # # def new_dots(self): # for i in range(len(self.selectedDots), len(self.dots)): # self.selectedDots.append(Dot()) # self.dots = self.selectedDots # # def mutate_dots(self): # for i, dot in enumerate(self.dots): # isMutating = random.randint(0, 1000) # if self.mutateChance > isMutating and i > int(len(self.dots) / 3) and i < (2 * int((len(self.dots) / 3))): # for j in range(len(dot.brain.directionsx)): # isMutatingDir = random.randint(0, 1000) # if isMutatingDir >= 800: # dot.brain.directionsx[j] = np.random.uniform(low=-2.5, high=2.5, size=1) # for j in range(len(dot.brain.directionsy)): # isMutatingDir = random.randint(0, 1000) # if isMutatingDir >= 800: # dot.brain.directionsy[j] = np.random.uniform(low=-2.5, high=2.5, size=1) # return self.dots
回答:
NoneType错误是由get_parent方法引起的。它搜索子点,但如果搜索失败则没有返回值(相当于return None)。以下代码可以解决这个错误
def get_parent(self): rand = random.uniform(0, self.fitness_sum) running_sum = 0 for dot in self.dots: running_sum += dot.fitness if running_sum >= rand: return dot return self.dots[0] # 搜索失败,返回第一个点