added 'score' textbox and 'GA iterations' input

This commit is contained in:
s452645 2021-06-20 09:41:38 +02:00
parent dfac987643
commit fcbd10684d
6 changed files with 104 additions and 39 deletions

View File

@ -72,25 +72,12 @@ def get_score(minefield, speciment, table=None):
if table is not None: if table is not None:
for el_index in range(len(speciment) - 1): for el_index in range(len(speciment) - 1):
if table[(initial_state.row, initial_state.column)] \
[(speciment[el_index][0], speciment[el_index][1])] \
[initial_state.direction]:
end_state, cost = table[(initial_state.row, initial_state.column)] \ end_state, cost = table[(initial_state.row, initial_state.column)] \
[(speciment[el_index][0], speciment[el_index][1])] \ [(speciment[el_index][0], speciment[el_index][1])] \
[initial_state.direction] [initial_state.direction]
initial_state = State(speciment[el_index][0], speciment[el_index][1], end_state.direction) initial_state = State(speciment[el_index][0], speciment[el_index][1], end_state.direction)
else:
action_sequence, _, cost = \
graphsearch(initial_state,
minefield,
target_type="mine",
tox=speciment[el_index][0],
toy=speciment[el_index][1],
with_data=True)
mine = minefield.matrix[speciment[el_index][0]][speciment[el_index][1]].mine mine = minefield.matrix[speciment[el_index][0]][speciment[el_index][1]].mine
if isinstance(mine, ChainedMine) and mine.predecessor is not None and mine.predecessor.active: if isinstance(mine, ChainedMine) and mine.predecessor is not None and mine.predecessor.active:

View File

