Creating a genetic algorithm - python

Im trying to recreate this code: https://github.com/Code-Bullet/Smart-Dots-Genetic-Algorithm-Tutorial/tree/master/BestTutorialEver , but in python, and it doesn't work, it keeps mutating the best dot and every generation starts with less dots.
Here is the code (i use pygame for graphics):
Brain class:
class Brain(object):
def __init__(self, size):
self.size = size
self.step = 0
self.directions = [[0.0, 0.0] for j in range(size)]
for i in range(len(self.directions)):
randomAngle = random.uniform(0, 2 * math.pi)
self.directions[i][0] = math.sin(randomAngle)
self.directions[i][1] = math.cos(randomAngle)
def mutate(self):
mutationRate = 1
for i in range(self.size):
rand = random.random()
if rand < mutationRate:
dirAngle = math.acos(self.directions[i][1]) * (1.0 + random.random())
self.directions[i][0] = math.sin(dirAngle)
self.directions[i][1] = math.cos(dirAngle)
Population Class:
class Population(object):
def __init__(self, size, win):
self.bestDot = 0
self.fitnessSum = 0.0
self.win = win
self.size = size
self.dots = [Dot(win) for i in range(size)]
def show(self):
for i in range(self.size-1):
self.dots[i+1].show()
self.dots[0].show()
def updt(self):
for i in range(self.size):
self.dots[i].updt()
def calculateFitness(self):
for i in range(self.size):
self.dots[i].calculateFitness()
def allDotsDead(self):
for i in range(self.size):
if not self.dots[i].dead and not self.dots[i].reachGoal:
return False
return True
def naturalSelection(self):
newDots = [Dot(self.win) for i in range(self.size)]
self.setBestDot()
self.calculateFitnessSum()
newDots[0] = self.dots[self.bestDot].baby()
newDots[0].isBest = True
for i in range(self.size-1):
parent = self.selectParent()
newDots[i+1] = parent.baby()
print(newDots[1])
self.dots = newDots
def calculateFitnessSum(self):
self.fitnessSum = 0.0
for i in range(self.size):
self.fitnessSum += self.dots[i].fitness
print(self.fitnessSum)
def selectParent(self):
rand = random.uniform(0, self.fitnessSum)
runningSum = 0.0
for i in range(self.size):
runningSum += self.dots[i].fitness
if runningSum >= rand:
return self.dots[i]
return None
def mutate(self):
for i in range(self.size):
if not self.dots[i].isBest:
self.dots[i].brain.mutate()
def setBestDot(self):
max = 0.0
maxIndex = 0
for i in range(len(self.dots)):
if self.dots[i].fitness > max:
max = self.dots[i].fitness
maxIndex = i
self.bestDot = maxIndex
Dot Class:
WIDTH, HEIGHT = 720, 640
GOAL = (WIDTH / 2, 50)
class Dot(object):
def __init__(self, win):
self.win = win
self.fitness = 0
self.reachGoal = False
self.dead = False
self.brain = Brain(200)
self.pos = [WIDTH / 2, HEIGHT - 50]
self.vel = [0, 0]
self.acc = [0, 0]
self.isBest = False
def move(self):
if len(self.brain.directions) > self.brain.step:
self.acc = self.brain.directions[self.brain.step]
self.brain.step += 1
else:
self.dead = True
for i in range(len(self.vel)): self.vel[i] += self.acc[i]
if self.vel[0] >= 5: self.vel[0] = 5
if self.vel[1] >= 5: self.vel[1] = 5
for i in range(len(self.pos)): self.pos[i] += self.vel[i]
def show(self):
if self.isBest:
pygame.draw.circle(self.win, (0, 255, 0), self.pos, 4)
else:
pygame.draw.circle(self.win, (200, 100, 0), self.pos, 2)
def updt(self):
if not self.dead and not self.reachGoal:
self.move()
if self.pos[0] < 4 or self.pos[1] < 4 or self.pos[0] > WIDTH - 4 or self.pos[1] > HEIGHT - 4:
self.dead = True
elif math.hypot(self.pos[0] - GOAL[0], self.pos[1] - GOAL[1]) < 5:
self.reachGoal = True
def calculateFitness(self):
distToGoal = math.hypot(self.pos[0] - GOAL[0], self.pos[1] - GOAL[1])
self.fitness = 1.0 / 16.0 + 10000.0 / (distToGoal * distToGoal)
def baby(self):
baby = Dot(self.win)
baby.brain.directions = self.brain.directions
return baby
The problem is that i especify that the best dot dont mutate, but its mutate or change to a worst dot, also, i dont know why but in every generetion less dots spawn(or dots has exactly the same brain a dont mutate not even a litle), the mutation rate is in 100% but in every run there are less and less dots.
Here screenshots of the first and 5th generation: https://imgur.com/a/675Jxit
Also, if someone has some genetic algorithm in python to take as a model it would help.

