faster GA
This commit is contained in:
parent
fcbd10684d
commit
d3ae11fbb1
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
1
game.py
1
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):
|
||||
|
3
main.py
3
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()
|
||||
|
36
minefield.py
36
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
|
||||
|
@ -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")
|
||||
|
||||
|
||||
|
@ -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": {
|
||||
|
Loading…
Reference in New Issue
Block a user