added 'score' textbox and 'GA iterations' input
This commit is contained in:
parent
dfac987643
commit
fcbd10684d
@ -72,25 +72,12 @@ def get_score(minefield, speciment, table=None):
|
||||
if table is not None:
|
||||
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)] \
|
||||
[(speciment[el_index][0], speciment[el_index][1])] \
|
||||
[initial_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
|
||||
|
||||
if isinstance(mine, ChainedMine) and mine.predecessor is not None and mine.predecessor.active:
|
||||
|
@ -1,3 +1,4 @@
|
||||
import time
|
||||
import numpy as np, random, operator, pandas as pd
|
||||
from algorithms.learn.genetic_algorithm import helpers
|
||||
|
||||
@ -40,8 +41,12 @@ def initialPopulation(popSize, cityList):
|
||||
|
||||
def rankRoutes(population):
|
||||
fitnessResults = {}
|
||||
|
||||
timer_collect_results = Timer("Collect fitness results")
|
||||
for i in range(0, len(population)):
|
||||
fitnessResults[i] = Fitness(population[i]).routeFitness()
|
||||
timer_collect_results.stop()
|
||||
|
||||
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
|
||||
gl_minefield = minefield
|
||||
|
||||
timer_scores_table = Timer("Create scores table")
|
||||
scores_table = helpers.create_scores_table(gl_minefield)
|
||||
timer_scores_table.stop()
|
||||
|
||||
timer_initial_population = Timer("Init and rank population")
|
||||
pop = initialPopulation(popSize, population)
|
||||
scores = rankRoutes(pop)
|
||||
timer_initial_population.stop()
|
||||
|
||||
print("Initial score: " + str(1000 / scores[0][1]))
|
||||
|
||||
for i in range(0, generations):
|
||||
pop = nextGeneration(scores, pop, eliteSize, mutationRate)
|
||||
|
||||
timer_rank_generation = Timer("Rank generation")
|
||||
scores = rankRoutes(pop)
|
||||
timer_rank_generation.stop()
|
||||
|
||||
print(f"Generation {i} best score: {str(1000 / scores[0][1])}")
|
||||
bestRouteIndex = scores[0][0]
|
||||
bestRoute = pop[bestRouteIndex]
|
||||
@ -158,6 +171,15 @@ def genetic_algorithm(minefield, population, popSize, eliteSize, mutationRate, g
|
||||
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__":
|
||||
gl_minefield = Minefield(os.path.join("..", "..", "..", "resources", "minefields", "fifthmap.json"))
|
||||
|
||||
|
73
game.py
73
game.py
@ -38,6 +38,7 @@ class Game:
|
||||
self.action_delta_time = 0
|
||||
|
||||
self.genetic_sequence = None
|
||||
self.genetics_done = False
|
||||
|
||||
# declaring and initializing gui components
|
||||
# ui_component managers
|
||||
@ -45,12 +46,15 @@ class Game:
|
||||
self.game_over_gui_components_manager = UiComponentsManager()
|
||||
|
||||
# in game gui
|
||||
self.textbox_points = TextBox((0, 0), (0, 0))
|
||||
|
||||
self.input_box_row = InputBox((0, 0), (0, 0))
|
||||
self.input_box_column = InputBox((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_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
|
||||
self.text_box_game_over = TextBox((0, 0), (0, 0))
|
||||
@ -109,6 +113,7 @@ class Game:
|
||||
if self.millisecond_timer >= const.TURN_INTERVAL:
|
||||
self.turn += 1
|
||||
self.minefield.next_turn()
|
||||
self.textbox_points.text = str(self.minefield.points)
|
||||
|
||||
# resetting timer
|
||||
self.millisecond_timer %= const.TURN_INTERVAL
|
||||
@ -138,7 +143,9 @@ class Game:
|
||||
else:
|
||||
return False
|
||||
|
||||
def run_genetics(self):
|
||||
def run_genetics(self, generations=10):
|
||||
print("Starting genetics algorithm...")
|
||||
|
||||
genetics_minefield = Minefield(const.MAP_RANDOM_10x10)
|
||||
|
||||
sequence = \
|
||||
@ -147,9 +154,10 @@ class Game:
|
||||
popSize=100,
|
||||
eliteSize=20,
|
||||
mutationRate=0.01,
|
||||
generations=15)
|
||||
generations=generations)
|
||||
|
||||
self.genetic_sequence = sequence
|
||||
self.genetics_done = True
|
||||
|
||||
def set_next_genetic_target(self):
|
||||
if any(self.genetic_sequence):
|
||||
@ -187,6 +195,10 @@ class Game:
|
||||
row, column = position
|
||||
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
|
||||
def initialize_before_game_loop(self):
|
||||
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
|
||||
|
||||
# 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(
|
||||
position=(gui_x, gui_y),
|
||||
position=(gui_x, gui_y - 50),
|
||||
dimensions=(gui_width, ib_height),
|
||||
text="row",
|
||||
box_color=(100, 200, 100),
|
||||
@ -273,7 +292,7 @@ class Game:
|
||||
)
|
||||
|
||||
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),
|
||||
text="column",
|
||||
box_color=(100, 200, 100),
|
||||
@ -287,7 +306,7 @@ class Game:
|
||||
)
|
||||
|
||||
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),
|
||||
text="auto",
|
||||
box_color=(100, 200, 100),
|
||||
@ -295,17 +314,8 @@ class Game:
|
||||
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(
|
||||
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),
|
||||
text="random",
|
||||
box_color=(100, 200, 100),
|
||||
@ -314,7 +324,7 @@ class Game:
|
||||
)
|
||||
|
||||
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),
|
||||
text="ok",
|
||||
box_color=(100, 200, 100),
|
||||
@ -322,11 +332,37 @@ class Game:
|
||||
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 = [
|
||||
self.textbox_points,
|
||||
self.input_box_row,
|
||||
self.input_box_column,
|
||||
self.button_auto,
|
||||
self.button_genetic_algorithm,
|
||||
self.input_box_generations,
|
||||
self.button_random,
|
||||
self.button_ok
|
||||
]
|
||||
@ -372,3 +408,6 @@ class Game:
|
||||
# heading either left or right
|
||||
else:
|
||||
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
22
main.py
@ -1,5 +1,7 @@
|
||||
# libraries
|
||||
import threading
|
||||
import pygame
|
||||
|
||||
from pyglet.gl import * # for blocky textures
|
||||
# other files of this project
|
||||
from game import Game
|
||||
@ -27,6 +29,7 @@ def main():
|
||||
auto = False
|
||||
genetics = False
|
||||
genetics_ready = False
|
||||
genetics_in_progress = False
|
||||
is_game_over = False
|
||||
|
||||
# create and initialize_gui_components game instance
|
||||
@ -66,7 +69,19 @@ def main():
|
||||
# if genetics button is clocked then start genetic algorithm
|
||||
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
|
||||
|
||||
# ========================== #
|
||||
@ -76,10 +91,6 @@ def main():
|
||||
# initializing action_sequence variable
|
||||
action_sequence = None
|
||||
|
||||
if genetics and not genetics_ready:
|
||||
game.run_genetics()
|
||||
genetics_ready = True
|
||||
|
||||
# getting action sequence for agent
|
||||
if auto and running:
|
||||
in_menu = False
|
||||
@ -157,6 +168,7 @@ def main():
|
||||
if auto:
|
||||
if not game.agent.defuse_a_mine(game.get_mine(game.goal)):
|
||||
print("BOOOOOOM\n\n")
|
||||
game.explosion(game.get_mine(game.goal))
|
||||
# is_game_over = True
|
||||
|
||||
else:
|
||||
|
@ -8,6 +8,7 @@ class Minefield:
|
||||
def __init__(self, json_path):
|
||||
self.turn = 0
|
||||
self.explosions = 0
|
||||
self.points = 0
|
||||
|
||||
self.agent = ag.Agent(json_path)
|
||||
self.json_path = json_path
|
||||
@ -38,6 +39,7 @@ class Minefield:
|
||||
|
||||
def next_turn(self):
|
||||
self.turn += 1
|
||||
self.points += 1
|
||||
|
||||
for row 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:
|
||||
# TODO: BOOM
|
||||
self.explosions += 1
|
||||
self.points += const.EXPLOSION_PENALTY
|
||||
mine.active = False
|
||||
|
||||
def get_active_mines(self):
|
||||
|
@ -21,6 +21,8 @@ from ui.input_box import InputBox
|
||||
V_NAME_OF_WINDOW = "MineFusion TM"
|
||||
V_FPS = 60
|
||||
|
||||
EXPLOSION_PENALTY = 200
|
||||
|
||||
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
DIR_ASSETS = os.path.join(ROOT_DIR, "resources", "assets")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user