I did not try the project you mentioned. You may try PyGAD, a Python 3 library for building the genetic algorithm and training machine learning algorithms. It is open-source where you can find the code at GitHub.
It is simple to use which allows you to control the crossover, mutation, and parent selection operators in an easy way. You can also control many parameters of the genetic algorithm using PyGAD.
PyGAD also works with a user-defined fitness function so you can adapt it to a wide-range of problems.
After installing PyGAD (pip install pygad), here is a simple example to get started that tries to find the best values for W1, W2, and W3 that satisfies the following equation:
44 = 4xW_1 - 2xW_2 + 1.2xW_3
import pygad
import numpy
function_inputs = [4,-2, 1.2]
desired_output = 44
def fitness_func(solution, solution_idx):
output = numpy.sum(solution*function_inputs)
fitness = 1.0 / (numpy.abs(output - desired_output) + 0.000001)
return fitness
def on_generation(ga_instance):
print(ga_instance.population)
ga_instance = pygad.GA(num_generations=50,
num_parents_mating=2,
fitness_func=fitness_func,
num_genes=3,
sol_per_pop=5)
ga_instance.run()
ga_instance.plot_result()
solution, solution_fitness, _ = ga_instance.best_solution()
print("Parameters of the best solution : {solution}".format(solution=solution))
print("Fitness value of the best solution = {solution_fitness}".format(solution_fitness=solution_fitness))

Related

Modify the Quadtree algorithm's criteria to create nodes/ children based on difference in pixel ID values, instead of number of points in each node

Quadtree code are readily available on Github. However most of the Quadtrees (collision detection) work on following criteria:
if No. Points in each Node > Capacity
Divide the node into Four parts
else
Do Not divide further
I am instead looking to apply the following logic. Id there are more than one Instances in a node, divide it further into four until each node has only one instance.
if No. of Instance in each Node > 1
Divide the node into Four parts
else
Do Not Divide further
I already have an image with each pixel labelled as per the instance. For example
Instance Value
Background 0
Chair 1
Table 2
Plant 3
Teddy Bear 4
So with all the pixels labelled, I have an image that looks like this
So if we read this image into an array, each (x,y) coordinate has a value associated.
After quadtree is applied, this is what I would like the quadtree to do to my image. As an example only a portion of quadtree applied on chair is shown for demo
So how do I modify the Quadtree criteria in the following code, copied from Github to achieve what I am looking for?
import numpy as np
import math
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def distanceToCenter(self, center):
return math.sqrt((center.x-self.x)**2 + (center.y-self.y)**2)
class Rectangle:
def __init__(self, center, width, height):
self.center = center
self.width = width
self.height = height
self.west = center.x - width
self.east = center.x + width
self.north = center.y - height
self.south = center.y + height
def containsPoint(self, point):
return (self.west <= point.x < self.east and
self.north <= point.y < self.south)
def intersects(self, range):
return not (range.west > self.east or
range.east < self.west or
range.north > self.south or
range.south < self.north)
def draw(self, ax, c='k', lw=1, **kwargs):
x1, y1 = self.west, self.north
x2, y2 = self.east, self.south
ax.plot([x1,x2,x2,x1,x1], [y1,y1,y2,y2,y1], c=c, lw=lw, **kwargs)
class QuadTree:
def __init__(self, boundary, capacity = 4):
self.boundary = boundary
self.capacity = capacity
self.points = []
self.divided = False
def insert(self, point):
# if the point is in the range of current quadTree
if not self.boundary.containsPoint(point):
return False
# if has not reached capcaity
if len(self.points) < self.capacity:
self.points.append(point)
return True
if not self.divided:
self.divide()
if self.nw.insert(point):
return True
elif self.ne.insert(point):
return True
elif self.sw.insert(point):
return True
elif self.se.insert(point):
return True
return False
def queryRange(self, range):
found_points = []
if not self.boundary.intersects(range):
return []
for point in self.points:
if range.containsPoint(point):
found_points.append(point)
if self.divided:
found_points.extend(self.nw.queryRange(range))
found_points.extend(self.ne.queryRange(range))
found_points.extend(self.sw.queryRange(range))
found_points.extend(self.se.queryRange(range))
return found_points
def queryRadius(self, range, center):
found_points = []
if not self.boundary.intersects(range):
return []
for point in self.points:
if range.containsPoint(point) and point.distanceToCenter(center) <= range.width:
found_points.append(point)
if self.divided:
found_points.extend(self.nw.queryRadius(range, center))
found_points.extend(self.ne.queryRadius(range, center))
found_points.extend(self.sw.queryRadius(range, center))
found_points.extend(self.se.queryRadius(range, center))
return found_points
def divide(self):
center_x = self.boundary.center.x
center_y = self.boundary.center.y
new_width = self.boundary.width / 2
new_height = self.boundary.height / 2
nw = Rectangle(Point(center_x - new_width, center_y - new_height), new_width, new_height)
self.nw = QuadTree(nw)
ne = Rectangle(Point(center_x + new_width, center_y - new_height), new_width, new_height)
self.ne = QuadTree(ne)
sw = Rectangle(Point(center_x - new_width, center_y + new_height), new_width, new_height)
self.sw = QuadTree(sw)
se = Rectangle(Point(center_x + new_width, center_y + new_height), new_width, new_height)
self.se = QuadTree(se)
self.divided = True
def __len__(self):
count = len(self.points)
if self.divided:
count += len(self.nw) + len(self.ne) + len(self.sw) + len(self.se)
return count
def draw(self, ax):
self.boundary.draw(ax)
if self.divided:
self.nw.draw(ax)
self.ne.draw(ax)
self.se.draw(ax)
self.sw.draw(ax)

