-
Notifications
You must be signed in to change notification settings - Fork 0
/
game.py
118 lines (107 loc) · 4.36 KB
/
game.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
from typing import Dict
import numpy as np
from brain import Brain
from cell import Cell
from coord import Coord
from evolution import Evolution
from grid import Grid
from snake import Snake
class Game:
def __init__(self, width: int, height: int, seed: int, generations: int,
population: int, selection: float, crossover: float,
mutation: float, create=True):
self.seed = seed
self.points = 0
self.current_id = 0
self.generation = 0
self.generations = generations
self.population = population
self.selection = selection
self.crossover = crossover
self.mutation = mutation
self.best_fitness = 0
self.avg_fitness = 0
self.is_running = True
self.random = np.random.default_rng(seed)
self.snakes = dict() # type: Dict[int, Snake]
self.grid = Grid(width, height)
self.cherry = self.grid.get_next_cherry(self.random)
self.initial_pos = self.random.choice(self.grid.get_free_cells())
self.create = create
self.create_all_snakes()
def run_snake(self, snake: Snake):
vision = self.grid.get_vision(snake.direction, snake.head, self.cherry)
tail = snake.run(vision) # type: Coord
head = self.grid.get(snake.head) # type: Cell
if head is None or head.is_wall() or head.has_body or snake.is_dead:
if not snake.is_dead:
snake.is_dead = True
snake.calculate_fitness()
else:
head.has_body = True
if tail is not None:
self.grid.get(tail).has_body = False
if head.has_cherry:
self.eat_cherry(snake)
def print_score_by_snake(self, snake: Snake):
print(f'{self.generation}> {snake}'
f'Best: {self.best_fitness:12.2f} '
f'AVG: {self.avg_fitness / (self.current_id + 1):12.2f}')
def run(self, save=False, save_ann=False):
snake = self.snakes[self.current_id]
self.run_snake(snake)
if snake.is_dead:
if save:
snake.save(save_ann)
self.avg_fitness += snake.fitness
self.print_score_by_snake(snake)
if snake.fitness > self.best_fitness:
self.best_fitness = snake.fitness
self.current_id += 1
if self.current_id == self.population:
self.generation += 1
if self.generation == self.generations:
self.is_running = False
else:
self.next_generation()
self.reset_game()
def create_all_snakes(self):
if self.create:
for snk_id in range(self.population):
seed = self.seed * self.population + snk_id
brain = Brain(seed, 0, 2, (2 ** 6) * 2)
snake = Snake(snk_id, self.initial_pos, brain)
self.snakes[snk_id] = snake
self.grid.get(self.initial_pos).has_body = True
else:
for snk_id in range(self.population):
snake = Snake.load(0, snk_id)
self.snakes[snk_id] = snake
def eat_cherry(self, snake: Snake):
self.grid.get(snake.head).has_cherry = False
snake.grow()
self.points += 1
self.cherry = self.grid.get_next_cherry(self.random)
def reset_game(self):
# self.random = np.random.default_rng(self.seed)
self.points = 0
self.grid = Grid(self.grid.width, self.grid.height)
self.cherry = self.grid.get_next_cherry(self.random)
self.grid.get(self.initial_pos).has_body = True
def next_generation(self):
self.current_id = 0
self.avg_fitness = 0
if self.create:
brains = [snake.brain for snake in self.snakes.values()]
generation = Evolution(brains, self.selection, self.crossover,
self.mutation, self.seed, self.generation)
brains = generation.evolve()
self.snakes = dict()
for snk_id in range(self.population):
snake = Snake(snk_id, self.initial_pos, brains[snk_id])
self.snakes[snk_id] = snake
else:
for snk_id in range(self.population):
snake = Snake.load(self.generation, snk_id)
self.snakes[snk_id] = snake
self.reset_game()