def __init__(self, goose, config): self._goose = goose self._configuration = config if (len(self._goose) > 0): self._r, self._c = row_col(self._goose[0], self._configuration.columns) else: self._r = -1 self._c = -1 self._possible_moves = ['SOUTH', 'NORTH', 'WEST', 'EAST']
def __init__(self, observation, configuration): self.obs = observation self.config = configuration self.rows = configuration.rows self.cols = configuration.columns self.player_index = self.obs.index self.start = row_col(self.obs.geese[self.player_index][0], self.cols) self.mapa = self.get_grid_from_obs() self.heu_map = self.heristic() self.frontier = []
def default_agent(obs_dict, config_dict=None): """This agent always moves toward observation.food[0] but does not take advantage of board wrapping""" observation = Observation(obs_dict) # configuration = Configuration(config_dict) configuration_columns = 11 player_index = observation.index player_goose = observation.geese[player_index] player_head = player_goose[0] player_row, player_column = row_col(player_head, configuration_columns) food = observation.food[0] food_row, food_column = row_col(food, configuration_columns) if food_row > player_row: return Action.SOUTH.name if food_row < player_row: return Action.NORTH.name if food_column > player_column: return Action.EAST.name return Action.WEST.name
def centroid_agent(self, board, head, configuration): head_row, head_col = row_col(head, configuration.columns) # X is [0, 11), center is 5 # Y is [0, 7), center is 3 dX = head_col - 5 dY = 3 - head_row # Сдвиг строк - dY if dY != 0: board = np.vstack((board[-dY:], board[:-dY])) # Сдвиг колонок - dX if dX != 0: board = np.hstack((board[:, dX:], board[:, :dX])) return board
def process_board(self, obs, conf, gindex): rows, columns = conf.rows, conf.columns board = np.zeros((rows + 2, columns + 2, 3)) if 'food' in obs.keys(): for food in obs['food']: r, c = row_col(food, columns) for i in range(r, r + 3): for j in range(c, c + 3): board[i, j, 0] = 1.0 if i == r + 1 and j == c + 1 else 0.0 for gind, goose in enumerate(obs['geese']): if len(goose) > 0: for v in goose[1:-1]: r, c = row_col(v, columns) board[r + 1, c + 1, 1] = 0.66 r, c = row_col(goose[-1], columns) board[r + 1, c + 1, 1] = 0.1 if gind != gindex: r, c = row_col(goose[0], columns) board[r + 1, c + 1, 1] = 1.0 for i in [0, 2]: if board[r + i, c + 1, 1] == 0: board[r + i, c + 1, 1] = 0.33 if board[r + 1, c + i, 1] == 0: board[r + 1, c + i, 1] = 0.33 else: for v in goose[1:-1]: r, c = row_col(v, columns) board[r + 1, c + 1, 2] = 0.66 r, c = row_col(goose[0], columns) board[r + 1, c + 1, 2] = 1.0 for i in range(rows): if board[i + 1, -2, 1] == 1.0: board[i + 1, 1, 1] = 0.33 if board[i + 1, 1, 1] == 1.0: board[i + 1, -2, 1] = 0.33 for i in range(columns): if board[-2, i + 1, 1] == 1.0: board[1, i + 1, 1] = 0.33 if board[1, i + 1, 1] == 1.0: board[-2, i + 1, 1] = 0.33 board[0] = board[-2] board[-1] = board[1] board[:, 0] = board[:, -2] board[:, -1] = board[:, 1] board[0, 0] = board[-2, -2] board[0, -1] = board[-2, 1] board[-1, 0] = board[1, -2] board[-1, -1] = board[1, 1] return board
def heristic(self): heu = [] foodPos = [] for food in self.obs['food']: x, y = row_col(food, self.cols) foodPos.append([x, y]) for i in range(0, self.mapa.shape[0]): heu.append([]) for j in range(0, self.mapa.shape[1]): tp = self.mapa[i][j] if (tp == 2): heu[i].append(-1) continue else: d = 1000000 for pos in foodPos: if (d > self.distance(i, j, pos[0], pos[1])): d = self.distance(i, j, pos[0], pos[1]) heu[i].append(d) return np.array(heu, dtype="int32")
def fill_matrix(observation, configuration): #0 = empty space #1 = player head #2 = player body #3 = player end #4 = generic goose head #5 = generic goose body #6 = generic goose end #7 = food Matrix = [[0 for x in range(numCols)] for y in range(numRows)] MatrixNoFood = [[0 for x in range(numCols)] for y in range(numRows)] MatrixHeadAvoid1 = [[0 for x in range(numCols)] for y in range(numRows)] MatrixHeadAvoid2 = [[0 for x in range(numCols)] for y in range(numRows)] foodPosition = 7 player_index = observation.index #might want to replace non empty spots with an array or tuple (to indicate what it is and what body position to track all parts of goose neck.) for i in range(len(observation.geese)): #Checks if for our goose or generic goose if i == player_index: bodyPart = 2 headPart = 1 endPart = 3 else: bodyPart = 5 headPart = 4 endPart = 6 player_goose = observation.geese[i] #for each body part for j in range(len(player_goose)): player_part = player_goose[j] player_row, player_column = row_col(player_part, configuration.columns) if j == 0: Matrix[player_row][player_column] = headPart MatrixNoFood[player_row][player_column] = headPart # MatrixHeadAvoid1[player_row][player_column] = headPart MatrixHeadAvoid2[player_row][player_column] = headPart if i != player_index: for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0)]: node_position = ((player_row + new_position[0])%numRows, (player_column + new_position[1])%numCols) if MatrixHeadAvoid1[node_position[0]][node_position[1]] == 0: MatrixHeadAvoid1[node_position[0]][node_position[1]] = 9 for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0), (-1, -1), (-1, 1), (1, -1), (1, 1)]: node_position = ((player_row + new_position[0])%numRows, (player_column + new_position[1])%numCols) if MatrixHeadAvoid2[node_position[0]][node_position[1]] == 0: MatrixHeadAvoid2[node_position[0]][node_position[1]] = 9 elif j == len(player_goose)-1: Matrix[player_row][player_column] = endPart MatrixNoFood[player_row][player_column] = endPart # MatrixHeadAvoid1[player_row][player_column] = endPart MatrixHeadAvoid2[player_row][player_column] = endPart else: Matrix[player_row][player_column] = bodyPart MatrixNoFood[player_row][player_column] = bodyPart # MatrixHeadAvoid1[player_row][player_column] = bodyPart MatrixHeadAvoid2[player_row][player_column] = bodyPart #Food placement for i in range(len(observation.food)): tempfood = observation.food[i] tempfood_row, tempfood_column = row_col(tempfood, configuration.columns) Matrix[tempfood_row][tempfood_column] = foodPosition return Matrix, MatrixNoFood, MatrixHeadAvoid1, MatrixHeadAvoid2
def agent(obs_dict, config_dict): """This agent always moves toward observation.food[0] but does not take advantage of board wrapping""" observation = Observation(obs_dict) configuration = Configuration(config_dict) maze_col = configuration.columns maze_rows = configuration.rows maze = np.zeros([maze_rows, maze_col]) print("Player") # Define my player player_index = observation.index player_goose = observation.geese[player_index] player_head = player_goose[0] player_row, player_column = row_col(player_head, configuration.columns) start = (player_row, player_column) print(start) #Define Food hipotenuse_low = 14 closest_food = observation.food[0] for food in observation.food: food_row, food_column = row_col(food, configuration.columns) hipotenuse = sqrt((player_row - food_row)**2 + (player_column - food_column)**2) if hipotenuse < hipotenuse_low: hipotenuse_low = hipotenuse closest_food = food end = row_col(closest_food, configuration.columns) # Define the enemies players enemies_indexes = observation.geese del enemies_indexes[player_index] for enemies in enemies_indexes: for enemies_pos in enemies: enemie_row, enemie_col = row_col(enemies_pos, configuration.columns) maze[enemie_row, enemie_col] = 1 for player_pos in player_goose[1:]: player_rw, player_col = row_col(player_pos, configuration.columns) maze[player_rw, player_col] = 1 path = astar(maze, start, end, False) next_move = path[1] print(next_move) print(player_column) print(player_row) x = int(next_move[1]) - int(player_column) y = int(next_move[0]) - int(player_row) print(x, y) print(maze) if x == -1 and y == 0: print("WEST") return Action.WEST.name if x == 1 and y == 0: print("EAST") return Action.EAST.name if x == 0 and y == -1: print("NORTH") return Action.NORTH.name if x == 0 and y == 1: print("SOUTH") return Action.SOUTH.name
def path_to_closest_food(observation, configuration, MatrixsToUse, start, shift): #instead of using obeservation.food[0] should find out which food has shortest route from head. bestFood = 0 bestFoodDistance = numCols + numRows bestPath = "no path" f = open("./myfile1.txt", "a") for MatrixToUse in MatrixsToUse: if bestPath != "no path": f.write("\n") f.write("Current MatrixToUse: " + str(MatrixToUse)) f.write("\n") continue for i in range(len(observation.food)): f.write(str(observation.food) + " <-- num foods, ") f.write("iteration of path to closest food: " + str(i)) f.write("\n") tempfood = observation.food[i] tempfood_row, tempfood_column = row_col(tempfood, configuration.columns) end = (tempfood_row, tempfood_column) tempRow = int((end[0] + shift[0]) % numRows) tempCol = (end[1] + shift[1]) % numCols end = (tempRow, tempCol) f.write("Start coords2 " + str(start) + "\n" + "End coords2 " + str(end) + "\n") filledspaces = 0 for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0)]: node_position = ((end[0] + new_position[0])%6, (end[1] + new_position[1])%10) if MatrixToUse[node_position[0]][node_position[1]] != 0: if MatrixToUse[node_position[0]][node_position[1]] == 4: filledspaces += 7 f.write("Head detected") filledspaces += 1 if filledspaces <= 1: path = astar(MatrixToUse, start, end) try: if (len(path)) < bestFoodDistance: bestFood = i bestFoodDistance = len(path) bestPath = path except TypeError: path = "no path" if bestPath == "no path": return bestPath for j in range(len(bestPath)): tempRow = int((bestPath[j][0] - shift[0]) % numRows) tempCol = int((bestPath[j][1] - shift[1]) % numCols) bestPath[j] = (tempRow, tempCol) #food = observation.food[bestFood] #food_row, food_column = row_col(food, configuration.columns) #This will need to be changed, food distance depends on direction snake just traveled, whether other geese are close (as it could be pointless) and which spots on the board are filled #Will implement a map solving algorithm for all alive geese and if our goose has shortest distance, will select food that way. #Could also implement escape route algorithm? Don't know how that would work, ask ben return bestPath
def agent(obs_dict, config_dict): global which_turn which_turn += 1 t0= time.clock() f = open("./myfile1.txt", "a") f.write("\n") f.write("Starting file" + "\n") observation = Observation(obs_dict) configuration = Configuration(config_dict) player_index = observation.index player_goose = observation.geese[player_index] #player_goose is list of all bodypart positions player_head = player_goose[0] player_row, player_column = row_col(player_head, configuration.columns) start = (player_row, player_column) f.write("Commencing turn: " + str(which_turn)) with open('./myfile2.txt', 'a') as testfile: testfile.write("Player_index: " + str(player_index) + " [0: White, 1: Blue, 2: Green, 3: Red], " + "\n") f.write("Player_index: " + str(player_index) + " [0: White, 1: Blue, 2: Green, 3: Red], " + "\n") """This agent always moves toward observation.food[0] but does not take advantage of board wrapping""" Matrix, MatrixNoFood, MatrixHeadAvoid1, MatrixHeadAvoid2 = fill_matrix(observation, configuration) f.write("Matrix filled" + "\n") [MatrixNoFood, MatrixHeadAvoid1, MatrixHeadAvoid2], start, shift = shift_matrix([MatrixNoFood, MatrixHeadAvoid1, MatrixHeadAvoid2], start) f.write("Matrix shifted" + "\n") f.write("Start coords " + str(start) + "\n") #MatrixToUse = MatrixNoFood #MatrixToUse = MatrixHeadAvoid2 #MatrixToUse = MatrixHeadAvoid1 #MatrixBackup1 = MatrixHeadAvoid1 #MatrixBackup2 = MatrixNoFood #MatrixsToUse = [MatrixHeadAvoid2, MatrixHeadAvoid1, MatrixNoFood] MatrixsToUse = [MatrixHeadAvoid1, MatrixNoFood] #will replace player_row, player_column with 2d array that has all positions filled with all player information path = path_to_closest_food(observation, configuration, MatrixsToUse, start, shift) if path == "no path": player_index = observation.index player_goose = observation.geese[player_index] player_end = player_goose[len(player_goose)-1] player_end_row, player_end_column = row_col(player_end, configuration.columns) for MatrixToUse in MatrixsToUse: if path == "no path": if start == (player_end_row, player_end_column): path = astar(MatrixToUse, start, (player_end_row+3, player_end_column+5)) else: path = astar(MatrixToUse, start, (player_end_row, player_end_column)) f.write("Path: " + str(path) + "\n") whichMove = which_direction(path) t1 = time.clock() - t0 f.write("This is turn: " + str(int(which_turn)) + " , chosen movement: " ) f.write(str(whichMove)) f.write(" which took " + str(t1) + " seconds") f.close() return whichMove
def translate(position: int, direction: Action, columns: int, rows: int): row, column = row_col(position, columns) row_offset, column_offset = direction.to_row_col() row = (row + row_offset) % rows column = (column + column_offset) % columns return row * columns + column
def get_sensors_from_grid(grid, columns, obs, last, debug): print() if (len(obs['geese'][obs['index']]) == 0): return np.array([0, 0, 0, 0, 0, 0, 0]) px, py = row_col(obs['geese'][obs['index']][0], columns) actL = [] for action in Action: actL.append(action) frente = 0 if (last): actL.remove(last) for i in range(0, len(actL)): if (actL[i] == opposite(last)): frente = i break else: # Diz que esta indo para o norte e remove o oposto (SUL) actL.remove(action.SOUTH) frente = 0 direita = frente + 1 if (direita > 3): direita = direita - 4 esquerda = frente + 3 if (esquerda > 3): esquerda = esquerda - 4 movimentos = [ [-1, 0], #Norte [0, 1], #Leste [1, 0], #Sul [0, -1], #Oeste ] sensor_frente = [0, 0] #[distancia,tipo (0:inimigo,1:food)] for i in range(0, 11): px_a, py_a = (px + movimentos[frente][0] * (i + 1), py + movimentos[frente][1] * (i + 1)) if (px_a > 6): px_a = px_a - 7 if (py_a > 10): py_a = py_a - 11 if (px_a < 0): px_a = 7 + px_a if (py_a < 0): py_a = 11 + py_a if (grid[px_a][py_a] == 2 or grid[px_a][py_a] == 1): break if (grid[px_a][py_a] == 3): sensor_frente[1] = 1 break else: sensor_frente[0] += 1 sensor_esquerda = [0, 0] #[distancia,tipo (0:inimigo,1:food)] for i in range(0, 11): px_a, py_a = (px + movimentos[esquerda][0] * (i + 1), py + movimentos[esquerda][1] * (i + 1)) if (px_a > 6): px_a = px_a - 7 if (py_a > 10): py_a = py_a - 11 if (px_a < 0): px_a = 7 + px_a if (py_a < 0): py_a = 11 + py_a if (grid[px_a][py_a] == 2 or grid[px_a][py_a] == 1): break if (grid[px_a][py_a] == 3): sensor_esquerda[1] = 1 break else: sensor_esquerda[0] += 1 sensor_direita = [0, 0] #[distancia,tipo (0:inimigo,1:food)] for i in range(0, 11): px_a, py_a = (px + movimentos[direita][0] * (i + 1), py + movimentos[direita][1] * (i + 1)) if (px_a > 6): px_a = px_a - 7 if (py_a > 10): py_a = py_a - 11 if (px_a < 0): px_a = 7 + px_a if (py_a < 0): py_a = 11 + py_a if (grid[px_a][py_a] == 2 or grid[px_a][py_a] == 1): break if (grid[px_a][py_a] == 3): sensor_direita[1] = 1 break else: sensor_direita[0] += 1 # Verificando as diagonais tras = frente + 2 if (tras >= 4): tras -= 4 px_a, py_a = (px + movimentos[direita][0] + movimentos[frente][0]), (py + movimentos[direita][1] + movimentos[frente][1]) if (px_a > 6): px_a = px_a - 7 if (py_a > 10): py_a = py_a - 11 if (px_a < 0): px_a = 7 + px_a if (py_a < 0): py_a = 11 + py_a frente_direita = grid[px_a, py_a] px_a, py_a = (px + movimentos[esquerda][0] + movimentos[frente][0]), (py + movimentos[esquerda][1] + movimentos[frente][1]) if (px_a > 6): px_a = px_a - 7 if (py_a > 10): py_a = py_a - 11 if (px_a < 0): px_a = 7 + px_a if (py_a < 0): py_a = 11 + py_a frente_esquerda = grid[px_a, py_a] px_a, py_a = (px + movimentos[esquerda][0] + movimentos[tras][0]), (py + movimentos[esquerda][1] + movimentos[tras][1]) if (px_a > 6): px_a = px_a - 7 if (py_a > 10): py_a = py_a - 11 if (px_a < 0): px_a = 7 + px_a if (py_a < 0): py_a = 11 + py_a tras_esqueda = grid[px_a, py_a] px_a, py_a = (px + movimentos[direita][0] + movimentos[tras][0]), (py + movimentos[direita][1] + movimentos[tras][1]) if (px_a > 6): px_a = px_a - 7 if (py_a > 10): py_a = py_a - 11 if (px_a < 0): px_a = 7 + px_a if (py_a < 0): py_a = 11 + py_a tras_direita = grid[px_a, py_a] return np.array([ frente, sensor_frente[0], sensor_frente[1], sensor_esquerda[0], sensor_esquerda[1], sensor_direita[0], sensor_direita[1], frente_direita, frente_esquerda, tras_direita, tras_esqueda ])
import numpy as np from kaggle_environments.envs.hungry_geese.hungry_geese import Action, row_col PLAYERS_N = 4 BASIC_GRID_ROWS, BASIC_GRID_COLUMNS = BASIC_GRID_SHAPE = (7, 11) BASIC_GRID_SIZE = np.prod(BASIC_GRID_SHAPE) MAX_DIM = max(BASIC_GRID_SHAPE) LAYER_FOOD, LAYER_OBSTACLES = np.arange(2) INDEX_TO_COORD = np.array( [row_col(x, BASIC_GRID_COLUMNS) for x in range(BASIC_GRID_SIZE)]) ROTATIONS_FOR_ACTION = { 'EAST': 1, 'WEST': 3, 'SOUTH': 2, 'NORTH': 0, } INDEX_TO_ACTION = ['WEST', 'NORTH', 'EAST', 'SOUTH'] ACTIONS_MAPPING_BY_DIRECTION = [ # NORTH ['WEST', 'NORTH', 'EAST'], # EAST ['NORTH', 'EAST', 'SOUTH'], # SOUTH ['EAST', 'SOUTH', 'WEST'], # WEST ['SOUTH', 'WEST', 'NORTH'], ]
def min_distance(position: int, food: List[int], columns: int): row, column = row_col(position, columns) return min( abs(row - food_row) + abs(column - food_column) for food_position in food for food_row, food_column in [row_col(food_position, columns)])
def agent(obs_dict, config_dict, gindex): ################################################# # State retrieval ################################################# #print("-----------") global last_action conf = Configuration(config_dict) obs = Observation(obs_dict) step = obs.step + 1 my_idx = gindex my_goose = obs.geese[my_idx] my_head = my_goose[0] my_row, my_col = row_col(position=my_head, columns=conf.columns) if DEBUG: print("---------- Step #" + str(step), "- Player #" + str(obs.index)) ################################################# # Map update ################################################# board = np.zeros((7, 11), dtype=int) # Add food to board for food in obs.food: food_row, food_col = row_col(position=food, columns=conf.columns) board[food_row, food_col] += FOOD_REWARD '''if DEBUG: print("food", food_row, food_col)''' # Iterate over geese to add geese data to board nb_geese = len(obs.geese) geese_lengths = [] for i in range(nb_geese): '''if DEBUG: print("--- Goose #" + str(i))''' goose = obs.geese[i] potential_food_head = None # Iterate over cells of current goose goose_len = len(goose) geese_lengths.append(goose_len) '''if DEBUG: print("--- Goose #" + str(i) + " len " + str(goose_len))''' for j in range(goose_len): '''if DEBUG: print("--- Goose #" + str(i) + " cell " + str(j))''' goose_cell = goose[j] goose_row, goose_col = row_col(position=goose_cell, columns=conf.columns) # Check for food on neighbour cells when handling head if j == 0: potential_heads = get_neighbours(goose_row, goose_col) for potential_head in potential_heads: for food in obs.food: food_row, food_col = row_col(position=food, columns=conf.columns) if potential_head == (food_row, food_col): potential_food_head = potential_head # Update rewards linked to body/tail if j < goose_len - 1: # Body or head board[goose_row, goose_col] += BODY_REWARD '''if DEBUG: print("--- Goose #" + str(i) + " cell " + str(j) + " add BODY_REWARD")''' else: # Tail : may not move if goose eats if potential_food_head is not None: board[goose_row, goose_col] += TAIL_REWARD '''if DEBUG: print("--- Goose #" + str(i) + " cell " + str(j) + " add TAIL_REWARD")''' # Update potential villain head positions if (i != my_idx) & (goose_len > 0): if potential_food_head is not None: # Head will prolly go to the food for potential_head in potential_heads: if potential_head == potential_food_head: if (board[potential_head[0], potential_head[1]] != BODY_REWARD) & \ (board[potential_head[0], potential_head[1]] != TAIL_REWARD): board[ potential_head[0], potential_head[1]] += PROBABLE_HEAD_FOOD_REWARD '''if DEBUG: print("--- Goose #" + str(i) + " cell " + str(j) + " add PROBABLE_HEAD_FOOD_REWARD")''' else: if (board[potential_head[0], potential_head[1]] != BODY_REWARD) & \ (board[potential_head[0], potential_head[1]] != TAIL_REWARD): board[potential_head[0], potential_head[ 1]] += IMPROBABLE_HEAD_FOOD_REWARD '''if DEBUG: print("--- Goose #" + str(i) + " cell " + str(j) + " add IMPROBABLE_HEAD_FOOD_REWARD")''' else: # Standard potential head reward for potential_head in potential_heads: if (board[potential_head[0], potential_head[1]] != BODY_REWARD) & \ (board[potential_head[0], potential_head[1]] != TAIL_REWARD): board[potential_head[0], potential_head[1]] += POTENTIAL_HEAD_STD_REWARD '''if DEBUG: print("--- Goose #" + str(i) + " cell " + str(j) + " add POTENTIAL_HEAD_STD_REWARD")''' # Check if I'm the current longest Goose if (len(my_goose) >= max(geese_lengths) - 3) & (step > 8): # Chasing my tail as a defensive action makes sense my_tail_row, my_tail_col = row_col(position=my_goose[-1], columns=conf.columns) board[my_tail_row, my_tail_col] += TAIL_CHASE_REWARD '''if DEBUG: print("Adding TAIL_CHASE_REWARD for me")''' # Diffuse values in adjacent cells if DEBUG: print("Initial board :") print(board) new_board = board.copy() for i in range(7): for j in range(11): value = board[i, j] if value > DIFFUSE_START: # Should diffuse positive value neighbours = get_neighbours(i, j) for neighbour in neighbours: # Level 1 new_board[neighbour] += (2 * DIFFUSE_POS_REWARD) # Level 2 neighbours_lvl2 = get_neighbours(neighbour[0], neighbour[1]) for neighbour_lvl2 in neighbours_lvl2: new_board[neighbour_lvl2] += DIFFUSE_POS_REWARD elif value < -DIFFUSE_START: # Should diffuse negative value neighbours = get_neighbours(i, j) for neighbour in neighbours: # Level 1 new_board[neighbour] += (2 * DIFFUSE_NEG_REWARD) # Level 2 neighbours_lvl2 = get_neighbours(neighbour[0], neighbour[1]) for neighbour_lvl2 in neighbours_lvl2: new_board[neighbour_lvl2] += DIFFUSE_NEG_REWARD board = new_board # Add last_action data to board if last_action is not None: if last_action == Action.SOUTH.name: board[(my_row + 6) % 7, my_col] += REVERSE_LAST_REWARD elif last_action == Action.NORTH.name: board[(my_row + 8) % 7, my_col] += REVERSE_LAST_REWARD elif last_action == Action.EAST.name: board[my_row, (my_col + 10) % 11] += REVERSE_LAST_REWARD elif last_action == Action.WEST.name: board[my_row, (my_col + 12) % 11] += REVERSE_LAST_REWARD '''if DEBUG: print("Adding REVERSE_LAST_REWARD for me")''' if DEBUG: print("Final board :") print(board) ################################################# # Choose best action ################################################# chosen_action = None rewards = [] potential_next = get_neighbours(my_row, my_col) for cell in potential_next: rewards.append(board[cell]) choice = np.argmax(rewards) if choice == 0: chosen_action = Action.NORTH.name elif choice == 1: chosen_action = Action.WEST.name elif choice == 2: chosen_action = Action.SOUTH.name else: chosen_action = Action.EAST.name if DEBUG: print("chosen_action", chosen_action) last_action = chosen_action return chosen_action
def straightforward_bfs(obs_dict, config_dict): observation = Observation(obs_dict) configuration = Configuration(config_dict) player_index = observation.index player_goose = observation.geese[player_index] player_head = player_goose[0] start_row, start_col = row_col(player_head, configuration.columns) mask = np.zeros((configuration.rows, configuration.columns)) for current_id in range(4): current_goose = observation.geese[current_id] for block in current_goose: current_row, current_col = row_col(block, configuration.columns) mask[current_row, current_col] = -1 food_coords = [] for food_id in range(configuration.min_food): food = observation.food[food_id] current_row, current_col = row_col(food, configuration.columns) mask[current_row, current_col] = 2 food_coords.append((current_row, current_col)) last_action = bfs(start_row, start_col, mask, food_coords) global LAST_ACTION up_x = start_row + 1 if start_row != 6 else 0 down_x = start_row - 1 if start_row != 0 else 6 left_y = start_col - 1 if start_col != 0 else 10 right_y = start_col + 1 if start_col != 10 else 0 step = Action.NORTH.name if last_action == 0: step = Action.SOUTH.name if LAST_ACTION == Action.NORTH.name: if mask[down_x, start_col] != -1: step = Action.NORTH.name elif mask[start_row, left_y] != -1: step = Action.WEST.name elif mask[start_row, right_y] != -1: step = Action.EAST.name if last_action == 1: step = Action.NORTH.name if LAST_ACTION == Action.SOUTH.name: if mask[up_x, start_col] != -1: step = Action.SOUTH.name elif mask[start_row, left_y] != -1: step = Action.WEST.name elif mask[start_row, right_y] != -1: step = Action.EAST.name if last_action == 2: step = Action.WEST.name if LAST_ACTION == Action.EAST.name: if mask[up_x, start_col] != -1: step = Action.SOUTH.name elif mask[down_x, start_col] != -1: step = Action.NORTH.name elif mask[start_row, right_y] != -1: step = Action.EAST.name if last_action == 3: step = Action.EAST.name if LAST_ACTION == Action.WEST.name: if mask[up_x, start_col] != -1: step = Action.SOUTH.name elif mask[down_x, start_col] != -1: step = Action.NORTH.name elif mask[start_row, left_y] != -1: step = Action.WEST.name LAST_ACTION = step return step
def agent(obs_dict, config_dict): observation = Observation(obs_dict) configuration = Configuration(config_dict) player_index = observation.index player_goose = observation.geese[player_index] player_head = player_goose[0] player_tail = player_goose[-1] my_X, my_Y = row_col(player_head, configuration.columns) my_tail_X, my_tail_Y = row_col(player_tail, configuration.columns) mask = np.zeros((configuration.rows, configuration.columns)) global last_direction global iteration_number print("**iteration**: {}".format(iteration_number)) print("my head at {} - {}".format([my_X, my_Y], last_direction)) iteration_number+=1 food_location = [] available_steps = {} other_heads = [] # head of competitor geese body_cells = [] other_tails = [] last_direction_updated = False # add all directions possible_positions = get_nearest_cells(my_X, my_Y) for x, y in possible_positions: direct = '-' if((x-1 == my_X) or (x==0 and my_X==6)) and last_direction != 'NORTH': direct = 'SOUTH' elif((x+1 == my_X) or (x==6 and my_X==0)) and last_direction != 'SOUTH': direct = 'NORTH' elif((y-1 == my_Y) or (y==0 and my_Y==10)) and last_direction != 'WEST': direct = 'EAST' elif((y+1 == my_Y) or (y==10 and my_Y==0)) and last_direction != 'EAST': direct = 'WEST' if direct != '-': available_steps[(x,y)] = [direct,0] for food in observation.food: x,y = row_col(food, configuration.columns) mask[x, y] = 2 food_location.append([x,y]) print("food locations are {}".format(food_location)) # where other goose can come danger_area = {} for i in range(len(observation.geese)): opp_goose = observation.geese[i] if len(opp_goose) == 0: continue for ind, goose in enumerate(opp_goose): x, y = row_col(goose, configuration.columns) mask[x, y] = -1 # and mark the occupied cells if not head or tail of goose if ind != 0 and ind != len(opp_goose) - 1: body_cells.append([x,y]) if ind != 0 and ind == len(opp_goose) - 1: other_tails.append([x,y]) if (x, y) in available_steps.keys(): # let's remove all cells that are not available from available steps available_steps.pop((x,y)) if (x, y) in danger_area.keys(): # let's remove all cells that are not available from danger steps danger_area.pop((x,y)) if not len(available_steps) and not len(danger_area): #if steps is empty kill by NORTH direction print("kill") if player_head!=player_tail and (my_tail_X, my_tail_Y) in possible_positions: last_direction = get_direction((my_X, my_Y), (my_tail_X, my_tail_Y)) else: last_direction = 'NORTH' last_direction_updated = True break if last_direction_updated: break if i != player_index: x, y = row_col(opp_goose[0], configuration.columns) # add competition goose head other_heads.append([x, y]) possible_moves = get_nearest_cells(x, y) # head can move anywhere for [x, y] in possible_moves: if (x,y) in available_steps.keys() and [x,y] in food_location: danger_area[(x,y)] = available_steps[(x,y)] available_steps.pop((x, y)) #only safe moves food_location.remove([x,y]) #don't consider this food elif (x,y) in available_steps.keys() and len(available_steps)+len(danger_area) > 1: danger_area[(x,y)] = available_steps[(x,y)] available_steps.pop((x, y)) #only safe moves if last_direction_updated: break print("body cells are {}".format(body_cells)) print("available steps are {}".format(available_steps)) print("other heads at {}".format(other_heads)) print("other tails at {}".format(other_tails)) print("danger area at {}".format(danger_area)) my_head = [my_X, my_Y] if not last_direction_updated: last_direction = my_move(food_location, available_steps, other_heads, my_head, last_direction, body_cells, danger_area, mask, other_tails) last_direction_updated = True return last_direction
def getGeesesIndex(): geeses = [] for geese in observation.geese: geeses.append(row_col(geese[0], configuration.columns)) return geeses
def getGoose(index): goose = [] for i in range(len(observation.geese[index])): goose.append( row_col(observation.geese[index][i], configuration.columns)) return goose
def getFoodsIndex(): foods = [] for i in range(len(observation.food)): food = observation.food[i] foods.append(row_col(food, configuration.columns)) return foods
def agent(obs_dict, config_dict): """This agent always moves toward observation.food[0] but does not take advantage of board wrapping""" global last_move observation = Observation(obs_dict) configuration = Configuration(config_dict) player_index = observation.index player_goose = observation.geese[player_index] player_head = player_goose[0] player_row, player_column = row_col(player_head, configuration.columns) possible_moves = [ Action.SOUTH.name, Action.NORTH.name, Action.WEST.name, Action.EAST.name ] possible_move = None oldFoodDistanceToMe = 9999 def getFoodsIndex(): foods = [] for i in range(len(observation.food)): food = observation.food[i] foods.append(row_col(food, configuration.columns)) return foods def getGoose(index): goose = [] for i in range(len(observation.geese[index])): goose.append( row_col(observation.geese[index][i], configuration.columns)) return goose def getGeesesIndex(): geeses = [] for geese in observation.geese: geeses.append(row_col(geese[0], configuration.columns)) return geeses def randomMove(moves): if len(moves) > 1: return moves[randint(0, len(moves) - 1)] return moves[0] def countMoves(x1, y1, x2, y2): return abs((x1 - x2) + (y1 - y2)) def willCollide(x, y, action): #print(f'Goose[{player_index} in player_row: {player_row}, player_column: {player_column} move to {action} and can collide with x: {x}, y: {y}') if action == Action.WEST.name: if player_column - 1 == y and x == player_row: return True if player_column == 0 and y == 10 and x == player_row: return True if action == Action.EAST.name: if player_column + 1 == y and x == player_row: return True if player_column == 10 and y == 0 and x == player_row: return True if action == Action.SOUTH.name: if player_row + 1 == x and y == player_column: return True if player_row == 6 and x == 0 and y == player_column: return True if action == Action.NORTH.name: if player_row - 1 == x and y == player_column: return True if player_row == 0 and x == 6 and y == player_column: return True return False def opposite(action): if action == Action.NORTH.name: return Action.SOUTH.name if action == Action.SOUTH.name: return Action.NORTH.name if action == Action.EAST.name: return Action.WEST.name if action == Action.WEST.name: return Action.EAST.name possible_moves = [ Action.SOUTH.name, Action.NORTH.name, Action.WEST.name, Action.EAST.name ] if last_move[player_index] is not None: print( f'Geese {player_index} removes opposite last move: {opposite(last_move[player_index])}' ) possible_moves.remove(opposite(last_move[player_index])) for geese_row, geese_column in getGeesesIndex(): for food_row, food_column in getFoodsIndex(): foodDistanceToMe = countMoves(food_row, food_column, player_row, player_column) if oldFoodDistanceToMe > foodDistanceToMe: oldFoodDistanceToMe = foodDistanceToMe else: continue geeseDistanceToFood = countMoves(geese_row, geese_column, food_row, food_column) if foodDistanceToMe < geeseDistanceToFood: if food_row > player_row: possible_move = Action.SOUTH.name if food_row < player_row: possible_move = Action.NORTH.name if food_column > player_column: possible_move = Action.EAST.name if food_column < player_column: possible_move = Action.WEST.name print( f'Geese {player_index} based by food, possible move: {possible_move}' ) if possible_move not in possible_moves: print( f'Geese {player_index}, possible move: {possible_move} is banned.') possible_move = randomMove(possible_moves) for i in range(len(observation.geese)): geese_index = getGoose(i) j = 0 while j < len(geese_index): collision = False x, y = geese_index[j] if i != player_index: print(f'geese {player_index} -> geese {i} part {j}') #print(f'goose[{player_index}] in {getGoose(player_index)[0]} with possible move: {possible_move} can colide with goose[{i}] in x: {x} and y: {y}') while willCollide(x, y, possible_move): collision = True print( f'goose[{player_index}] in {getGoose(player_index)[0]} with possible move: {possible_move} will colide with goose[{i}] in x: {x} and y: {y}' ) possible_moves.remove(possible_move) possible_move = randomMove(possible_moves) print(f'now goose[{player_index}] will to {possible_move}') j = 0 if not collision: j += 1 for x, y in getGoose(player_index): while willCollide(x, y, possible_move): print(f'BODY HIT!!!') possible_moves.remove(possible_move) possible_move = randomMove(possible_moves) if len(possible_moves) == 1: print( f'Geese {player_index} just remain this move: {possible_moves[0]}') possible_move = possible_moves[0] last_move[player_index] = possible_move print( f'Geese {player_index}: {getGoose(player_index)} move to {possible_move}' ) return possible_move
def agent(obs_dict, config_dict): global last_move global last_eaten global last_size global step #print ("==============================================") observation = Observation(obs_dict) configuration = Configuration(config_dict) player_index = observation.index player_goose = observation.geese[player_index] player_head = player_goose[0] player_row, player_column = row_col(player_head, configuration.columns) if (len(player_goose) > last_size): last_size = len(player_goose) last_eaten = step step += 1 moves = {1: 'SOUTH', 2: 'NORTH', 3: 'EAST', 4: 'WEST'} board = np.zeros((7, 11)) # Adding food to board for food in observation.food: x, y = row_col(food, configuration.columns) #print ("Food cell on ({}, {})".format(x, y)) board[x, y] = FOOD_CELL # Adding geese to the board for i in range(4): goose = observation.geese[i] # Skip if goose is dead if len(goose) == 0: continue # If it's an opponent if i != player_index: x, y = row_col(goose[0], configuration.columns) # Add possible head movements for it for px, py in get_nearest_cells(x, y): #print ("Head possible cell on ({}, {})".format(px, py)) # If one of these head movements may lead the goose # to eat, add tail as BODY_CELL, because it won't move. if board[px, py] == FOOD_CELL: x_tail, y_tail = row_col(goose[-1], configuration.columns) #print ("Adding tail on ({}, {}) as the goose may eat".format(x_tail, y_tail)) board[x_tail, y_tail] = BODY_CELL board[px, py] = HEAD_POSSIBLE_CELL # Adds goose body without tail (tail is previously added only if goose may eat) for n in goose[:-1]: x, y = row_col(n, configuration.columns) #print ("Body cell on ({}, {})".format(x, y)) board[x, y] = BODY_CELL # Adding my head to the board x, y = row_col(player_head, configuration.columns) #print ("My head is at ({}, {})".format(x, y)) board[x, y] = MY_HEAD # Debug board #print (board) # Iterate over food and geese in order to compute distances for each one food_race = {} for food in observation.food: food_race[food] = {} for i in range(4): goose = observation.geese[i] if len(goose) == 0: continue food_race[food][i] = cell_distance(goose[0], food, configuration) # The best food is the least coveted best_food = None best_distance = float('inf') best_closest_geese = float('inf') for food in food_race: #print ("-> Food on {}".format(row_col(food, configuration.columns))) my_distance = food_race[food][player_index] #print (" - My distance is {}".format(my_distance)) closest_geese = 0 for goose_id in food_race[food]: if goose_id == player_index: continue if food_race[food][goose_id] <= my_distance: closest_geese += 1 #print (" - There are {} closest geese".format(closest_geese)) if (closest_geese < best_closest_geese): best_food = food best_distance = my_distance best_closest_geese = closest_geese #print (" * This food is better") elif (closest_geese == best_closest_geese) and (my_distance <= best_distance): best_food = food best_distance = my_distance best_closest_geese = closest_geese #print (" * This food is better") # Now that the best food has been found, check if the movement towards it is safe. # Computes every available move and then check for move priorities. if len(player_goose) > 1: food_movements = move_towards(player_head, player_goose[1], best_food, configuration) else: food_movements = move_towards(player_head, player_head, best_food, configuration) all_movements = get_all_movements(player_head, configuration) # Excluding last movement reverse food_movements = [ move for move in food_movements if move[2] != REVERSE_MOVE[last_move] ] all_movements = [ move for move in all_movements if move[2] != REVERSE_MOVE[last_move] ] #print ("-> Available food moves: {}".format(food_movements)) #print ("-> All moves: {}".format(all_movements)) # Trying to reach goal size of 4 if (len(player_goose) < 4): # 1. Food movements that are safe and not closed for food_movement in food_movements: #print ("Food movement {}".format(food_movement)) if is_safe(food_movement, board) and not is_closed(food_movement, board): #print ("It's safe! Let's move {}!".format(moves[food_movement[2]])) last_move = food_movement[2] return moves[food_movement[2]] # Move here # 2. Any movement safe and not closed for movement in all_movements: #print ("Movement {}".format(movement)) if is_safe(movement, board) and not is_closed(movement, board): #print ("It's safe! Let's move {}!".format(moves[movement[2]])) last_move = movement[2] return moves[movement[2]] # Move here # 3. Food movements half safe and not closed for food_movement in food_movements: if is_half_safe(food_movement, board) and not is_closed(food_movement, board): #print ("Food movement {} is half safe, I'm going {}!".format(food_movement, moves[food_movement[2]])) last_move = food_movement[2] return moves[food_movement[2]] # Move here # 4. Any movement half safe and not closed for movement in all_movements: if is_half_safe(movement, board) and not is_closed(movement, board): #print ("Movement {} is half safe, I'm going {}!".format(movement, moves[movement[2]])) last_move = movement[2] return moves[movement[2]] # Move here # 5. Food movements that are safe for food_movement in food_movements: #print ("Food movement {}".format(food_movement)) if is_safe(food_movement, board): #print ("It's safe! Let's move {}!".format(moves[food_movement[2]])) last_move = food_movement[2] return moves[food_movement[2]] # Move here # 6. Any movement safe for movement in all_movements: #print ("Movement {}".format(movement)) if is_safe(movement, board): #print ("It's safe! Let's move {}!".format(moves[movement[2]])) last_move = movement[2] return moves[movement[2]] # Move here # 7. Food movements half safe for food_movement in food_movements: if is_half_safe(food_movement, board): #print ("Food movement {} is half safe, I'm going {}!".format(food_movement, moves[food_movement[2]])) last_move = food_movement[2] return moves[food_movement[2]] # Move here # 8. Any movement half safe for movement in all_movements: if is_half_safe(movement, board): #print ("Movement {} is half safe, I'm going {}!".format(movement, moves[movement[2]])) last_move = movement[2] return moves[movement[2]] # Move here # Just trying to walk in circles else: # Delete food moves food_coordinates = [] for food in food_race: x_food, y_food = row_col(food, configuration.columns) food_coordinates.append((x_food, y_food)) available_moves = [] for move in all_movements: for (x_food, y_food) in food_coordinates: if (move[0] != x_food) or (move[1] != y_food): available_moves.append(move) # 1. Run in circles if you can circle_move = CIRCLE_MOVE[last_move] for move in available_moves: if (move[2] == circle_move) and (is_safe( move, board)) and not (is_closed(move, board)): last_move = move[2] return moves[move[2]] # 2. Any movement safe and not closed for movement in all_movements: #print ("Movement {}".format(movement)) if is_safe(movement, board) and not is_closed(movement, board): #print ("It's safe! Let's move {}!".format(moves[movement[2]])) last_move = movement[2] return moves[movement[2]] # Move here # 3. Any movement half safe and not closed for movement in all_movements: if is_half_safe(movement, board) and not is_closed(movement, board): #print ("Movement {} is half safe, I'm going {}!".format(movement, moves[movement[2]])) last_move = movement[2] return moves[movement[2]] # Move here # 4. Any movement safe for movement in all_movements: #print ("Movement {}".format(movement)) if is_safe(movement, board): #print ("It's safe! Let's move {}!".format(moves[movement[2]])) last_move = movement[2] return moves[movement[2]] # Move here # 5. Any movement half safe for movement in all_movements: if is_half_safe(movement, board): #print ("Movement {} is half safe, I'm going {}!".format(movement, moves[movement[2]])) last_move = movement[2] return moves[movement[2]] # Move here # Finally, if all moves are unsafe, randomly pick one rand_pick = np.random.randint(4) + 1 last_move = rand_pick #print ("Yeah whatever, I'm going {}".format(moves[rand_pick])) return moves[rand_pick]
def get_head_pos(self): if (len(self._goose) > 0): return row_col(self._goose[0], self._configuration.columns) else: return -1, -1
def _row_col(self, position): return row_col(position, self.columns)
def get_neck_pos(self): if (len(self._goose) > 1): return row_col(self._goose[1], self._configuration.columns) else: return -1, -1
def agent(obs_dict, config_dict): global last_step # State retrieval observation = Observation(obs_dict) configuration = Configuration(config_dict) player_index = observation.index player_goose = observation.geese[player_index] player_head = player_goose[0] player_row, player_column = row_col(player_head, configuration.columns) # Map creation # 0 - empty cells # -1 - obstacles # -4 - possible obstacles # -2 - food # -3 - head # 1,2,3,4 - reachable on the current step cell, number is the id of the first step direction table = np.zeros((7, 11)) legend = {1: 'SOUTH', 2: 'NORTH', 3: 'EAST', 4: 'WEST'} # let's add food to the map for food in observation.food: x, y = row_col(food, configuration.columns) table[x, y] = -2 # food # let's add all cells that are forbidden for i in range(4): opp_goose = observation.geese[i] if len(opp_goose) == 0: continue is_close_to_food = False if i != player_index: x, y = row_col(opp_goose[0], configuration.columns) possible_moves = get_nearest_cells(x, y) # head can move anywhere for x, y in possible_moves: if table[x, y] == -2: is_close_to_food = True table[ x, y] = -4 # Cells where opponent might possibly go next step # usually we ignore the last tail cell but there are exceptions tail_change = -1 if obs_dict['step'] % 40 == 39: tail_change -= 1 # we assume that the goose will eat the food if is_close_to_food: tail_change += 1 if tail_change >= 0: tail_change = None for n in opp_goose[:tail_change]: x, y = row_col(n, configuration.columns) table[x, y] = -1 # forbidden cells # going back is forbidden according to the new rules x, y = row_col(player_head, configuration.columns) if last_step is not None: if last_step == 1: table[(x + 6) % 7, y] = -1 elif last_step == 2: table[(x + 8) % 7, y] = -1 elif last_step == 3: table[x, (y + 10) % 11] = -1 elif last_step == 4: table[x, (y + 12) % 11] = -1 # add head position table[x, y] = -3 # the first step toward the nearest food step = int(find_closest_food(table)) # if there is not available steps try to go to possibly dangerous cell if step not in [1, 2, 3, 4]: x, y = row_col(player_head, configuration.columns) if table[(x + 8) % 7, y] == -4: step = 1 elif table[(x + 6) % 7, y] == -4: step = 2 elif table[x, (y + 12) % 11] == -4: step = 3 elif table[x, (y + 10) % 11] == -4: step = 4 # else - do a random step and lose else: step = np.random.randint(4) + 1 last_step = step return legend[step]
def minDistance(index): if len(heads) <= 0: return 1 pt = np.array(row_col(index, self._columns), np.float) return min([np.linalg.norm(x - pt) for x in heads])