File size: 3,189 Bytes
a5f2e46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import chess
from PIL import Image
from io import BytesIO
import cairosvg


def _create_board_from_moves(moves: list[str]) -> chess.Board:
    """
    Create a chess board and apply a sequence of moves.

    Args:
        moves: List of moves in UCI format (e.g., ['e2e4', 'd7d5'])

    Returns:
        Chess board with moves applied
    """
    board = chess.Board()
    for move_str in moves:
        try:
            move = chess.Move.from_uci(move_str)
            board.push(move)
        except ValueError:
            pass  # Skip invalid moves
    return board


def generate_board_image(moves: list[str], size: int = 400) -> Image.Image:
    """
    Generate a PIL image of a chess board after applying a sequence of moves.

    Args:
        moves: List of moves in UCI format (e.g., ['e2e4', 'd7d5'])
        size: Size of the output image in pixels (default: 400)

    Returns:
        PIL Image of the chess board
    """
    import chess.svg

    board = _create_board_from_moves(moves)

    # Generate SVG using chess library
    svg_data = chess.svg.board(board, size=size)

    # Convert SVG to PNG using cairosvg
    png_data = cairosvg.svg2png(bytestring=svg_data.encode("utf-8"))

    # Load PNG into PIL Image
    img = Image.open(BytesIO(png_data))

    return img


def generate_board_ascii(moves: list[str]) -> str:
    """
    Generate an ASCII representation of a chess board after applying a sequence of moves.

    Args:
        moves: List of moves in UCI format (e.g., ['e2e4', 'd7d5'])

    Returns:
        String representation of the chess board
    """
    board = _create_board_from_moves(moves)
    return str(board)


def generate_game_gif(moves: list[str], size: int = 400, duration: int = 500) -> bytes:
    """
    Generate an animated GIF of a chess game from a sequence of moves.

    Args:
        moves: List of moves in UCI format (e.g., ['e2e4', 'd7d5'])
        size: Size of each frame in pixels (default: 400)
        duration: Duration of each frame in milliseconds (default: 500)

    Returns:
        Bytes of the animated GIF
    """
    frames = []

    # Initial position
    img = generate_board_image([], size)
    frames.append(img)

    # Apply moves and capture frames
    moves_so_far = []
    for move_str in moves:
        try:
            move = chess.Move.from_uci(move_str)
            moves_so_far.append(move_str)
            img = generate_board_image(moves_so_far, size)
            frames.append(img)
        except ValueError:
            pass  # Skip invalid moves

    # Save frames as GIF in memory
    gif_bytes = BytesIO()
    frames[0].save(
        gif_bytes,
        format="GIF",
        save_all=True,
        append_images=frames[1:],
        duration=duration,
        loop=0,
    )
    gif_bytes.seek(0)

    return gif_bytes.getvalue()


if __name__ == "__main__":
    moves = ["e2e4"]
    img = generate_board_image(moves)
    img.show()

    ascii_board = generate_board_ascii(moves)
    print(ascii_board)

    coup_du_berget = ["e2e4", "e7e5", "f1c4", "b8c6", "d1h5", "g8f6", "h5f7"]
    gif = generate_game_gif(coup_du_berget)
    with open("coup_du_berget.gif", "wb") as f:
        f.write(gif)