@ -1,3 +1,4 @@
import time
import numpy as np, random, operator, pandas as pd import numpy as np, random, operator, pandas as pd
from algorithms.learn.genetic_algorithm import helpers from algorithms.learn.genetic_algorithm import helpers
@ -40,8 +41,12 @@ def initialPopulation(popSize, cityList):
def rankRoutes(population): def rankRoutes(population):
fitnessResults = {} fitnessResults = {}
timer_collect_results = Timer("Collect fitness results")
for i in range(0, len(population)): for i in range(0, len(population)):
fitnessResults[i] = Fitness(population[i]).routeFitness() fitnessResults[i] = Fitness(population[i]).routeFitness()
timer_collect_results.stop()
return sorted(fitnessResults.items(), key=operator.itemgetter(1), reverse=True) return sorted(fitnessResults.items(), key=operator.itemgetter(1), reverse=True)
@ -137,16 +142,24 @@ def genetic_algorithm(minefield, population, popSize, eliteSize, mutationRate, g
global gl_minefield, scores_table global gl_minefield, scores_table
gl_minefield = minefield gl_minefield = minefield
timer_scores_table = Timer("Create scores table")
scores_table = helpers.create_scores_table(gl_minefield) scores_table = helpers.create_scores_table(gl_minefield)
timer_scores_table.stop()
timer_initial_population = Timer("Init and rank population")
pop = initialPopulation(popSize, population) pop = initialPopulation(popSize, population)
scores = rankRoutes(pop) scores = rankRoutes(pop)
timer_initial_population.stop()
print("Initial score: " + str(1000 / scores[0][1])) print("Initial score: " + str(1000 / scores[0][1]))
for i in range(0, generations): for i in range(0, generations):
pop = nextGeneration(scores, pop, eliteSize, mutationRate) pop = nextGeneration(scores, pop, eliteSize, mutationRate)
timer_rank_generation = Timer("Rank generation")
scores = rankRoutes(pop) scores = rankRoutes(pop)
timer_rank_generation.stop()
print(f"Generation {i} best score: {str(1000 / scores[0][1])}") print(f"Generation {i} best score: {str(1000 / scores[0][1])}")
bestRouteIndex = scores[0][0] bestRouteIndex = scores[0][0]
bestRoute = pop[bestRouteIndex] bestRoute = pop[bestRouteIndex]
@ -158,6 +171,15 @@ def genetic_algorithm(minefield, population, popSize, eliteSize, mutationRate, g
return bestRoute return bestRoute
class Timer:
def __init__(self, name):
self.name = name
self.start_time = time.time()
def stop(self):
print(f"{self.name} took {time.time() - self.start_time} seconds.")
if __name__ == "__main__": if __name__ == "__main__":
gl_minefield = Minefield(os.path.join("..", "..", "..", "resources", "minefields", "fifthmap.json")) gl_minefield = Minefield(os.path.join("..", "..", "..", "resources", "minefields", "fifthmap.json"))

73
game.py
View File

@ -38,6 +38,7 @@ class Game:
self.action_delta_time = 0 self.action_delta_time = 0
self.genetic_sequence = None self.genetic_sequence = None
self.genetics_done = False
# declaring and initializing gui components # declaring and initializing gui components
# ui_component managers # ui_component managers
@ -45,12 +46,15 @@ class Game:
self.game_over_gui_components_manager = UiComponentsManager() self.game_over_gui_components_manager = UiComponentsManager()
# in game gui # in game gui
self.textbox_points = TextBox((0, 0), (0, 0))
self.input_box_row = InputBox((0, 0), (0, 0)) self.input_box_row = InputBox((0, 0), (0, 0))
self.input_box_column = InputBox((0, 0), (0, 0)) self.input_box_column = InputBox((0, 0), (0, 0))
self.button_auto = Button((0, 0), (0, 0)) self.button_auto = Button((0, 0), (0, 0))
self.button_genetic_algorithm = Button((0, 0), (0, 0))
self.button_random = Button((0, 0), (0, 0)) self.button_random = Button((0, 0), (0, 0))
self.button_ok = Button((0, 0), (0, 0)) self.button_ok = Button((0, 0), (0, 0))
self.button_genetic_algorithm = Button((0, 0), (0, 0))
self.input_box_generations = InputBox((0, 0), (0, 0))
# game over screen # game over screen
self.text_box_game_over = TextBox((0, 0), (0, 0)) self.text_box_game_over = TextBox((0, 0), (0, 0))
@ -109,6 +113,7 @@ class Game:
if self.millisecond_timer >= const.TURN_INTERVAL: if self.millisecond_timer >= const.TURN_INTERVAL:
self.turn += 1 self.turn += 1
self.minefield.next_turn() self.minefield.next_turn()
self.textbox_points.text = str(self.minefield.points)
# resetting timer # resetting timer
self.millisecond_timer %= const.TURN_INTERVAL self.millisecond_timer %= const.TURN_INTERVAL
@ -138,7 +143,9 @@ class Game:
else: else:
return False return False
def run_genetics(self): def run_genetics(self, generations=10):
print("Starting genetics algorithm...")
genetics_minefield = Minefield(const.MAP_RANDOM_10x10) genetics_minefield = Minefield(const.MAP_RANDOM_10x10)
sequence = \ sequence = \
@ -147,9 +154,10 @@ class Game:
popSize=100, popSize=100,
eliteSize=20, eliteSize=20,
mutationRate=0.01, mutationRate=0.01,
generations=15) generations=generations)
self.genetic_sequence = sequence self.genetic_sequence = sequence
self.genetics_done = True
def set_next_genetic_target(self): def set_next_genetic_target(self):
if any(self.genetic_sequence): if any(self.genetic_sequence):
@ -187,6 +195,10 @@ class Game:
row, column = position row, column = position
return self.minefield.matrix[row][column].mine return self.minefield.matrix[row][column].mine
def explosion(self, position):
# show explosion on position
self.minefield.points += const.EXPLOSION_PENALTY
# initializes attributes before game loop begins # initializes attributes before game loop begins
def initialize_before_game_loop(self): def initialize_before_game_loop(self):
self.agent_action = None self.agent_action = None
@ -258,8 +270,15 @@ class Game:
gui_y = const.SCREEN.get_height() / 2 - (2 * ib_height + 3 * bt_height + 50) / 2 gui_y = const.SCREEN.get_height() / 2 - (2 * ib_height + 3 * bt_height + 50) / 2
# creating in game gui components # creating in game gui components
self.textbox_points = TextBox(
position=(gui_x, gui_y - 134),
dimensions=(gui_width, ib_height - 10),
text="0",
box_color=(172, 220, 172)
)
self.input_box_row = InputBox( self.input_box_row = InputBox(
position=(gui_x, gui_y), position=(gui_x, gui_y - 50),
dimensions=(gui_width, ib_height), dimensions=(gui_width, ib_height),
text="row", text="row",
box_color=(100, 200, 100), box_color=(100, 200, 100),
@ -273,7 +292,7 @@ class Game:
) )
self.input_box_column = InputBox( self.input_box_column = InputBox(
position=(gui_x, gui_y + ib_height + 10), position=(gui_x, gui_y + ib_height - 40),
dimensions=(gui_width, ib_height), dimensions=(gui_width, ib_height),
text="column", text="column",
box_color=(100, 200, 100), box_color=(100, 200, 100),
@ -287,7 +306,7 @@ class Game:
) )
self.button_auto = Button( self.button_auto = Button(
position=(gui_x, gui_y + 2 * ib_height + 20), position=(gui_x, gui_y + 2 * ib_height - 30),
dimensions=(gui_width, bt_height), dimensions=(gui_width, bt_height),
text="auto", text="auto",
box_color=(100, 200, 100), box_color=(100, 200, 100),
@ -295,17 +314,8 @@ class Game:
outline_additional_pixel=True outline_additional_pixel=True
) )
self.button_genetic_algorithm = Button(
position=(gui_x, gui_y + 2 * ib_height + bt_height + 30),
dimensions=(gui_width, bt_height),
text="genetic",
box_color=(100, 200, 100),
outline_color=(80, 180, 80),
outline_additional_pixel=True
)
self.button_random = Button( self.button_random = Button(
position=(gui_x, gui_y + 2 * ib_height + 2 * bt_height + 40), position=(gui_x, gui_y + 2 * ib_height + 1 * bt_height - 20),
dimensions=(gui_width, bt_height), dimensions=(gui_width, bt_height),
text="random", text="random",
box_color=(100, 200, 100), box_color=(100, 200, 100),
@ -314,7 +324,7 @@ class Game:
) )
self.button_ok = Button( self.button_ok = Button(
position=(gui_x, gui_y + 2 * ib_height + 3 * bt_height + 50), position=(gui_x, gui_y + 2 * ib_height + 2 * bt_height - 10),
dimensions=(gui_width, bt_height), dimensions=(gui_width, bt_height),
text="ok", text="ok",
box_color=(100, 200, 100), box_color=(100, 200, 100),
@ -322,11 +332,37 @@ class Game:
outline_additional_pixel=True outline_additional_pixel=True
) )
self.button_genetic_algorithm = Button(
position=(gui_x, gui_y + 2 * ib_height + 4 * bt_height + 10),
dimensions=(gui_width, bt_height),
text="genetic",
box_color=(100, 200, 100),
outline_color=(80, 180, 80),
outline_additional_pixel=True
)
self.input_box_generations = InputBox(
position=(gui_x, gui_y + 2 * ib_height + 5 * bt_height + 20),
dimensions=(gui_width, ib_height),
text="iters",
user_input="10",
box_color=(100, 200, 100),
bottom_strip_color=(120, 220, 120),
inner_box_color=(120, 220, 120),
outline_color=(80, 180, 80),
outline_additional_pixel=True,
valid_input_characters="1234567890",
input_centered=True,
clear_input_on_click=True
)
gui_list = [ gui_list = [
self.textbox_points,
self.input_box_row, self.input_box_row,
self.input_box_column, self.input_box_column,
self.button_auto, self.button_auto,
self.button_genetic_algorithm, self.button_genetic_algorithm,
self.input_box_generations,
self.button_random, self.button_random,
self.button_ok self.button_ok
] ]
@ -372,3 +408,6 @@ class Game:
# heading either left or right # heading either left or right
else: else:
return self.agent.row, max(0, min(9, self.agent.column - self.agent.direction.value + 2)) return self.agent.row, max(0, min(9, self.agent.column - self.agent.direction.value + 2))
def get_input_generations(self):
return self.input_box_generations.get_input()

