chat gpt is probably god? hopefully works, untested

This commit is contained in:
Heli-o 2024-01-01 19:03:26 +01:00
parent 28fcbd4a0d
commit 3412605b1e
5 changed files with 688 additions and 70 deletions

129
assets.py
View file

@ -1,34 +1,137 @@
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():
pass
def get_valid_jumps() -> list:
raise NotImplementedError
class Bee(Piece):
pass
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):
pass
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):
pass
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):
pass
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):
pass
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
class PieceTranslator(Enum):
q = Bee
b = Beetle
s = Spider
g = Grasshopper
a = Ant
# 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))

56
modified_assets.py Normal file
View file

@ -0,0 +1,56 @@
from enum import Enum
class Piece:
def get_valid_jumps() -> list:
raise NotImplementedError
class Bee(Piece):
pass
class Beetle(Piece):
pass
class Spider(Piece):
pass
class Grasshopper(Piece):
pass
class Ant(Piece):
pass
class PieceTranslator(Enum):
q = Bee
b = Beetle
s = Spider
g = Grasshopper
a = Ant
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):
# 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
get_neighbors = <function get_neighbors at 0x7eb8eda90940>

55
modified_assets_v2.py Normal file
View file

@ -0,0 +1,55 @@
from enum import Enum
class Piece:
def get_valid_jumps() -> list:
raise NotImplementedError
class Bee(Piece):
pass
class Beetle(Piece):
pass
class Spider(Piece):
pass
class Grasshopper(Piece):
pass
class Ant(Piece):
pass
class PieceTranslator(Enum):
q = Bee
b = Beetle
s = Spider
g = Grasshopper
a = Ant
class Bee(Piece):
def __init__(self, p, q, team):
self.p = p
self.q = q
self.team = team # 'team' is a boolean where True represents one team and False represents the other.
def get_valid_jumps(self, board):
# 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 board and board[neighbor] == '':
valid_moves.append(neighbor)
return valid_moves
def get_neighbors(p, q):
get_neighbors.<locals>.<listcomp>

335
player.py
View file

