my battlesnake code
This commit is contained in:
+98
-26
@@ -1,5 +1,5 @@
|
||||
import random
|
||||
from typing import List, Dict
|
||||
from scipy import spatial
|
||||
|
||||
"""
|
||||
This file can be a nice home for your move logic, and to write helper functions.
|
||||
@@ -9,10 +9,8 @@ from the list of possible moves!
|
||||
"""
|
||||
|
||||
|
||||
def avoid_my_neck(my_head: Dict[str, int], my_body: List[dict], possible_moves: List[str]) -> List[str]:
|
||||
def avoid_my_body(my_body, possible_moves: dict) -> list:
|
||||
"""
|
||||
my_head: Dictionary of x/y coordinates of the Battlesnake head.
|
||||
e.g. {"x": 0, "y": 0}
|
||||
my_body: List of dictionaries of x/y coordinates for every segment of a Battlesnake.
|
||||
e.g. [ {"x": 0, "y": 0}, {"x": 1, "y": 0}, {"x": 2, "y": 0} ]
|
||||
possible_moves: List of strings. Moves to pick from.
|
||||
@@ -20,20 +18,70 @@ def avoid_my_neck(my_head: Dict[str, int], my_body: List[dict], possible_moves:
|
||||
|
||||
return: The list of remaining possible_moves, with the 'neck' direction removed
|
||||
"""
|
||||
my_neck = my_body[1] # The segment of body right after the head is the 'neck'
|
||||
remove = []
|
||||
for direction, location in possible_moves.items():
|
||||
if location in my_body:
|
||||
remove.append(direction)
|
||||
|
||||
if my_neck["x"] < my_head["x"]: # my neck is left of my head
|
||||
possible_moves.remove("left")
|
||||
elif my_neck["x"] > my_head["x"]: # my neck is right of my head
|
||||
possible_moves.remove("right")
|
||||
elif my_neck["y"] < my_head["y"]: # my neck is below my head
|
||||
possible_moves.remove("down")
|
||||
elif my_neck["y"] > my_head["y"]: # my neck is above my head
|
||||
possible_moves.remove("up")
|
||||
for direction in remove:
|
||||
del possible_moves[direction]
|
||||
|
||||
return possible_moves
|
||||
|
||||
|
||||
def avoid_walls(board_width: int, board_height: int, possible_moves: dict):
|
||||
remove = []
|
||||
for direction, location in possible_moves.items():
|
||||
x_out_range = (location["x"] < 0 or location["x"] == board_width)
|
||||
y_out_range = (location["y"] < 0 or location["y"] == board_height)
|
||||
if x_out_range or y_out_range:
|
||||
remove.append(direction)
|
||||
|
||||
for direction in remove:
|
||||
del possible_moves[direction]
|
||||
|
||||
return possible_moves
|
||||
|
||||
def avoid_snakes(snakes: list, possible_moves: dict):
|
||||
remove = []
|
||||
for snake in snakes:
|
||||
for direction, location in possible_moves.items():
|
||||
if location in snake["body"]:
|
||||
remove.append(direction)
|
||||
|
||||
remove = set(remove)
|
||||
for direction in remove:
|
||||
del possible_moves[direction]
|
||||
|
||||
return possible_moves
|
||||
|
||||
def get_rarget_close(foods: list, my_head: dict):
|
||||
coordinates = []
|
||||
|
||||
if len(foods) == 0:
|
||||
return None
|
||||
|
||||
for food in foods:
|
||||
coordinates.append((food["x"], food["y"]))
|
||||
|
||||
tree = spatial.KDTree(coordinates)
|
||||
results = tree.query([(my_head["x"], my_head["y"])])[1]
|
||||
|
||||
return foods[results[0]]
|
||||
|
||||
def move_target(possible_moves: list, my_head: dict, target:dict):
|
||||
distance_x = abs(my_head["x"] - target["x"])
|
||||
distance_y = abs(my_head["y"] - target["y"])
|
||||
|
||||
for direction, location in possible_moves.items():
|
||||
new_distance_x = abs(location["x"] - target["x"])
|
||||
new_distance_y = abs(location["y"] - target["y"])
|
||||
|
||||
if new_distance_x < distance_x or new_distance_y < distance_y:
|
||||
return direction
|
||||
|
||||
return list(possible_moves.keys())[0]
|
||||
|
||||
def choose_move(data: dict) -> str:
|
||||
"""
|
||||
data: Dictionary of all Game Board data as received from the Battlesnake Engine.
|
||||
@@ -48,6 +96,10 @@ def choose_move(data: dict) -> str:
|
||||
"""
|
||||
my_head = data["you"]["head"] # A dictionary of x/y coordinates like {"x": 0, "y": 0}
|
||||
my_body = data["you"]["body"] # A list of x/y coordinate dictionaries like [ {"x": 0, "y": 0}, {"x": 1, "y": 0}, {"x": 2, "y": 0} ]
|
||||
board_height = data["board"]["height"]
|
||||
board_width = data["board"]["width"]
|
||||
snakes = data["board"]["snakes"]
|
||||
foods = data["board"]["food"]
|
||||
|
||||
# TODO: uncomment the lines below so you can see what this data looks like in your output!
|
||||
# print(f"~~~ Turn: {data['turn']} Game Mode: {data['game']['ruleset']['name']} ~~~")
|
||||
@@ -55,24 +107,44 @@ def choose_move(data: dict) -> str:
|
||||
# print(f"My Battlesnakes head this turn is: {my_head}")
|
||||
# print(f"My Battlesnakes body this turn is: {my_body}")
|
||||
|
||||
possible_moves = ["up", "down", "left", "right"]
|
||||
#possible_moves = ["up", "down", "left", "right"]
|
||||
|
||||
possible_moves = {
|
||||
"up": {
|
||||
"x": my_head["x"],
|
||||
"y": my_head["y"] + 1
|
||||
},
|
||||
"down": {
|
||||
"x": my_head["x"],
|
||||
"y": my_head["y"] - 1
|
||||
},
|
||||
"left": {
|
||||
"x": my_head["x"] - 1,
|
||||
"y": my_head["y"]
|
||||
},
|
||||
"right": {
|
||||
"x": my_head["x"] + 1,
|
||||
"y": my_head["y"]
|
||||
}
|
||||
}
|
||||
|
||||
# Don't allow your Battlesnake to move back in on it's own neck
|
||||
possible_moves = avoid_my_neck(my_head, my_body, possible_moves)
|
||||
possible_moves = avoid_my_body(my_body, possible_moves)
|
||||
possible_moves = avoid_walls(board_width, board_height, possible_moves)
|
||||
possible_moves = avoid_snakes(snakes, possible_moves)
|
||||
|
||||
# TODO: Using information from 'data', find the edges of the board and don't let your Battlesnake move beyond them
|
||||
# board_height = ?
|
||||
# board_width = ?
|
||||
target = get_rarget_close(foods, my_head)
|
||||
|
||||
# TODO Using information from 'data', don't let your Battlesnake pick a move that would hit its own body
|
||||
|
||||
# TODO: Using information from 'data', don't let your Battlesnake pick a move that would collide with another Battlesnake
|
||||
|
||||
# TODO: Using information from 'data', make your Battlesnake move towards a piece of food on the board
|
||||
|
||||
# Choose a random direction from the remaining possible_moves to move in, and then return that move
|
||||
move = random.choice(possible_moves)
|
||||
# TODO: Explore new strategies for picking a move that are better than random
|
||||
if len(possible_moves) > 0:
|
||||
if target is not None:
|
||||
move = move_target(possible_moves, my_head, target)
|
||||
else:
|
||||
possible_moves = list(possible_moves.keys())
|
||||
move = random.choice(possible_moves)
|
||||
else:
|
||||
move = "up"
|
||||
print("GOING TO LOSE!!")
|
||||
|
||||
print(f"{data['game']['id']} MOVE {data['turn']}: {move} picked from all valid options in {possible_moves}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user