still not working

This commit is contained in:
Heli-o 2024-01-06 19:56:48 +01:00
parent 56b3f0a6f1
commit fc5b73c771
5 changed files with 130 additions and 197 deletions

3
.gitignore vendored
View file

@ -1,2 +1,3 @@
images/*
*.png
*.png
moves/*

Binary file not shown.

Binary file not shown.

156
assets.py
View file

@ -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
View file

@ -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