-
-
Save Ocean-Moist/0064caf583bc4ccf4151fd1a50601836 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Chess FEN Parser and Board Renderer | |
def parse_fen(fen): | |
"""Parses a FEN string and returns a dictionary with board state and game info.""" | |
# Split the FEN string into its components | |
fields = fen.strip().split() | |
if len(fields) != 6: | |
raise ValueError("Invalid FEN: Incorrect number of fields.") | |
piece_placement, active_color, castling_availability, en_passant_target, halfmove_clock, fullmove_number = fields | |
# Create the board matrix and piece positions | |
board = [] | |
piece_positions = {'White': {}, 'Black': {}, 'Empty': []} | |
ranks = piece_placement.split('/') | |
if len(ranks) != 8: | |
raise ValueError("Invalid FEN: Incorrect number of ranks.") | |
for rank_index, rank in enumerate(ranks): | |
board_row = [] | |
file_index = 0 # Files from 'a' to 'h' | |
for char in rank: | |
if char.isdigit(): | |
empty_squares = int(char) | |
for _ in range(empty_squares): | |
board_row.append('.') | |
file_char = chr(ord('a') + file_index) | |
rank_char = 8 - rank_index | |
position = f"{file_char}{rank_char}" | |
piece_positions['Empty'].append(position) | |
file_index += 1 | |
else: | |
board_row.append(char) | |
color = 'White' if char.isupper() else 'Black' | |
piece = char.upper() | |
file_char = chr(ord('a') + file_index) | |
rank_char = 8 - rank_index | |
position = f"{file_char}{rank_char}" | |
if piece not in piece_positions[color]: | |
piece_positions[color][piece] = [] | |
piece_positions[color][piece].append(position) | |
file_index += 1 | |
if len(board_row) != 8: | |
raise ValueError("Invalid FEN: Incorrect number of files in a rank.") | |
board.append(board_row) | |
game_info = { | |
'active_color': 'White' if active_color == 'w' else 'Black', | |
'castling_availability': castling_availability if castling_availability != '-' else 'None', | |
'en_passant_target': en_passant_target if en_passant_target != '-' else 'None', | |
'halfmove_clock': int(halfmove_clock), | |
'fullmove_number': int(fullmove_number) | |
} | |
return board, piece_positions, game_info | |
def render_board(board): | |
"""Renders the board matrix into an ASCII diagram with labels on all sides.""" | |
files = ' a b c d e f g h ' | |
print(" " + files) | |
print(" +" + "----" * 8 + "+") | |
for rank_index, rank in enumerate(board): | |
rank_number = 8 - rank_index | |
rank_str = f"{rank_number} |" | |
for piece in rank: | |
rank_str += f" {piece} |" | |
rank_str += f" {rank_number}" | |
print(rank_str) | |
print(" +" + "----" * 8 + "+") | |
print(" " + files) | |
def list_piece_positions(piece_positions): | |
"""Lists the positions of each piece, including empty squares.""" | |
for color in ['White', 'Black']: | |
print(f"{color} Pieces:") | |
if piece_positions[color]: | |
for piece in sorted(piece_positions[color].keys()): | |
positions = ', '.join(sorted(piece_positions[color][piece])) | |
piece_name = piece_full_name(piece) | |
print(f"- {piece_name}: {positions}") | |
else: | |
print("- None") | |
print() | |
# List empty squares | |
print("Empty Squares:") | |
if piece_positions['Empty']: | |
empty_positions = ', '.join(sorted(piece_positions['Empty'])) | |
print(f"- {empty_positions}") | |
else: | |
print("- None") | |
print() | |
def piece_full_name(piece_symbol): | |
"""Returns the full name of a piece given its symbol.""" | |
names = {'K': 'King', 'Q': 'Queen', 'R': 'Rook', | |
'B': 'Bishop', 'N': 'Knight', 'P': 'Pawn'} | |
return names.get(piece_symbol, 'Unknown') | |
def display_game_info(game_info): | |
"""Displays human-readable game information.""" | |
print("Game Information:") | |
print(f"- Active Color: {game_info['active_color']}") | |
print(f"- Castling Availability: {game_info['castling_availability']}") | |
print(f"- En Passant Target Square: {game_info['en_passant_target']}") | |
print(f"- Halfmove Clock: {game_info['halfmove_clock']}") | |
print(f"- Fullmove Number: {game_info['fullmove_number']}") | |
print() | |
def main(): | |
fen = input("<FEN String>\n") | |
print("</FEN String>") | |
try: | |
board, piece_positions, game_info = parse_fen(fen) | |
print("<ASCII Diagram of the Board>") | |
render_board(board) | |
print("</ASCII Diagram of the Board>") | |
print("<Piece Positions>") | |
list_piece_positions(piece_positions) | |
print("</Piece Positions>") | |
print("<Game Information>") | |
display_game_info(game_info) | |
print("</Game Information>") | |
print("<Instruction>") | |
print(f"Find the best, valid move for {game_info['active_color']}.") | |
print("</Instruction>") | |
except ValueError as e: | |
print(f"Error: {e}") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment