From 11c1adf96ca4c66577e360bd684db62ee9576bb7 Mon Sep 17 00:00:00 2001 From: Daniel Dolezal Date: Mon, 24 Jan 2022 17:12:11 +0100 Subject: [PATCH] my battlesnake code --- server.py | 4 +- server_logic.py | 124 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 100 insertions(+), 28 deletions(-) diff --git a/server.py b/server.py index b02076a..7715b58 100644 --- a/server.py +++ b/server.py @@ -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 } diff --git a/server_logic.py b/server_logic.py index 9b0c7dd..9a6f1d0 100644 --- a/server_logic.py +++ b/server_logic.py @@ -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}")