22
main.py
View File

@ -1,5 +1,7 @@
# libraries # libraries
import threading
import pygame import pygame
from pyglet.gl import * # for blocky textures from pyglet.gl import * # for blocky textures
# other files of this project # other files of this project
from game import Game from game import Game
@ -27,6 +29,7 @@ def main():
auto = False auto = False
genetics = False genetics = False
genetics_ready = False genetics_ready = False
genetics_in_progress = False
is_game_over = False is_game_over = False
# create and initialize_gui_components game instance # create and initialize_gui_components game instance
@ -66,7 +69,19 @@ def main():
# if genetics button is clocked then start genetic algorithm # if genetics button is clocked then start genetic algorithm
genetics = game.button_genetic_algorithm.is_clicked(pygame.mouse.get_pos(), events) genetics = game.button_genetic_algorithm.is_clicked(pygame.mouse.get_pos(), events)
if genetics: if genetics and not (genetics_in_progress or genetics_ready):
generations = game.get_input_generations()
genetics_in_progress = True
game.genetics_done = False
threading.Thread(target=game.run_genetics, args=(int(generations), )).start()
if genetics_in_progress:
genetics = True
genetics_ready = game.genetics_done
if genetics and genetics_ready:
genetics_in_progress = False
auto = True auto = True
# ========================== # # ========================== #
@ -76,10 +91,6 @@ def main():
# initializing action_sequence variable # initializing action_sequence variable
action_sequence = None action_sequence = None
if genetics and not genetics_ready:
game.run_genetics()
genetics_ready = True
# getting action sequence for agent # getting action sequence for agent
if auto and running: if auto and running:
in_menu = False in_menu = False
@ -157,6 +168,7 @@ def main():
if auto: if auto:
if not game.agent.defuse_a_mine(game.get_mine(game.goal)): if not game.agent.defuse_a_mine(game.get_mine(game.goal)):
print("BOOOOOOM\n\n") print("BOOOOOOM\n\n")
game.explosion(game.get_mine(game.goal))
# is_game_over = True # is_game_over = True
else: else:

