my battlesnake code

This commit is contained in:
2022-01-24 17:12:11 +01:00
parent ad77bbc1f2
commit 11c1adf96c
2 changed files with 100 additions and 28 deletions
+2 -2
View File
@@ -24,8 +24,8 @@ def handle_info():
print("INFO")
return {
"apiversion": "1",
"author": "", # TODO: Your Battlesnake Username
"color": "#888888", # TODO: Personalize
"author": "daniel156161", # TODO: Your Battlesnake Username
"color": "#00ff00", # TODO: Personalize
"head": "default", # TODO: Personalize
"tail": "default", # TODO: Personalize
}
+98 -26
View File
@@ -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}")