From d3ae11fbb14fe97c59726d2738c1ef355ae90e90 Mon Sep 17 00:00:00 2001 From: s452645 Date: Sun, 20 Jun 2021 11:42:43 +0200 Subject: [PATCH] faster GA --- .../genetic_algorithm/genetic_algorithm.py | 2 +- algorithms/learn/genetic_algorithm/helpers.py | 12 +++---- algorithms/learn/genetic_algorithm/new_ga.py | 21 ++--------- game.py | 1 + main.py | 3 ++ minefield.py | 36 ++++++++++++------- project_constants.py | 2 +- resources/minefields/fourthmap.json | 20 +++++------ 8 files changed, 46 insertions(+), 51 deletions(-) diff --git a/algorithms/learn/genetic_algorithm/genetic_algorithm.py b/algorithms/learn/genetic_algorithm/genetic_algorithm.py index 5dd8f9e..be13e8a 100644 --- a/algorithms/learn/genetic_algorithm/genetic_algorithm.py +++ b/algorithms/learn/genetic_algorithm/genetic_algorithm.py @@ -131,7 +131,7 @@ if __name__ == "__main__": # create new minefield instance import os from minefield import Minefield - minefield = Minefield(os.path.join("..", "..", "..", "resources", "minefields", "fifthmap.json")) + minefield = Minefield(os.path.join("..", "..", "..", "resources", "minefields", "fourthmap.json")) # perform the genetic algorithm search best, score = genetic_algorithm(minefield, helpers.get_score, n_iter, n_pop, r_cross, r_mut) diff --git a/algorithms/learn/genetic_algorithm/helpers.py b/algorithms/learn/genetic_algorithm/helpers.py index dcba1fd..2a833ca 100644 --- a/algorithms/learn/genetic_algorithm/helpers.py +++ b/algorithms/learn/genetic_algorithm/helpers.py @@ -1,3 +1,5 @@ +import time + from minefield import Minefield import project_constants as const @@ -14,7 +16,7 @@ def possible_states(row, column): possible_states.append(State(row + 1, column, Direction.UP)) if Minefield.is_valid_move(row - 1, column): - possible_states.append(State(row + 1, column, Direction.DOWN)) + possible_states.append(State(row - 1, column, Direction.DOWN)) if Minefield.is_valid_move(row, column + 1): possible_states.append(State(row, column + 1, Direction.LEFT)) @@ -70,7 +72,7 @@ def get_score(minefield, speciment, table=None): initial_state = State(0, 0, Direction.RIGHT) if table is not None: - for el_index in range(len(speciment) - 1): + for el_index in range(len(speciment)): end_state, cost = table[(initial_state.row, initial_state.column)] \ [(speciment[el_index][0], speciment[el_index][1])] \ @@ -81,13 +83,11 @@ def get_score(minefield, speciment, table=None): 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: - cost += 200 + score += 200 mine.active = False - for _ in range(cost): - minefield.next_turn() - + minefield.next_turn(n_turns=cost) score += cost score += 200 * minefield.explosions diff --git a/algorithms/learn/genetic_algorithm/new_ga.py b/algorithms/learn/genetic_algorithm/new_ga.py index bef5ee9..6d198bd 100644 --- a/algorithms/learn/genetic_algorithm/new_ga.py +++ b/algorithms/learn/genetic_algorithm/new_ga.py @@ -23,6 +23,7 @@ class Fitness: def routeFitness(self): if self.fitness == 0: self.fitness = 1000 / float(self.routeDistance()) + return self.fitness @@ -42,10 +43,8 @@ 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) @@ -142,23 +141,16 @@ 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] @@ -171,17 +163,8 @@ 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")) + gl_minefield = Minefield(os.path.join("..", "..", "..", "resources", "minefields", "fourthmap.json")) genetic_algorithm(minefield=gl_minefield, population=helpers.get_mines_coords(gl_minefield), diff --git a/game.py b/game.py index 40627de..f279526 100644 --- a/game.py +++ b/game.py @@ -120,6 +120,7 @@ class Game: def revert_minefield_turn(self): self.minefield.turn -= 1 + self.minefield.points -= 1 # returns turn number def get_turn_number(self): diff --git a/main.py b/main.py index 9477bf1..80ae097 100644 --- a/main.py +++ b/main.py @@ -158,6 +158,9 @@ def main(): # reset values after the game loop if game.agent_made_all_actions(action_sequence): + if genetics: + game.minefield.points -= 1 + # clean up after game loop game.agent_take_last_action() game.cleanup_after_game_loop() diff --git a/minefield.py b/minefield.py index 2a7bde3..cc590da 100644 --- a/minefield.py +++ b/minefield.py @@ -37,22 +37,20 @@ class Minefield: predecessor = self.matrix[predecessor_row][predecessor_column].mine self.matrix[successor_row][successor_column].mine.predecessor = predecessor - def next_turn(self): - self.turn += 1 - self.points += 1 + self.time_mines = self._get_time_mines() - for row in range(const.V_GRID_VER_TILES): - for column in range(const.V_GRID_VER_TILES): - mine = self.matrix[row][column].mine + def next_turn(self, n_turns=1): + self.turn += n_turns + self.points += n_turns - if mine is not None and isinstance(mine, TimeMine): - mine.timer = max(0, mine.starting_time - int(self.turn)) + for mine in self.time_mines: + mine.timer = max(0, mine.starting_time - int(self.turn)) - if mine.timer == 0 and mine.active: - # TODO: BOOM - self.explosions += 1 - self.points += const.EXPLOSION_PENALTY - mine.active = False + 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): mines = list() @@ -96,3 +94,15 @@ class Minefield: def __copy__(self): copy = Minefield(self.json_path) return copy + + def _get_time_mines(self): + time_mines = list() + + for row in range(const.V_GRID_VER_TILES): + for column in range(const.V_GRID_VER_TILES): + mine = self.matrix[row][column].mine + + if mine is not None and isinstance(mine, TimeMine): + time_mines.append(mine) + + return time_mines diff --git a/project_constants.py b/project_constants.py index 91666b4..cca742a 100644 --- a/project_constants.py +++ b/project_constants.py @@ -164,6 +164,6 @@ HIGHLIGHT.set_alpha(100) # ==== MAPS ==== # # ============== # -MAP_RANDOM_10x10 = os.path.join("resources", "minefields", "fifthmap.json") +MAP_RANDOM_10x10 = os.path.join("resources", "minefields", "fourthmap.json") diff --git a/resources/minefields/fourthmap.json b/resources/minefields/fourthmap.json index 41ec34c..7f12846 100644 --- a/resources/minefields/fourthmap.json +++ b/resources/minefields/fourthmap.json @@ -14,8 +14,7 @@ "0,3": { "terrain": "GRASS", "mine": { - "mine_type": "chained", - "predecessor": null + "mine_type": "standard" } }, "0,4": { @@ -41,7 +40,7 @@ "terrain": "MUD", "mine": { "mine_type": "chained", - "predecessor": "0,3" + "predecessor": "0,4" } }, "0,9": { @@ -69,7 +68,7 @@ "terrain": "GRASS", "mine": { "mine_type": "chained", - "predecessor": null + "predecessor": "3,3" } }, "1,4": { @@ -165,7 +164,7 @@ "terrain": "MUD", "mine": { "mine_type": "chained", - "predecessor": "1,3" + "predecessor": null } }, "3,4": { @@ -229,7 +228,7 @@ "terrain": "GRASS", "mine": { "mine_type": "chained", - "predecessor": null + "predecessor": "7,0" } }, "4,8": { @@ -247,8 +246,8 @@ "5,1": { "terrain": "GRASS", "mine": { - "mine_type": "chained", - "predecessor": "2,3" + "mine_type": "time", + "timer": 50 } }, "5,2": { @@ -262,8 +261,7 @@ "5,4": { "terrain": "GRASS", "mine": { - "mine_type": "chained", - "predecessor": "2,8" + "mine_type": "standard" } }, "5,5": { @@ -334,7 +332,7 @@ "terrain": "GRASS", "mine": { "mine_type": "chained", - "predecessor": "4,7" + "predecessor": null } }, "7,1": {