Animate algorithm

I want to visualize an algorithm (Graham scan) in python with tkinter.
I want to animate the algorithm and I am stuck.
I basically want to draw and delete lines but I don't understand canvas.after() well enough to make it work.
draw_line() returns the line object but when I call it in canvas.after(..., draw_line, ...) I don't see a way to get the return value or how to call another canvas.after() to change the color/delete that line if the function draw_line() hasn't been called yet because of the delay.
Thanks in advance.
from tkinter import *
import math
import random
class Point:
def __init__(self, _x, _y, _a=0):
self.x = _x
self.y = _y
self.angle = _a
def get_co(self):
return self.x, self.y
def draw_hull(hull):
for i in range(len(hull) - 1):
canvas.create_line(hull[i][0], hull[i][1], hull[i + 1][0], hull[i + 1][1], fill="red", width=2)
def draw_line(p1, p2, color="yellow"):
return canvas.create_line(p1.x, p1.y, p2.x, p2.y, fill=color, width=2)
def convex_hull(list_points):
# find bottom point
bottom_point = Point(math.inf, math.inf)
for point in list_points:
if point[1] < bottom_point.y:
bottom_point = Point(point[0], point[1])
# calculate angles between the bottom point and the other points
points = []
for point in list_points:
if point != bottom_point.get_co():
new_point = Point(point[0], point[1])
angle = calculate_angle(bottom_point, new_point)
new_point.angle = angle
points.append(new_point)
# sort the points by angle
swaps = None
while swaps != 0:
swaps = 0
for i in range(len(points) - 1):
point1 = points[i]
point2 = points[i + 1]
if point1.angle > point2.angle:
points[i], points[i + 1] = points[i + 1], points[i]
swaps += 1
# go through the points and add them to the convex hull
# if the angle between 3 points ever exeeds 180 degrees, discard the middle point
hull = [bottom_point, points[0]]
i = 1
while i < len(points):
####### DRAW LINE #######
canvas.after(i*500, draw_line, hull[-2], hull[-1])
##############
# check angle
angle = calculate_angle(hull[-2], hull[-1], points[i])
if angle == -1:
########## DELETE LINE ##########
# change color of line to red and delete it a bit later
# canvas.itemconfig(line, fill="red")
# canvas.after(i*500+250, canvas.delete, line)
####################
# pop the point of the stack
hull.pop()
else:
########## CHANGE COLOR OF LINE ##########
# change color of line to green
# canvas.itemconfig(line, fill="green")
####################
# move to the next point
hull.append(points[i])
i += 1
# add bottom point again for loop
hull.append(bottom_point)
# give easy return list (with coordinate-tupels not class objects)
output = []
for point in hull:
output.append(point.get_co())
return output
def calculate_angle(point1, point2, point3=None):
if point3 is None:
if point2.x - point1.x == 0:
return 90
elif point2.x - point1.x > 0:
return math.degrees(math.atan((point2.y - point1.y)/(point2.x - point1.x)))
else:
return 180 - math.degrees(math.atan((point2.y - point1.y)/(point1.x - point2.x)))
else:
v1 = Point(point1.x - point2.x, point1.y - point2.y)
v2 = Point(point3.x - point2.x, point3.y - point2.y)
det = (v1.x * v2.y) - (v2.x * v1.y)
if det < 0:
return 1
else:
return -1
window = Tk()
window.geometry("1000x600")
canvas = Canvas(window, width=1000, height=600)
canvas.pack()
POINTSIZE = 2
points = []
for i in range(100):
x = random.randint(50, 950)
y = random.randint(50, 550)
points.append((x, y))
canvas.create_oval(x - POINTSIZE, y - POINTSIZE, x + POINTSIZE, y + POINTSIZE, fill="black")
hull = convex_hull(points)
# draw_hull(hull)
window.mainloop()
If you have questions about the code, let me know. Because I dont know where to start to explain, since I made major changes to your code.
Anyway, I would be glad if you share your code again, once you are done with, on CodeReview and please do let me know. Because it was fun to work with and your code seems incomplete to me.
Happy Coding:
import tkinter as tk
import random
import math
class Point:
def __init__(self, _x, _y, _a=0):
self.x = _x
self.y = _y
self.angle = _a
return None
def get_co(self):
return self.x, self.y
class Window(tk.Tk):
def __init__(self,_w,_h):
super().__init__()
self.POINTSIZE = 2
self.points = []
self.swaps = None
self.count = 1
self.delay = 200
self.title('Graham scan simulation')
self.toolbar = tk.Frame(self,background='grey')
self.refresh_button = tk.Button(self.toolbar,text='Refresh',
command=self.refresh)
self.start_button = tk.Button(self.toolbar,text='Start',
command = self.convex_hull)
self.canvas = tk.Canvas(self,width=_w,height=_h)
self.toolbar.pack(side=tk.TOP,fill=tk.BOTH,expand=True)
self.refresh_button.pack(side=tk.LEFT)
self.start_button.pack(side=tk.LEFT)
self.canvas.pack(side=tk.BOTTOM,fill=tk.BOTH,expand=True)
def generate_points(self):
for point_instance in self.points:
yield point_instance
def find_bottom_point(self):
bottom_point = Point(math.inf,math.inf)
for point in self.generate_points():
if point.y < bottom_point.y:
bottom_point = point
return bottom_point
def calculate_angle(self,point1, point2):
if point2.x - point1.x == 0:
return 90
elif point2.x - point1.x > 0:
return math.degrees(math.atan((point2.y - point1.y)/(point2.x - point1.x)))
else:
return 180 - math.degrees(math.atan((point2.y - point1.y)/(point1.x - point2.x)))
def calculate_angels_by_bottom_point(self,bottom_point):
for point in self.generate_points():
if point != bottom_point:
angle = self.calculate_angle(bottom_point,point)
point.angle = angle
def sort_points(self,event_variable):
if self.swaps != 0:
self.swaps = 0
for i in range(len(self.points)-1):
point1 = self.points[i]
point2 = self.points[i + 1]
if point1.angle > point2.angle:
self.points[i], self.points[i + 1] = self.points[i + 1], self.points[i]
self.swaps += 1
if self.swaps == 0:
event_variable.set(1)
self.after(20,self.sort_points,event_variable)
def check_angle(self,point1,point2,point3):
v1 = Point(point1.x - point2.x, point1.y - point2.y)
v2 = Point(point3.x - point2.x, point3.y - point2.y)
det = (v1.x * v2.y) - (v2.x * v1.y)
if det < 0:
return 1
else:
return -1
def draw_line(self,p1,p2,color='yellow'):
return self.canvas.create_line(p1.x,p1.y, p2.x,p2.y, fill='yellow',tags='line')
def clear_red_lines(self,p1,p2):
shapes = self.canvas.find_withtag('line')
for shape in shapes:
if self.canvas.itemcget(shape,'fill') == 'red':
coords = self.canvas.coords(shape)
overlapped = self.canvas.find_overlapping(*coords)
for i in overlapped:
coords2 = self.canvas.coords(i)
if coords == coords2:
self.canvas.delete(i)
self.canvas.delete(shape)
def animated_draw(self,hull):
if self.count != len(self.points):
line = self.draw_line(hull[-2],hull[-1])
check_mark = self.check_angle(hull[-2],hull[-1],self.points[self.count])
if check_mark == -1:
self.canvas.itemconfig(line,fill='red')
self.after(self.delay-100,lambda:self.clear_red_lines(hull[-2],hull[-1]))
hull.pop()
else:
self.canvas.itemconfig(line,fill='green')
hull.append(self.points[self.count])
self.count += 1
self.after(self.delay,self.animated_draw,hull)
def convex_hull(self):
bottom_point = self.find_bottom_point()
self.calculate_angels_by_bottom_point(bottom_point)
event_variable = tk.IntVar(self,value=0)
self.sort_points(event_variable)
self.wait_variable(event_variable)
self.points.pop(0)
self.animated_draw(hull = [bottom_point, self.points[0]])
def generate_listpoints(self,_amount):
'''using a generator for memory purpose'''
for i in range(_amount):
x = random.randint(50, 950)
y = random.randint(50, 550)
yield x,y
def refresh(self):
self.swaps = None
self.count = 1
self.points= []
self.populate_canvas()
def populate_canvas(self):
self.canvas.delete('all')
for x,y in self.generate_listpoints(100):
self.points.append(Point(x, y))#instead of creating throwing instances away.
self.canvas.create_oval(x - self.POINTSIZE,
y - self.POINTSIZE,
x + self.POINTSIZE,
y + self.POINTSIZE,
fill="black")
root = Window(1000,600)
root.mainloop()

