【问题标题】:Genetic algorithm for "smart dots" in python doesn't workpython中“智能点”的遗传算法不起作用
【发布时间】:2020-11-14 14:44:54
【问题描述】:

在过去的几天里,我一直在尝试实现所谓的“智能点”游戏。我第一次在 Code Bullet youtube 频道上看到它:https://www.youtube.com/watch?v=BOZfhUcNiqk。不幸的是,它是用处理语言编码的,而我几乎不知道的唯一语言是 Python。我完成了我的python版本的游戏,但出现了一些错误。

问题在于,在第二代中,被选为最佳的点几乎会立即停止移动。我认为这与我不擅长 OOP 和错误地复制 Brain 类有关。步骤(我用于移动)在主循环的第一个或第二个循环中从零(在开始时设置)跳转到最大值(200)。但问题还不止于此。在下一代,当我尝试将大脑步数设置为零时,它会中断:

AttributeError: 'NoneType' object has no attribute 'brain'

我尝试手动设置新大脑,但仍然遇到相同的错误。如果有人已经做过这个或有时间可以帮助我解决这个错误甚至是项目,我将不胜感激。

我知道代码中有很多未使用的东西,但这只是我试图修复它的产物 :(

注释掉的代码是我使用的一些旧代码。

main2.py(主循环):

import pygame
import klase2

pygame.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():
            # natural selection
            population.natural_selection()

            # mutation
            dots = population.mutate_dots()
            population.gen += 1
            print(population.gen)

        pygame.display.update()


main()

kase2(处理所有函数和类):

import pygame
import numpy as np
from pygame import gfxdraw
import math
import random

pygame.init()

WIN_W = 500
WIN_H = 500


class 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 = 0


class 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.fitness


class 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
    '''

    def natural_selection(self):
        self.selectedDots = []
        for dot in self.dots:
            dot.fitness_dot()
        self.sort_dots()
        self.selectedDots = self.dots[0:int(0.3 * len(self.dots))]

    def new_dots(self):
        for i in range(len(self.dots) - int(0.3 * len(self.dots))):
            self.selectedDots.append(self.dots[i])
        self.dots = []

    def mutate_dots(self):
        for i, selectedDot in enumerate(self.selectedDots):
            self.tick = 0
            self.x = WIN_W / 2
            self.y = WIN_H - 10
            self.r = 3
            self.alive = True
            self.velLimit = 5
            self.fitness = 0

        self.dots = self.selectedDots
        return self.dots
    '''

    '''
    def mutate_dots(self):
        for i, selectedDot in enumerate(self.selectedDots):
            selectedDot.alive = True
            if i >= 1:
                isMutating = random.randint(0, 1000)
                if isMutating <= self.mutateChance:
                    for j in range(len(selectedDot.brain.directionsx)):
                        isMutatingDir = random.randint(0, 1000)
                        if isMutatingDir >= 800:
                            selectedDot.brain.directionsx[j] = np.random.uniform(low=-2.5, high=2.5, size=1)
                    for j in range(len(selectedDot.brain.directionsy)):
                        isMutatingDir = random.randint(0, 1000)
                        if isMutatingDir >= 800:
                            selectedDot.brain.directionsy[j] = np.random.uniform(low=-2.5, high=2.5, size=1)
                elif isMutating <= 800:
                    selectedDot.brain.directionsx = np.array(np.random.uniform(low=-2.5, high=2.5, size=200))
                    selectedDot.brain.directionsy = np.array(np.random.uniform(low=-2.5, high=2.5, size=200))
            self.newDots.append(selectedDot)

        return self.newDots
    '''

【问题讨论】:

    标签: python oop machine-learning pygame genetic-algorithm


    【解决方案1】:

    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]  # search failed, return 1st dot
    

    【讨论】:

      猜你喜欢
      • 2016-03-10
      • 2019-02-08
      • 2017-08-30
      • 1970-01-01
      • 2023-04-01
      • 2023-01-09
      • 1970-01-01
      • 2015-07-15
      • 1970-01-01
      相关资源
      最近更新 更多