still not working
This commit is contained in:
parent
56b3f0a6f1
commit
fc5b73c771
5 changed files with 130 additions and 197 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
images/*
|
||||
*.png
|
||||
*.png
|
||||
moves/*
|
BIN
__pycache__/assets.cpython-311.pyc
Normal file
BIN
__pycache__/assets.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
156
assets.py
156
assets.py
|
@ -1,137 +1,31 @@
|
|||
from enum import Enum
|
||||
from collections import deque
|
||||
from player import Player
|
||||
import ast
|
||||
|
||||
|
||||
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]
|
||||
def update_player(b, m, t, mp, rp):
|
||||
p = Player("p", t, 13, mp, rp)
|
||||
p.myMove = m
|
||||
p.board = b
|
||||
p.update()
|
||||
return p
|
||||
|
||||
|
||||
class Piece:
|
||||
def get_valid_jumps() -> list:
|
||||
raise NotImplementedError
|
||||
def insert():
|
||||
board = input("insert board: ").strip()
|
||||
move = input("insert move: ").strip()
|
||||
mp = input("insert my team: ").strip()
|
||||
rp = input("insert rival team: ").strip()
|
||||
team = input("insert team: ").strip()
|
||||
|
||||
board = ast.literal_eval(board.split(" = ")[1])
|
||||
move = ast.literal_eval(move.split(" = ")[1])
|
||||
team = ast.literal_eval(team.split(" = ")[1])
|
||||
mp = ast.literal_eval(mp.split(" = ")[1])
|
||||
rp = ast.literal_eval(rp.split(" = ")[1])
|
||||
|
||||
p = update_player(board, move, team, mp, rp)
|
||||
return p, [board, move, team, mp, rp]
|
||||
|
||||
|
||||
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))
|
||||
def update(pkg):
|
||||
return update_player(*pkg)
|
||||
|
|
168
player.py
168
player.py
|
@ -1,21 +1,38 @@
|
|||
import base as Base
|
||||
import copy, random, time, math
|
||||
import copy
|
||||
import random
|
||||
import time
|
||||
import math
|
||||
from PIL import Image, ImageDraw
|
||||
from collections import deque
|
||||
|
||||
|
||||
# Player template for HIVE --- ALP semestral work
|
||||
# Vojta Vonasek, 2023
|
||||
|
||||
|
||||
# PUT ALL YOUR IMPLEMENTATION INTO THIS FILE
|
||||
|
||||
def inBoard(p, q, size):
|
||||
""" return True if (p,q) is valid coordinate """
|
||||
return (q >= 0) and (q < size) and (p >= -(q//2)) and (p < (size - q//2))
|
||||
|
||||
|
||||
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]
|
||||
|
||||
|
||||
def has_neighbors(p, q, board, pp, pq):
|
||||
# Check if the position (p, q) has at least one neighbor
|
||||
board = copy.deepcopy(board)
|
||||
board[pp][pq] = ""
|
||||
for dp, dq in get_neighbors(0, 0):
|
||||
neighbor_p, neighbor_q = p + dp, q + dq
|
||||
if inBoard(neighbor_p, neighbor_q, 13) and board[neighbor_p][neighbor_q] != "":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Piece:
|
||||
def get_piece_info(self, myisupper):
|
||||
class_to_letter = {
|
||||
|
@ -29,10 +46,10 @@ class Piece:
|
|||
if not myisupper:
|
||||
letter = letter.lower()
|
||||
return [letter, self.p, self.q]
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return ",".join(map(str, self.get_piece_info(True)+[self.team]))
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
|
@ -49,7 +66,8 @@ class Piece:
|
|||
board_copy = {p: {q: board[p][q] for q in board[p]} for p in board}
|
||||
|
||||
# See if the hive falls apart without the piece (if so, then the move wasnt valid)
|
||||
board_copy[self.p][self.q] = None # Remove the piece from its current position
|
||||
# Remove the piece from its current position
|
||||
board_copy[self.p][self.q] = None
|
||||
|
||||
# Get all remaining pieces on the board
|
||||
remaining_pieces = [
|
||||
|
@ -102,7 +120,9 @@ class Beetle(Piece):
|
|||
|
||||
def get_valid_jumps(self, board):
|
||||
valid_moves = get_neighbors(self.p, self.q)
|
||||
return valid_moves
|
||||
checked = [v for v in valid_moves if has_neighbors(
|
||||
v[0], v[1], board, self.p, self.q)]
|
||||
return checked
|
||||
|
||||
|
||||
class Spider(Piece):
|
||||
|
@ -120,7 +140,8 @@ class Spider(Piece):
|
|||
while queue:
|
||||
current_position, current_distance = queue.popleft()
|
||||
if current_distance == 3:
|
||||
valid_moves.append(current_position)
|
||||
if has_neighbors(*current_position, board, self.p, self.q):
|
||||
valid_moves.append(current_position)
|
||||
continue
|
||||
|
||||
if current_position in visited:
|
||||
|
@ -128,13 +149,11 @@ class Spider(Piece):
|
|||
|
||||
visited.add(current_position)
|
||||
|
||||
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))
|
||||
for p, q in get_neighbors(*current_position):
|
||||
next_pos = (p, q)
|
||||
if (inBoard(p, q, 13) and board[p][q] == "" and next_pos not in visited
|
||||
and has_neighbors(p, q, board, self.p, self.q)):
|
||||
queue.append((next_pos, current_distance + 1))
|
||||
|
||||
return valid_moves
|
||||
|
||||
|
@ -170,27 +189,34 @@ class Ant(Piece):
|
|||
self.team = team
|
||||
|
||||
def get_valid_jumps(self, board):
|
||||
visited = set() # Keep track of visited nodes to prevent cycles
|
||||
visited = set()
|
||||
|
||||
# Just a recursive, eh?
|
||||
def explore(p, q):
|
||||
def explore(p, q, depth=0):
|
||||
if depth >= 5: # Limit recursion depth
|
||||
return []
|
||||
|
||||
valid_moves = []
|
||||
for dp, dq in get_neighbors(0, 0):
|
||||
new_p, new_q = p + dp, q + dq
|
||||
next_pos = (new_p, new_q)
|
||||
while (
|
||||
next_pos in board
|
||||
and board[next_pos] != ""
|
||||
and next_pos not in visited
|
||||
):
|
||||
|
||||
while (inBoard(next_pos[0], next_pos[1], 13) and
|
||||
board[next_pos[0]][next_pos[1]] != "" and
|
||||
next_pos not in visited):
|
||||
visited.add(next_pos)
|
||||
next_pos = (next_pos[0] + dp, next_pos[1] + dq)
|
||||
if next_pos in board and board[next_pos] == "":
|
||||
visited.add(next_pos)
|
||||
yield next_pos
|
||||
yield from explore(next_pos[0], next_pos[1])
|
||||
|
||||
valid_moves = list(explore(self.p, self.q))
|
||||
return valid_moves
|
||||
if (inBoard(next_pos[0], next_pos[1], 13) and
|
||||
board[next_pos[0]][next_pos[1]] == "" and
|
||||
has_neighbors(next_pos[0], next_pos[1], board, self.p, self.q)):
|
||||
visited.add(next_pos)
|
||||
valid_moves.append(next_pos)
|
||||
valid_moves.extend(
|
||||
explore(next_pos[0], next_pos[1], depth + 1))
|
||||
|
||||
return valid_moves
|
||||
|
||||
return explore(self.p, self.q)
|
||||
|
||||
|
||||
class Player(Base.Board):
|
||||
|
@ -203,7 +229,7 @@ class Player(Base.Board):
|
|||
self.playerName = playerName
|
||||
self.myIsUpper = myIsUpper
|
||||
self.algorithmName = "just roll the dice, eh?"
|
||||
self.transated_board = dict()
|
||||
self.tboard = dict()
|
||||
self.can_place = lambda: sum([v for v in self.myPieces.values()])
|
||||
|
||||
def getAllEmptyCells(self):
|
||||
|
@ -241,9 +267,11 @@ class Player(Base.Board):
|
|||
if tile_content.isalpha():
|
||||
topmost_piece_letter = tile_content[-1]
|
||||
is_upper = topmost_piece_letter.isupper()
|
||||
piece_class = piece_class_mapping.get(topmost_piece_letter.upper())
|
||||
piece_class = piece_class_mapping.get(
|
||||
topmost_piece_letter.upper())
|
||||
if piece_class:
|
||||
piece_instance = piece_class(p, q, is_upper == self.myIsUpper)
|
||||
piece_instance = piece_class(
|
||||
p, q, is_upper == self.myIsUpper)
|
||||
translated_board[p][q] = piece_instance
|
||||
total_pieces_count += 1
|
||||
if is_upper == self.myIsUpper:
|
||||
|
@ -258,7 +286,6 @@ class Player(Base.Board):
|
|||
@property
|
||||
def queen_placed(self):
|
||||
return any(isinstance(p, Bee) for p in self.myPieces)
|
||||
|
||||
|
||||
def random_piece(self, pieces):
|
||||
return random.choice(pieces) if pieces else None
|
||||
|
@ -275,6 +302,7 @@ class Player(Base.Board):
|
|||
piece_class = self.get_piece_class(piece_letter)
|
||||
unplaced_pieces.append(piece_class(None, None, True))
|
||||
return unplaced_pieces
|
||||
|
||||
def get_valid_placements(self, translated_board, piece_to_place):
|
||||
valid_placements = []
|
||||
|
||||
|
@ -303,27 +331,28 @@ class Player(Base.Board):
|
|||
valid_placements.append((p, q))
|
||||
|
||||
return valid_placements
|
||||
|
||||
|
||||
def mover(self):
|
||||
movable_pieces = [
|
||||
piece
|
||||
for row in self.translated_board.values()
|
||||
for piece in row.values()
|
||||
if piece and piece.team and piece.validate_jumps(self.translated_board)
|
||||
]
|
||||
chosen_piece = self.random_piece(movable_pieces) # -> can be None, usually the cause for an error
|
||||
movable_pieces = list()
|
||||
for row in self.tboard.values():
|
||||
for piece in row.values():
|
||||
if piece and piece.team:
|
||||
jumps = piece.validate_jumps(self.tboard)
|
||||
if jumps:
|
||||
movable_pieces.append((piece, jumps))
|
||||
|
||||
# -> can be None, usually the cause for an error
|
||||
chosen_piece = self.random_piece(movable_pieces)
|
||||
if chosen_piece:
|
||||
new_p, new_q = random.choice(
|
||||
chosen_piece.validate_jumps(self.translated_board)
|
||||
)
|
||||
return chosen_piece.get_piece_info(self.myIsUpper) + [new_p, new_q]
|
||||
|
||||
new_p, new_q = random.choice(chosen_piece[1])
|
||||
return chosen_piece[0].get_piece_info(self.myIsUpper) + [new_p, new_q]
|
||||
return "failed"
|
||||
|
||||
def placer(self):
|
||||
piece_to_place = self.random_piece(self.get_unplaced_pieces())
|
||||
if piece_to_place is None:
|
||||
return self.mover()
|
||||
if piece_to_place:
|
||||
valid_placements = self.get_valid_placements(self.translated_board, piece_to_place)
|
||||
valid_placements = self.get_valid_placements(
|
||||
self.tboard, piece_to_place)
|
||||
new_p, new_q = random.choice(valid_placements)
|
||||
return piece_to_place.get_piece_info(self.myIsUpper)[:1] + [
|
||||
None,
|
||||
|
@ -333,46 +362,55 @@ class Player(Base.Board):
|
|||
]
|
||||
|
||||
def update(self):
|
||||
self.translated_board, total_pieces_count, my_pieces_count = self.translate_board(self.board)
|
||||
trb, total_pieces_count, my_pieces_count = self.translate_board(
|
||||
self.board)
|
||||
self.tboard = trb
|
||||
p = self
|
||||
return total_pieces_count, my_pieces_count
|
||||
|
||||
def move(self):
|
||||
total_pieces_count, my_pieces_count = self.update()
|
||||
|
||||
bee_unplaced = "q" in [k.lower() for k in self.myPieces.keys()] and {k.lower(): v for k,v in self.myPieces.items()}["q"]!=0
|
||||
bee_unplaced = "q" in [k.lower() for k in self.myPieces.keys()] and {
|
||||
k.lower(): v for k, v in self.myPieces.items()}["q"] != 0
|
||||
|
||||
if bee_unplaced and (total_pieces_count > 3 or random.choice([True, False])):
|
||||
queen_bee = self.get_piece_class('Q')(None, None, True)
|
||||
valid_placements = self.get_valid_placements(self.translated_board, queen_bee)
|
||||
valid_placements = self.get_valid_placements(
|
||||
self.tboard, queen_bee)
|
||||
if valid_placements:
|
||||
new_p, new_q = random.choice(valid_placements)
|
||||
return queen_bee.get_piece_info(self.myIsUpper)[:1]+ [None, None, new_p, new_q]
|
||||
return queen_bee.get_piece_info(self.myIsUpper)[:1] + [None, None, new_p, new_q]
|
||||
|
||||
if total_pieces_count == 0:
|
||||
elif total_pieces_count == 0:
|
||||
piece_to_place = self.random_piece(self.get_unplaced_pieces())
|
||||
return (
|
||||
piece_to_place.get_piece_info(self.myIsUpper)[:1] + [None, None, 3, 6]
|
||||
piece_to_place.get_piece_info(self.myIsUpper)[
|
||||
:1] + [None, None, 3, 6]
|
||||
)
|
||||
|
||||
elif total_pieces_count == 1:
|
||||
for _, row in self.translated_board.items():
|
||||
for _, row in self.tboard.items():
|
||||
for _, piece in row.items():
|
||||
if piece:
|
||||
adjacent_positions = get_neighbors(piece.p, piece.q)
|
||||
random_position = self.random_piece(adjacent_positions)
|
||||
piece_to_place = self.random_piece(self.get_unplaced_pieces())
|
||||
piece_to_place = self.random_piece(
|
||||
self.get_unplaced_pieces())
|
||||
return (
|
||||
piece_to_place.get_piece_info(self.myIsUpper)[:1]
|
||||
+ [None, None, *random_position]
|
||||
)
|
||||
|
||||
elif self.myMove <= 4:
|
||||
return self.placer()
|
||||
return self.placer()
|
||||
|
||||
choice = random.choice(["move", "place"])
|
||||
print(choice)
|
||||
if choice == "place" and bool(self.can_place):
|
||||
return self.placer()
|
||||
else:
|
||||
move_or_place = random.choice(["move", "place"]) if self.can_place else "move"
|
||||
if move_or_place == "place":
|
||||
return self.placer()
|
||||
else:
|
||||
return self.mover()
|
||||
return []
|
||||
return self.mover()
|
||||
|
||||
|
||||
def updatePlayers(move, activePlayer, passivePlayer):
|
||||
|
@ -421,13 +459,13 @@ if __name__ == "__main__":
|
|||
move = P1.move()
|
||||
print("P1 returned", move)
|
||||
updatePlayers(move, P1, P2) # update P1 and P2 according to the move
|
||||
filename = "move-{:03d}-player1.png".format(moveIdx)
|
||||
filename = "moves/move-{:03d}-player1.png".format(moveIdx)
|
||||
P1.saveImage(filename)
|
||||
|
||||
move = P2.move()
|
||||
print("P2 returned", move)
|
||||
updatePlayers(move, P2, P1) # update P2 and P1 according to the move
|
||||
filename = "move-{:03d}-player2.png".format(moveIdx)
|
||||
filename = "moves/move-{:03d}-player2.png".format(moveIdx)
|
||||
P1.saveImage(filename)
|
||||
|
||||
moveIdx += 1
|
||||
|
|
Loading…
Add table
Reference in a new issue