Genetic algorithm for "smart dots" in python doesn't work

For the past few days I've been trying to implement the so called "Smart dots" game. I first saw it on Code Bullet youtube channel: https://www.youtube.com/watch?v=BOZfhUcNiqk. Unfortunately it was coded in Processing language, while the only language I barely know is Python. I finished my python version of the game but some bugs have appeared.
The problem is that on the second generation dots that are selected to be the best just stop moving almost instantly. I think that it has something to do with me being bad at OOP and copying the Brain class wrong. Steps(which i use for movement) Jump from zero(that is set at the beginning) to max value(200) at the first or second looping of the main loop. But the problems don't stop there. At the next generation, when i try to set brain step to zero, it just breaks with:
AttributeError: 'NoneType' object has no attribute 'brain'
I tried setting up the new brain manually but i still get the same errors. If anyone who already made this or has time to spare can help me with this error or even project i would appreciate it.
I know the code has a lot of unused things but that's just the product of me trying to fix it
:(
The commented out code is some of the old code i used.
main2.py(main loop):
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(handles all the functions and classes):
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
'''
The NoneType error is caused by the get_parent method. It searches for a child dot, but has no return value if the search fails (same effect as return None). This code will get past that error
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

AttributeError: 'area' object has no attribute 'radius'

I'm new baby in Python and having the following error can you guys look into it........................................
AttributeError: 'area' object has no attribute 'radius'. So, I'm facing error in any cases. Thank for help
import math, random
class area:
def __init__(self, radius, length, breath, height, base):
if radius == 0 and breath != 0:
self.radius = random.uniform(1.1, 9.5)
self.length = random.uniform(10.5, 15.5)
self.breath = random.uniform(15, 20)
self.height = random.uniform(20, 25)
self.base = random.uniform(26, 32)
elif length == 0 and heigh != 0:
self.radius = random.uniform(1.1, 9.5)
self.length = length
self.breath = random.uniform(15, 20)
self.height = height
self.base = base
elif height == 0 and base != 0:
self.radius = radius
self.length = random.uniform(1.1, 9.5)
self.breath = breath
self.height = random.uniform(1.1, 9.5)
self.base = base
def areaofcircle(self):
return (self.radius ** 2) * math.pi
def areaoftriangl(self):
return 0.5 * (self.height) * (self.base)
def areaofrectangle(self):
return (self.length) * (self.breath)
areas = []
for i in range(0, 10):
v = area(1, 3, 5, 0, 0)
areas.append(v)
for v in areas:
print(
"Area of Circle:",
v.areaofcircle(),
"Area of Triangle:",
v.areaoftriangl(),
"Area of Rectangle:",
v.areaofrectangle(),
)
You may need to remove radius from this function arguments
def areaofcircle(self, radius):
return (self.radius ** 2) * math.pi
to be:
def areaofcircle(self):
return (self.radius ** 2) * math.pi
By defining the function as
def areaofcircle(self, radius)
Your function expect two inputs, but in your case you only give one. As far as I understand 'radius' is a datafield of the area class. Therefore, you can call it with "self.radius". In this case if you remove the radius parameter from the function, it should all work out.
def areaofcircle(self)

Alpha Beta Checkers- Same player always wins

I am implementing a simple checkers AI using alpha-beta (minimax) search and have the implementation complete. I have two players, 1 and 2, but regardless of what depth I am using for my search (even if 1's depth > 2's depth), player 2 seems to win. I cannot seem to spot what I'm doing wrong. Do you have any thoughts as to what may be causing this? I am unsure if my implementation of alpha-beta search is entirely correct or if I am misunderstanding something about it. The game does run properly, just the results are not as expected. Please let me know if I can clarify this in any way. Your help is much appreciated!I have stripped away the GUI for purposes of this question, but it shouldn't affect anything. Thanks so much!
Board is a class that has a board attribute which is an 8x8 array of ints.
0 empty space
1 white piece
2 red piece
3 white king
4 red king
class Player:
def __init__(self, id, depth):
self.id = id
self.depth = depth
def board_eval(self, board):
if len(board.get_moves(self.id)) == 0:
return float('inf')*-1
else:
red = 0
redK = 0
white = 0
whiteK = 0
for r in range(len(board.board[0])):
for c in range(len(board.board[0])):
if board.board[r][c]>0:
if board.board[r][c]==1:
white+=1
elif board.board[r][c]==2:
red+=1
elif board.board[r][c]==3:
whiteK+=1
elif board.board[r][c]==4:
redK+=1
if self.id == 1:
return white+whiteK-red-redK
else:
return red+redK-white-whiteK
def minimax (self, board, depth, alpha, beta, player):
board_value = self.board_eval(board)
if depth == 0 or board_value == float('inf') or board_value == float('inf')*-1:
return board_value
if self.id == player:
for poss_board in board.get_moves(player):
alpha = max(alpha, self.minimax(poss_board, depth - 1, alpha, beta, (player%2)+1))
if (alpha >= beta):
break
return alpha
else:
for poss_board in board.get_moves(player): #TODO: should this be the other player? pretty sure no
beta = min(beta, self.minimax(poss_board, depth - 1, alpha, beta, (player%2)+1))
if (beta <= alpha):
break
return beta
def update_board(self, board):
best_move = None
best_score = float('inf') * -1
for poss_move in board.get_moves(self.id):
alpha = self.minimax(poss_move, self.depth-1, best_score, float('inf'), (self.id%2)+1)
if best_move is None or alpha > best_score:
best_move = poss_move
best_score = alpha
elif alpha == best_score and random.random() <= 0.3: #arbitrary randomness if multiple best moves
best_move = poss_move
return best_move
class Game:
def __init__(self):
self.board = Board()
self.p1 = Player(1, 4) #id, depth
self.p2 = Player(2, 2)
self.height=800
self.width=800
self.win= GraphWin("Checkerboard", self.width, self.height)
self.lag_win = GraphWin("Prev Board", self.width, self.height)
self.lag_board = copy.deepcopy(self.board)
self.cell_size = 50 # Height and width of checkerboard squares.
self.offset_x = (self.width - 8*self.cell_size) / 2
self.offset_y = (self.height - 8*self.cell_size) / 2
def play(self):
while True:
self.board = self.p1.update_board(self.board)
if self.board is None: #print("Game over, player 2 wins\n")
return 2
self.board = self.p2.update_board(self.board)
if self.board is None: #print("Game over, player 1 wins\n")
return 1
game = Game()
winner = game.play()
Your board_eval appears to be returning a score relative to the player, but the minimax part of the code seems to be assuming an absolute score. What happens if you eliminate that if in board_eval and just return white+whiteK-red-redK?

Categories