diff --git a/player algo.py b/player algo.py index 7836bcd..70b6927 100644 --- a/player algo.py +++ b/player algo.py @@ -45,7 +45,7 @@ class Player(Base.Board): for i in graph[str(cell)][0]: if(graph[str(i)][1] == False): break - return self.getCount()-1 == cn(graph,i,{str(cell):True,str(i):True}) + 1 + return self.getCount()-1 == cn(graph, i, {str(cell): True, str(i): True}) + len(graph[str(i)][2]) def spider(self,graph,cell,n,visited): n += 1 diff --git a/player.py b/player.py index e30ecf5..2372204 100644 --- a/player.py +++ b/player.py @@ -33,7 +33,25 @@ def has_neighbors(p, q, board, pp, pq): return False +def cn(spots, s, visited): + n = 0 + for i in spots[s][0]: + if i not in visited and spots[i][1] == False: + visited.add(i) + n += len(spots[i][2]) + n += cn(spots, i, visited) + return n + class Piece: + def __init__(self, p, q, team): + self.p = p + self.q = q + self.team = team + + @property + def pos(self): + return (self.p, self.q) + def get_piece_info(self, myisupper): class_to_letter = { "Bee": "Q", @@ -99,124 +117,110 @@ class Piece: class Bee(Piece): - def __init__(self, p, q, team): - self.p = p - self.q = q - self.team = team - def get_valid_jumps(self, board) -> list: - valid_moves = [] - for neighbor in get_neighbors(self.p, self.q): - if neighbor in board and board[neighbor] == "": - valid_moves.append(neighbor) - return valid_moves + def get_valid_jumps(self, spots, s) -> list: + result = [] + for i in spots[s][0]: + if spots[i][1]: + hive = False + empty = False + for j in spots[i][0]: + if hive and empty: + break + if j in spots[s][0]: + if spots[j][1]: + empty = True + else: + hive = True + if (hive and empty): + result.append(i) + return result class Beetle(Piece): - def __init__(self, p, q, team): - self.p = p - self.q = q - self.team = team - def get_valid_jumps(self, board): - valid_moves = get_neighbors(self.p, self.q) - checked = [v for v in valid_moves if has_neighbors( - v[0], v[1], board, self.p, self.q)] - return checked + def get_valid_jumps(self, spots, s): + if len(spots[s][2]) > 1: + return spots[s][0] + result = [] + for i in spots[s][0]: + if spots[i][1]: + for j in spots[i][0]: + if (j[0] != s[0] or j[1] != s[1]) and spots[j][1] == False: + result.append(i) + break + else: + result.append(i) + return result class Spider(Piece): - def __init__(self, p, q, team): - self.p = p - self.q = q - self.team = team + def get_valid_jumps(self, spots: dict, s: tuple): + return self.crawl(spots, s, 0, set()) - def get_valid_jumps(self, board): - start = (self.p, self.q) - visited = set() - queue = deque([(start, 0)]) # Queue of (position, distance) - valid_moves = [] - - while queue: - current_position, current_distance = queue.popleft() - if current_distance == 3: - if has_neighbors(*current_position, board, self.p, self.q): - valid_moves.append(current_position) - continue - - if current_position in visited: - continue - - visited.add(current_position) - - 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 + def crawl(self, spots, s, n, visited): + n += 1 + visited.add(s) + if n == 4: + return [s] + result = [] + for i in spots[s][0]: + hive = False + empty = False + if i in visited and spots[i][1]: + for j in spots[i][0]: + if empty and hive: + break + if j in spots[s][0]: + if spots[str(j)][1] or j in visited: + empty = True + else: + hive = True + if (empty and hive): + result += self.spider(spots, i, n, visited.copy()) + return result 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(): - for dp, dq in get_neighbors(0, 0): - pos = (self.p + dp, self.q + dq) - while pos in board and board[pos] != "": - pos = (pos[0] + dp, pos[1] + dq) - if ( - pos in board - and board[pos] == "" - and (pos[0] != self.p or pos[1] != self.q) - ): - yield pos - - valid_moves = list(generate_moves()) - return valid_moves + def get_valid_jumps(self, spots, s): + result = [] + for i in get_neighbors(0, 0): + q = (s[0]+i[0], s[1]+i[1]) + if not spots[q][1]: + while True: + q = (q[0]+i[0], q[1]+i[1]) + if q in spots.keys() and spots[q][1]: + result.append(q) + break + else: + break + return result class Ant(Piece): - def __init__(self, p, q, team): - self.p = p - self.q = q - self.team = team + def get_valid_jumps(self, spots: dict, s: tuple): + return self.crawl(spots, s, set()) - def get_valid_jumps(self, board): - visited = set() - - 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 (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 (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) + def crawl(self, spots: dict, s: tuple, visited: set): + visited.add(s) + result = [] + for i in spots[s][0]: + hive = False + empty = False + if i in visited and spots[i][1]: + for j in spots[i][0]: + if empty and hive: + break + if j in spots[s][0]: + if spots[str(j)][1] or visited.get(str(j)): + empty = True + else: + hive = True + if empty and hive: + result += [i] + result += self.ant(spots, i, visited) + return result class Player(Base.Board): @@ -227,10 +231,25 @@ class Player(Base.Board): self, myIsUpper, size, myPieces, rivalPieces ) # do not change this line self.playerName = playerName - self.myIsUpper = myIsUpper self.algorithmName = "just roll the dice, eh?" - self.tboard = dict() - self.can_place = lambda: sum([v for v in self.myPieces.values()]) + self.spots = dict() + self.figures_player = list() + self.bee = None + self.total_piece_count = 18 + + @property + def all_remaining(self): + return self.total_piece_count - sum(self.myPieces.values()+self.rivalPieces.values()) + + @property + def remaining_pieces(self): + return sum(self.myPieces.values()) + + def connected(self, graph, cell): + for i in graph[str(cell)][0]: + if (graph[i][1] == False): + break + return self.remaining_pieces-1 == cn(graph, i, {str(cell): True, i: True}) + len(graph[i][2]) def getAllEmptyCells(self): result = [] @@ -258,160 +277,75 @@ class Player(Base.Board): "A": Ant, } - translated_board = {p: {} for p in board} - total_pieces_count = 0 - my_pieces_count = 0 + spots = dict() - for p, row in board.items(): - for q, tile_content in row.items(): - 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()) - 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] = topmost_piece_letter - else: - translated_board[p][q] = tile_content + figures_player = list() - return translated_board, total_pieces_count, my_pieces_count + for p, r in self.board.items(): + for q, a in r.items(): + surr = [s for s in get_neighbors( + p, q) if self.inBoard(s[0], s[1])] + spots[(p, q)] = [surr, piece_class_mapping[a[-1].upper()]( + p, q, self.myColorIsUpper == a[-1].isupper()) if a else None] + if (a, self.myColorIsUpper == a.isupper()): + figures_player.append((p, q)) - @property - def queen_placed(self): - return any(isinstance(p, Bee) for p in self.myPieces) + self.spots = spots + self.figures_player = figures_player - def random_piece(self, pieces): - return random.choice(pieces) if pieces else None - - def get_piece_class(self, letter): - return {"Q": Bee, "B": Beetle, "S": Spider, "G": Grasshopper, "A": Ant}.get( - letter.upper() - ) - - def get_unplaced_pieces(self): - 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 get_valid_placements(self, translated_board, piece_to_place): - valid_placements = [] - - # If the board is empty, place the piece at the center. - if not any(row.values() for row in translated_board.values()): - return [(3, 6)] - - # Iterate over each tile in the board - for p, row in translated_board.items(): - for q, tile_content in row.items(): - # Check if the tile is empty - if tile_content == "": - # Check if any neighbors are your pieces and none are opponent's pieces - neighbors = get_neighbors(p, q) - if any( - # Check if the neighboring tile is occupied by your team's piece - isinstance(translated_board.get(np, {}).get(nq), Piece) and - translated_board[np][nq].team == piece_to_place.team - for np, nq in neighbors - ) and not any( - # Check if the neighboring tile is occupied by the opponent's piece - isinstance(translated_board.get(np, {}).get(nq), Piece) and - translated_board[np][nq].team != piece_to_place.team - for np, nq in neighbors - ): - valid_placements.append((p, q)) - - return valid_placements - - def mover(self): - 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[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: - 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, - None, - new_p, - new_q, - ] - - def update(self): - 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 get_movable_pieces(self): + # GET Movable,Empty + moveable = {} + empty_spots = [] + for cell in self.figures_player: + # Get all empty cells + if (self.remaining_pieces != 0): + for i in get_neighbors(0, 0): + q = (cell[0]+i[0], cell[1]+i[1]) + if q in self.spots.keys(): + if self.spots[q][1]: + enemy = False + for j in get_neighbors(0, 0): + qq = (q[0]+j[0], q[1]+j[1]) + qqs = str(qq) + if (self.spots.get(qqs) != None): + if (self.spots[qqs][1] == False): + if (self.spots[qqs][2] == False): + enemy = True + break + if (not enemy): + empty_spots.append(q) + # Get all moves + if self.myMove > 3: + if self.connected(self.spots, cell): + animal = self.spots[cell][2] + arr = animal.get_valid_jumps(self.spots, cell) + if (len(arr) > 0): + moveable[cell] = arr + return moveable, empty_spots def move(self): - total_pieces_count, my_pieces_count = self.update() + if self.myMove > 80: + return [] - 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 + self.translate_board() - 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.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] + free = [1 for n in get_neighbors( + self.bee.p, self.bee.q) if self.spots[n][1] == None] + if sum(free) <= 0: + return [] - 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] - ) - - elif total_pieces_count == 1: - 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()) - return ( - piece_to_place.get_piece_info(self.myIsUpper)[:1] - + [None, None, *random_position] - ) - - elif self.myMove <= 4: - return self.placer() - - choice = random.choice(["move", "place"]) - print(choice) - if choice == "place" and bool(self.can_place): - return self.placer() - else: - return self.mover() + if (self.myMove == 0): + animal = random.choice(list(self.myPieces.keys())) + if (self.getCount() == 0): + return [animal, None, None, 3, 6] + else: + choice = random.choice(get_neighbors(3, 6)) + return [animal, None, None, choice[0], choice[1]] + moveable, empty = self.get_movable_pieces() + if len(moveable) == 0 and len(empty) == 0: # movement impossible + return [] def updatePlayers(move, activePlayer, passivePlayer): """write move made by activePlayer player