@ -1,6 +1,7 @@
import base as Base
import copy, random, time, math
from PIL import Image, ImageDraw
from collections import deque
# Player template for HIVE --- ALP semestral work
@ -9,75 +10,296 @@ from PIL import Image, ImageDraw
# PUT ALL YOUR IMPLEMENTATION INTO THIS FILE
class Player(Base.Board):
def __init__(self, playerName, myIsUpper, size, myPieces, rivalPieces): #do not change this line
Base.Board.__init__(self, myIsUpper, size, myPieces, rivalPieces) #do not change this line
self.playerName = playerName
self.algorithmName = "myGreatMethod"
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_piece_info(self):
# Convert the class name to the corresponding letter
class_to_letter = {
'Bee': 'Q',
'Beetle': 'B',
'Spider': 'S',
'Grasshopper': 'G',
'Ant': 'A'
}
letter = class_to_letter[self.__class__.__name__]
if not self.team: # If the piece is not on the player's team, make it lowercase
letter = letter.lower()
return [letter, self.p, self.q]
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))
class Player(Base.Board):
def __init__(
self, playerName, myIsUpper, size, myPieces, rivalPieces
): # do not change this line
Base.Board.__init__(
self, myIsUpper, size, myPieces, rivalPieces
) # do not change this line
self.playerName = playerName
self.algorithmName = "just roll the dice, eh?"
def getAllEmptyCells(self):
result = []
for p in self.board:
for q in self.board[p]:
if self.isEmpty(p,q, self.board):
result.append( [p,q] )
if self.isEmpty(p, q, self.board):
result.append([p, q])
return result
def getAllNonemptyCells(self):
def getAllNonemptyCells(self):
result = []
for p in self.board:
for q in self.board[p]:
if not self.isEmpty(p,q, self.board):
result.append( [p,q] )
if not self.isEmpty(p, q, self.board):
result.append([p, q])
return result
def translate_board(self, board):
# Create a dictionary to map letters to piece classes
piece_class_mapping = {
'Q': Bee,
'B': Beetle,
'S': Spider,
'G': Grasshopper,
'A': Ant
}
translated_board = {p: {} for p in board}
total_pieces_count = 0 # To count the total number of pieces on the board
my_pieces_count = 0 # To count the number of your pieces on the board
for p, row in board.items():
for q, piece_letter in row.items():
if piece_letter.isalpha(): # Check if it's a letter representing a piece
is_upper = piece_letter.isupper()
piece_class = piece_class_mapping.get(piece_letter.upper())
if piece_class:
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:
my_pieces_count += 1
else:
translated_board[p][q] = piece_letter
else:
translated_board[p][q] = piece_letter
return translated_board, total_pieces_count, my_pieces_count
@property
def queen_placed(self):
# Check if the queen is placed
return any(isinstance(p, Bee) for p in self.myPieces)
def get_piece_class(self, letter):
# Maps letter to piece class
return {
'Q': Bee,
'B': Beetle,
'S': Spider,
'G': Grasshopper,
'A': Ant
}.get(letter)
def get_unplaced_pieces(self):
# Return a list of unplaced pieces
unplaced_pieces = []
for piece_letter, count in self.myPieces.items():
for _ in range(count):
piece_class = self.get_piece_class(piece_letter)
unplaced_pieces.append(piece_class(None, None, True))
return unplaced_pieces
def move(self):
""" return [animal, oldP, oldQ, newP, newQ], or [animal, None, None, newP, newQ] or [] """
translated_board, total_pieces_count, _ = self.translate_board(self.board)
#the following code just randomly places (ignoring all the rules) some random figure at the board
emptyCells = self.getAllEmptyCells()
if len(emptyCells) == 0:
return []
randomCell = emptyCells[ random.randint(0, len(emptyCells)-1) ]
randomP, randomQ = randomCell
# Randomly choose a piece to place or move
def choose_random_piece(pieces):
return random.choice(pieces) if pieces else None
for animal in self.myPieces:
if self.myPieces[animal] > 0: #is this animal still available? if so, let's place it
return [ animal, None, None, randomP, randomQ ]
# If we're the first player and no pieces are on the board, place a random piece at the center
if total_pieces_count == 0:
piece_to_place = choose_random_piece(self.get_unplaced_pieces())
return piece_to_place.get_piece_info()[:1] + [None, None, 3, 6] if piece_to_place else []
# If we're the second player, place next to the first player's piece
elif total_pieces_count == 1:
for _, row in translated_board.items():
for _, piece in row.items():
if piece: # Found the first player's piece
adjacent_positions = get_neighbors(piece.p, piece.q)
random_position = choose_random_piece(adjacent_positions)
piece_to_place = choose_random_piece(self.get_unplaced_pieces())
return piece_to_place.get_piece_info()[:1] + [None, None, *random_position] if piece_to_place else []
# After the queen is placed or after the 4th turn, randomly choose between moving and placing a piece
elif self.queen_placed or total_pieces_count >= 8:
move_or_place = random.choice(["move", "place"])
if move_or_place == "move":
movable_pieces = [p for p in translated_board.values() if p.get_valid_jumps(translated_board)]
chosen_piece = choose_random_piece(movable_pieces)
if chosen_piece:
new_p, new_q = random.choice(chosen_piece.get_valid_jumps(translated_board))
return chosen_piece.get_piece_info() + [new_p, new_q]
else:
piece_to_place = choose_random_piece(self.get_unplaced_pieces())
if piece_to_place:
valid_placements = self.get_valid_placements(translated_board, piece_to_place)
new_p, new_q = random.choice(valid_placements) if valid_placements else (None, None)
return piece_to_place.get_piece_info()[:1] + [None, None, new_p, new_q]
# If it's not possible to move or place a piece, pass the turn
return []
#all animals are places, let's move some randomly (again, while ignoring all rules)
allFigures = self.getAllNonemptyCells()
randomCell = allFigures[ random.randint(0, len(allFigures)-1) ]
randomFigureP, randomFigureQ = randomCell
#determine which animal is at randomFigureP, randomFigureQ
animal = self.board[ randomFigureP ][ randomFigureQ ][-1] # [-1] means the last letter
return [animal, randomFigureP, randomFigureQ, randomP, randomQ ]
def updatePlayers(move, activePlayer, passivePlayer):
""" write move made by activePlayer player
this method assumes that all moves are correct, no checking is made
"""write move made by activePlayer player
this method assumes that all moves are correct, no checking is made
"""
if len(move) == 0:
return
animal, p,q, newp, newq = move
animal, p, q, newp, newq = move
if p == None and q == None:
#placing new animal
activePlayer.myPieces[animal]-=1
# placing new animal
activePlayer.myPieces[animal] -= 1
passivePlayer.rivalPieces = activePlayer.myPieces.copy()
else:
#just moving animal
#delete its old position
# just moving animal
# delete its old position
activePlayer.board[p][q] = activePlayer.board[p][q][:-1]
passivePlayer.board[p][q] = passivePlayer.board[p][q][:-1]
@ -85,32 +307,36 @@ def updatePlayers(move, activePlayer, passivePlayer):
passivePlayer.board[newp][newq] += animal
if __name__ == "__main__":
boardSize = 13
smallFigures = { "q":1, "a":2, "b":2, "s":2, "g":2 } #key is animal, value is how many is available for placing
bigFigures = { figure.upper(): smallFigures[figure] for figure in smallFigures } #same, but with upper case
smallFigures = {
"q": 1,
"a": 2,
"b": 2,
"s": 2,
"g": 2,
} # key is animal, value is how many is available for placing
bigFigures = {
figure.upper(): smallFigures[figure] for figure in smallFigures
} # same, but with upper case
P1 = Player("player1", False, 13, smallFigures, bigFigures)
P2 = Player("player2", True, 13, bigFigures, smallFigures)
filename = "begin.png"
P1.saveImage(filename)
moveIdx = 0
while True:
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)
P1.saveImage(filename)
updatePlayers(move, P1, P2) # update P1 and P2 according to the move
filename = "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
updatePlayers(move, P2, P1) # update P2 and P1 according to the move
filename = "move-{:03d}-player2.png".format(moveIdx)
P1.saveImage(filename)
@ -121,8 +347,3 @@ if __name__ == "__main__":
if moveIdx > 50:
print("End of the test game")
break

183
spider.py Normal file
View file

@ -0,0 +1,183 @@
import copy
import math
from PIL import Image, ImageDraw
class Board:
def __init__(self, size=0):
self.size = size
self.board = {}
# create empty board as a dictionary
self.b2 = {}
for p in range(-self.size, self.size):
for q in range(-self.size, self.size):
if self.inBoard(p, q):
if not p in self.board:
self.board[p] = {}
self.board[p][q] = 0
if not q in self.b2:
self.b2[q] = {}
self.b2[q][p] = 0
# this is for visualization and to synchronize colors between png/js
self._colors = {}
self._colors[-1] = "#fdca40" # sunglow
self._colors[0] = "#ffffff" # white
self._colors[1] = "#947bd3" # medium purple
self._colors[2] = "#ff0000" # red
self._colors[3] = "#00ff00" # green
self._colors[4] = "#0000ff" # blue
self._colors[5] = "#566246" # ebony
self._colors[6] = "#a7c4c2" # opan
self._colors[7] = "#ADACB5" # silver metalic
self._colors[8] = "#8C705F" # liver chestnut
self._colors[9] = "#FA7921" # pumpkin
self._colors[10] = "#566E3D" # dark olive green
def inBoard(self, p, q):
"""return True if (p,q) is valid coordinate"""
return (
(q >= 0)
and (q < self.size)
and (p >= -(q // 2))
and (p < (self.size - q // 2))
)
def rotateRight(self, p, q):
pp = -q
qq = p + q
return pp, qq
def rotateLeft(self, p, q):
pp = p + q
qq = -p
return pp, qq
def saveImage(self, filename):
"""draw actual board to png"""
cellRadius = 60
cellWidth = int(cellRadius * (3**0.5))
cellHeight = 2 * cellRadius
width = cellWidth * self.size + cellRadius * 3
height = cellHeight * self.size
img = Image.new("RGB", (width, height), "white")
draw = ImageDraw.Draw(img)
lineColor = (50, 50, 50)
for p in self.board:
for q in self.board[p]:
cx = cellRadius * (math.sqrt(3) * p + math.sqrt(3) / 2 * q) + cellRadius
cy = cellRadius * (0 * p + 3 / 2 * q) + cellRadius
pts = []
for a in [30, 90, 150, 210, 270, 330]:
nx = cx + cellRadius * math.cos(a * math.pi / 180)
ny = cy + cellRadius * math.sin(a * math.pi / 180)
pts.append(nx)
pts.append(ny)
color = "#ff00ff" # pink is for values out of range -1,..10
if self.board[p][q] in self._colors:
color = self._colors[self.board[p][q]]
draw.polygon(pts, fill=color)
pts.append(pts[0])
pts.append(pts[1])
draw.line(pts, fill="black", width=1)
draw.text(
[cx - 3, cy - 3], "{} {}".format(p, q), fill="black", anchor="m"
)
img.save(filename)
def loadBoard(self, filename):
board = {}
fread = open(filename, "rt")
size = -1
for line in fread:
p, q, value = list(map(int, line.strip().split()))
size = max(size, q)
if p not in board:
board[p] = {}
board[p][q] = value
fread.close()
self.board = board
self.size = size + 1
import sys
# alternativa: nacteni ze souboru
b = Board()
b.loadBoard(sys.argv[1])
# prochazeni radku/sloupce:
b_copy = {}
for p in b.board:
b_copy[p] = {}
for q in b.board[p]:
b_copy[p][q] = b.board[p][q]
if b.board[p][q] == 2:
spider_p = p
spider_q = q
smer = ((0, -1), (1, -1), (1, 0), (0, 1), (-1, 1), (-1, 0))
def okoli(b, p, q):
o = [0] * 6
for i in range(6):
p2, q2 = smer[i]
if b.inBoard(p + p2, q + q2):
o[i] = b.board[p + p2][q + q2]
else:
o[i] = -1
return o
def spider_tah1(p, q, o):
mozne_tahy = []
for i in range(6):
if o[i] == 0 and (
(o[(i - 1) % 6] == 0 and o[(i + 1) % 6] == 1)
or (o[(i - 1) % 6] == 1 and o[(i + 1) % 6] == 0)
):
mozne_tahy.append([p + smer[i][0], q + smer[i][1]])
return mozne_tahy
o_spider = okoli(b, spider_p, spider_q)
print(o_spider)
komponenty = 0
for i in range(6):
if o_spider[i] == 1 and o_spider[(i + 1) % 6] != 1:
komponenty += 1
if komponenty > 1:
flood_fill()
pos = [[spider_p, spider_q]]
dont_go_back = pos[:]
b.board[spider_p][spider_q] = 0
for i in range(3):
pos2 = []
print(i, pos)
for p, q in pos:
mozne = spider_tah1(p, q, okoli(b, p, q))
for x in mozne:
if not x in dont_go_back:
print("jdu vpred", x)
pos2.append(x)
dont_go_back.append(x)
else:
print("jdu zpet", x)
pos = pos2
pos2.sort()
print(pos2)