~zstix/pysnake

2b6f586097e61cb1c6e6a045ddf69d5203913865 — Zack Stickles 5 months ago e3b6f7b
starting to reimplement with types
3 files changed, 56 insertions(+), 9 deletions(-)

M board.py
M logic.py
M state.py
M board.py => board.py +13 -0
@@ 1,4 1,17 @@
from copy import deepcopy
from typing import List, Union
from state import Snake, Pos

# TODO: notes
def get_snake_bodies_2(snakes: List[Snake], you: Union[Snake, None]=None) -> List[Pos]:
    bodies = []
    for snake in snakes:
        body = deepcopy(snake[1])
        if you != None and snake == you:
            bodies += body[1:]
        else:
            bodies += body
    return bodies

def get_snake_bodies(snakes, you=None):
    """

M logic.py => logic.py +35 -1
@@ 4,12 4,46 @@ import itertools
from typing import Literal, Tuple, List
import bitboard
from state import State
from board import is_snake_in_board, get_snake_bodies, get_next_pos
from board import is_snake_in_board, get_snake_bodies, get_snake_bodies_2, get_next_pos

Dir = Literal["up", "down", "left", "right"]
Move = Tuple[str, Dir]

# TODO: advance_state that handles new state format
def advance_state_2(prev_state: State, moves: List[Move]) -> State:
    snakes = deepcopy(prev_state["snakes"]) # TODO: verify this copy is correct
    food = deepcopy(prev_state["food"]) # TODO: verify this copy is correct

    # move snakes
    for [snake_id, body] in snakes:
        move = None
        for [move_snake_id, snake_move] in moves:
            if move_snake_id == snake_id:
                move = snake_move
                break
        head = get_next_pos(prev_state["board"], body[0], move)
        body = [head] + body # NOTE: might be a more efficient way to do this

    # kill off snakes that run into each other
    # TODO: handle head-to-head interactions
    alive_snakes = []
    for snake in snakes:
        if snake[1][0] not in get_snake_bodies_2(snakes, snake):
            alive_snakes.append(snake)


    # handle food / growth interactions
    # loop through food
    # if food is at head of snake, remove snake and keep snake at length
    # if snake hasn't eaten, remove tail

    return {
        "turn": prev_state["turn"] + 1,
        "board": prev_state["board"],
        "hazards": prev_state["hazards"],
        "food": [], # TODO
        "snakes": alive_snakes,
    }

def advance_state(state, moves: List[Move]):
    new_state = deepcopy(state) # gross

M state.py => state.py +8 -8
@@ 1,14 1,7 @@
from typing import Dict, List, Tuple, TypedDict

Pos = Tuple[int, int]
Snake = Tuple[str, List[Pos]]

def dict_to_tuple(pos: Dict[str, int]) -> Pos:
    """
    Convert a dictionary of `{"x": 0, "y": 0}` to a tuple of `(0, 0)` for more
    efficient (and immutable) position storage.
    """
    return (pos["x"], pos["y"])
Snake = Tuple[str, List[Pos]] # TODO: health?

class State(TypedDict):
    """


@@ 21,6 14,13 @@ class State(TypedDict):
    hazards: List[Pos]
    snakes: List[Snake]

def dict_to_tuple(pos: Dict[str, int]) -> Pos:
    """
    Convert a dictionary of `{"x": 0, "y": 0}` to a tuple of `(0, 0)` for more
    efficient (and immutable) position storage.
    """
    return (pos["x"], pos["y"])

def parse_state(state) -> State:
    """
    Turn the game state object from the Battlesnake API into the format used