def height(g_prec, g_next, action): """ Heuristique qui retourne la hauteur du dernier coup joué. Paramètres : - grid_prec : instance State.State : Etat du jeu avant le coup 'action'. - grid_next : instance State.State : Etat du jeu après le coup 'action'. - action : dictionnaire de la forme {"choose" : kind, "rotate" : rotation, "hor_move" : move} : action à jouer. retour : int : hauteur du dernier coup""" kind = action["choose"] rotation = action["rotate"] hor_move = action["hor_move"] p = Piece.Piece.factory(kind, copy.copy(Piece.Piece.centers_init[kind])) etat = State.State(g_prec.grid) hauteur = 0 for _ in range(rotation): p.rotate() if (State.is_piece_accepted_abscisse( p, p.center[0] + p.block_control[0] + hor_move)): p.center[0] += hor_move r = etat.drop_piece(p, 0) for b in p.blocks: h_tmp = p.center[1] + b[1] if h_tmp > hauteur: hauteur = h_tmp return hauteur return gp.TAILLE_Y_LIMITE - 1
def basic_smart_ia(state) : """ Stratégie IA aléatoire smart : Elle joue aléatoirement, sauf si elle peut prendre une ligne. Dans ce cas, elle complète la ligne; Paramètres : - state : instance State.State : etat du jeu Retour : Un play de la forme {"hor_move":hor_move, "rotate":rotat, "choose":piece}""" pieces = copy.copy(state["pieces"]) scores = [] compteur = 0 for kind in pieces : for rotation in range(0,4,1) : for move in range(-5,7,1) : play = {"choose":kind, "rotate":rotation, "hor_move":move} grid_tmp = State.State(copy_grid(state["grid"])) p = Piece.Piece.factory(kind, copy.copy(Piece.Piece.centers_init[kind])) for _ in range(rotation) : p.rotate() if(State.is_piece_accepted_abscisse(p, p.center[0] + p.block_control[0] + move)) : p.center[0] += move r = grid_tmp.drop_piece(p, 0) scores += [[play, grid_tmp.score[0]]] scores.sort(key=lambda x : x[1], reverse=True) best = scores[0][1] best_plays = [] for s in scores : if s[1] >= best : best_plays += [s] play_send = random.choice(best_plays)[0] return play_send
def erosion(g_prec, g_next, action): """ Heuristique : (nombre de line réalisée par action)*(nombre de block de la piece détuits). Paramètres : - grid_prec : instance State.State : Etat du jeu avant le coup 'action'. - grid_next : instance State.State : Etat du jeu après le coup 'action'. - action : dictionnaire de la forme {"choose" : kind, "rotate" : rotation, "hor_move" : move} : action à jouer. retour : - int : (nombre de line réalisée par action)*(nombre de block de la piece détuits) """ kind = action["choose"] rotation = action["rotate"] hor_move = action["hor_move"] #on recréer la piece et l'état précédent p = Piece.Piece.factory(kind, copy.copy(Piece.Piece.centers_init[kind])) etat = State.State(g_prec.grid) hauteur = 0 for _ in range(rotation): p.rotate() #si elle dépasse, return 0 if (not State.is_piece_accepted_abscisse( p, p.center[0] + p.block_control[0] + hor_move)): return 0 #on descend la piece p.center[0] += hor_move while not etat.is_piece_blocked(p): p.center[1] -= 1 #on calcul tous les indices d'ordonne de la piece qui est tombé indices_ordonnee_piece = [] for block in p.blocks: indices_ordonnee_piece += [int(p.center[1] + block[1])] etat.grid[int(p.center[0] + block[0])][int(p.center[1] + block[1])] = p.color set_ordonnee_piece = list(set(indices_ordonnee_piece)) #on compte le nombre de block détruit et le nombre de ligne réalisées. nb_block_detruit = 0 nb_lines_complete = 0 for j in set_ordonnee_piece: line_complete = True for i in range(gp.TAILLE_X): if etat.grid[i][j] == Block.Block.Empty: line_complete = False if line_complete: nb_lines_complete += 1 nb_block_detruit += indices_ordonnee_piece.count(j) return nb_lines_complete * nb_block_detruit
async def hor_move_piece(self, move): """Déplace la pièce courante horizontalement selon move. Attributs : - move : int / Réprésente le mouvement horizontale de la pièce move > 0 : déplacement à droite move < 0 : déplacement à gauche""" if State.is_piece_accepted_abscisse(self.current_piece, self.current_abscisse + move): self.current_abscisse = self.current_abscisse + move self.current_piece.center[0] += move
def format_state(self, state): """ Formats the state so that it can be used by tensorforce. :param state: dictionary containing information about the game, send by the server. :return: list containing the heuristics values. Represents the state. """ state_bis = State.State(state['grid']) heuristics_values = self.evaluate_heuristics(self.heuristics, None, state_bis, None) # selectable pieces as a one-shot vector pieces_one_hot = self.format_pieces(state['pieces']) # state used by tensorforce state_formatted = heuristics_values + pieces_one_hot print('{}, {}'.format(heuristics_values, pieces_one_hot)) return state_formatted
def __init__(self, gid, nb_players, nb_turn, nb_choices): """Créer une nouvelle Game. Attributs : - gid : int / ID de la Game. - nb_players : int / Nombre de joueurs dans la partie - nb_turn : int / Nombre de tour maximum dans la partie - nb_choice : int / Nombre de différentes pieces présentées aux joueurs à chaque tours Retourne : - Game : nouvelle game""" super().__init__(gid) self.grid = State.State() self.actual_turn = 0 self.actual_player = 0 self.actual_pieces = list() self.step = "init" self.current_piece = None self.current_abscisse = None self.nb_turn = nb_turn self.nb_choices = nb_choices self.nb_players = nb_players
def agregate_height(g_prec, g_next, action): """ Heuristique : Somme de la hauteur de chaque colonne. Paramètres : - grid_prec : instance State.State : Etat du jeu avant le coup 'action'. - grid_next : instance State.State : Etat du jeu après le coup 'action'. - action : dictionnaire de la forme {"choose" : kind, "rotate" : rotation, "hor_move" : move} : action à jouer. retour : - int : somme de la heuteur de chaque colonne de g_next """ etat = State.State(g_next.grid) somme = 0 for i in range(gp.TAILLE_X): ordonnes = list(range(gp.TAILLE_Y_LIMITE - 1)) ordonnes.reverse() for j in ordonnes: if etat.grid[i][j] != Block.Block.Empty: #première case de la colonne qui n'est pas vide somme += j break return somme
def __init__(self, name, load_file=None, is_stats=False, file_stats=None, train_adversary_level=2, nb_batches=5000, nb_games_per_batch=2, layer_size=15, nb_layers=3): """ :param name: name of the IA/ :param load_file: path and name of the model to load (without any extension). :param is_stats: boolean which tells whether the statistics are enabled. :param file_stats: name of the file where the statistics are written. :param train_adversary_level: integer indicating the AI to train against (corresponds to level in AICreator). :param nb_batches: number of batches. A batch is a group of successive games on which the ratio (nb_won_games / nb_games_per_batch) is computed and saved in score.txt. :param nb_games_per_batch: number of games per batch. :param layer_size: size of a neural network layer. :param nb_layers: number of layers in the neural network. """ super().__init__(name, load_file) self.current_game_is_finish = None self.first_game = True # score self.score_self_old, self.score_self_new = 0, 0 self.score_other_old, self.score_other_new = 0, 0 self.file_scores = open('scores.txt', 'w') # AI parameters self.heuristics = [ Heuristic.line_transition, Heuristic.column_transition, Heuristic.hidden_empty_cells, Heuristic.wells, Heuristic.holes, Heuristic.highest_column, Heuristic.columns_heights ] state = State.State() heuristics_sizes = [ heuristic(state, state, None) for heuristic in self.heuristics ] self.nb_heuristics = len(flatten(heuristics_sizes)) print('self.nb_heuristics', heuristics_sizes) self.train_adversary_level = train_adversary_level # iteration self.nb_batches = nb_batches self.nb_games_per_batch = nb_games_per_batch self.iteration = 0 # neural network self.layer_size = layer_size self.nb_layers = nb_layers network_spec = [ dict(type='dense', size=self.layer_size, activation='relu') ] * self.nb_layers self.agent = DQNAgent(states_spec={ 'shape': (self.nb_heuristics + NOMBRE_DE_PIECES, ), 'type': 'float' }, actions_spec={ 'hor_move': { 'type': 'int', 'num_actions': 11 }, 'rotate': { 'type': 'int', 'num_actions': 4 }, 'choose': { 'type': 'int', 'num_actions': 3 } }, network_spec=network_spec) # loading of a saved model if load_file is not None: self.load(load_file) # stats self.is_stats = is_stats self.my_stats = None self.file_stats = file_stats self.pid_stats = None
def best_move(heuristic, weights, state): """ Teste toutes les coups et retourne le meilleurs selon les heuristiques et l'état du jeu. Paramètres : - heuristic : liste de fonction : chaque fonction de la liste représente une heuristic et est de la forme : fonction(grid_prec, grid_next, action) . - weights : liste de poids (float) : cette liste doit être de la même taille que heuristic. Chaque poids indicé i dans la liste sera associé à l'heuristique indicée i. - state : instance State.State : représente l'état du jeu au moment de choisir le l'action Retour : dictionnaire de la forme {"choose" : kind, "rotate" : rotation, "hor_move" : move} : Représente la meilleur action calculée en fonction des heuristiques.""" pieces = copy.copy(state["pieces"]) scores_valid = [] scores_non_valid = [] compteur = 0 for kind in pieces: for rotation in range(0, 4, 1): for move in range(-5, 5, 1): play = {"choose": kind, "rotate": rotation, "hor_move": move} grid_tmp = State.State(copy_grid(state["grid"])) grid_prec = State.State(copy_grid(state["grid"])) p = Piece.Piece.factory( kind, copy.copy(Piece.Piece.centers_init[kind])) for _ in range(rotation): p.rotate() if (State.is_piece_accepted_abscisse( p, p.center[0] + p.block_control[0] + move)): p.center[0] += move r = grid_tmp.drop_piece(p, 0) if r: #ne prends pas en compte les coups perdants scores_valid += [[ play, evaluate_play(grid_prec, grid_tmp, play, weights, heuristic) ]] else: #prends tous les coups perdants scores_non_valid += [[ play, evaluate_play(grid_prec, grid_tmp, play, weights, heuristic) ]] scores = [] if len(scores_valid) > 0: #On ne veut choisir un play que parmis ceux qui ne font pas perdre scores = scores_valid else: #s'il n'existe pas de play valid, alors on doit en choisir un parmis tous ceux qui font perdre scores = scores_non_valid scores.sort(key=lambda x: x[1], reverse=True) best = scores[0][1] best_plays = [] for s in scores: if s[1] >= best: best_plays += [s] play_send = random.choice(best_plays)[0] return play_send
Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty ], [ Block.Block.Red, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Red, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty, Block.Block.Empty ]] action = {"hor_move": 1, "choose": 'L', "rotate": 1} # etat = State.State(my_grid) # etat.score[0] = 125 # etat.score[1] = 168 # print(etat) # etat2 = State.State(my_grid) # etat2.score[0] = 125 # etat2.score[1] = 365 # print(score(etat, etat2, None)) etat = State.State(my_grid) #print(etat) #print("Erosion : ", erosion(etat, None, action))