faster GA

This commit is contained in:
s452645 2021-06-20 11:42:43 +02:00
parent fcbd10684d
commit d3ae11fbb1
8 changed files with 46 additions and 51 deletions

View File

@ -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)

View File

@ -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

View File

@ -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),

View File

@ -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):

View File

@ -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()

View File

@ -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

View File

@ -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")

View File

@ -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": {