Hive/assets.py

137 lines
4.6 KiB
Python

from enum import Enum
from collections import deque
def get_neighbors(p, q):
directions = [(0, -1), (1, -1), (1, 0), (0, 1), (-1, 1), (-1, 0)]
return [(p + dp, q + dq) for dp, dq in directions]
class Piece:
def get_valid_jumps() -> list:
raise NotImplementedError
class Bee(Piece):
def __init__(self, board, p, q, team):
self.board = board
self.p = p
self.q = q
self.team = team # 'team' should be 'upper' or 'lower' based on the piece case.
def get_valid_jumps(self) -> list:
# The bee can move to an adjacent empty space.
valid_moves = []
for neighbor in get_neighbors(self.p, self.q):
# Check if the neighbor is within the bounds of the board and is empty
if neighbor in self.board and self.board[neighbor] == "":
valid_moves.append(neighbor)
return valid_moves
class Beetle(Piece):
def __init__(self, p, q, team):
self.p = p
self.q = q
self.team = team
def get_valid_jumps(self, board):
# The beetle can move to an adjacent space whether it is empty or not.
valid_moves = get_neighbors(self.p, self.q)
return valid_moves
class Spider(Piece):
def __init__(self, p, q, team):
self.p = p
self.q = q
self.team = team
def get_valid_jumps(self, board):
# Use BFS to find all tiles exactly three moves away
start = (self.p, self.q)
visited = set() # Keep track of visited tiles
queue = deque([(start, 0)]) # Queue of (position, distance)
valid_moves = []
while queue:
current_position, current_distance = queue.popleft()
if current_distance == 3:
# We have found a tile exactly three moves away
valid_moves.append(current_position)
continue # We don't want to move further from this tile
if current_position in visited:
continue # Already visited this tile
visited.add(current_position)
# Get all neighboring positions
for neighbor in get_neighbors(*current_position):
if (
neighbor in board
and board[neighbor] == ""
and neighbor not in visited
):
queue.append((neighbor, current_distance + 1))
return valid_moves
class Grasshopper(Piece):
def __init__(self, p, q, team):
self.p = p
self.q = q
self.team = team
def get_valid_jumps(self, board):
# Generator function to yield valid moves
def generate_moves():
# Check each direction for possible jumps
for dp, dq in get_neighbors(0, 0): # Use (0, 0) to get direction vectors
pos = (self.p + dp, self.q + dq)
# Continue in the direction until we find a piece to jump over
while pos in board and board[pos] != "":
pos = (pos[0] + dp, pos[1] + dq)
# If we jumped over at least one piece and landed on an empty space, yield the move
if (
pos in board
and board[pos] == ""
and (pos[0] != self.p or pos[1] != self.q)
):
yield pos
return list(generate_moves())
class Ant(Piece):
def __init__(self, p, q, team):
self.p = p
self.q = q
self.team = team
def get_valid_jumps(self, board):
visited = set() # Keep track of visited nodes to prevent cycles
# Recursive function to explore all valid moves
def explore(p, q):
for dp, dq in get_neighbors(0, 0): # Get direction vectors
new_p, new_q = p + dp, q + dq
next_pos = (new_p, new_q)
# Continue in this direction while there are pieces to slide around
while (
next_pos in board
and board[next_pos] != ""
and next_pos not in visited
):
visited.add(next_pos)
next_pos = (next_pos[0] + dp, next_pos[1] + dq)
# If we found an empty space, add it as a valid move and explore from there
if next_pos in board and board[next_pos] == "":
visited.add(next_pos)
yield next_pos
# Explore further moves from this new position
yield from explore(next_pos[0], next_pos[1])
# Start exploring from the Ant's current position
return list(explore(self.p, self.q))