View File

@ -8,6 +8,7 @@ class Minefield:
def __init__(self, json_path): def __init__(self, json_path):
self.turn = 0 self.turn = 0
self.explosions = 0 self.explosions = 0
self.points = 0
self.agent = ag.Agent(json_path) self.agent = ag.Agent(json_path)
self.json_path = json_path self.json_path = json_path
@ -38,6 +39,7 @@ class Minefield:
def next_turn(self): def next_turn(self):
self.turn += 1 self.turn += 1
self.points += 1
for row in range(const.V_GRID_VER_TILES): for row in range(const.V_GRID_VER_TILES):
for column in range(const.V_GRID_VER_TILES): for column in range(const.V_GRID_VER_TILES):
@ -49,6 +51,7 @@ class Minefield:
if mine.timer == 0 and mine.active: if mine.timer == 0 and mine.active:
# TODO: BOOM # TODO: BOOM
self.explosions += 1 self.explosions += 1
self.points += const.EXPLOSION_PENALTY
mine.active = False mine.active = False
def get_active_mines(self): def get_active_mines(self):

View File

@ -21,6 +21,8 @@ from ui.input_box import InputBox
V_NAME_OF_WINDOW = "MineFusion TM" V_NAME_OF_WINDOW = "MineFusion TM"
V_FPS = 60 V_FPS = 60
EXPLOSION_PENALTY = 200
ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
DIR_ASSETS = os.path.join(ROOT_DIR, "resources", "assets") DIR_ASSETS = os.path.join(ROOT_DIR, "resources", "assets")