File size: 3,936 Bytes
c4367ba
93ed0ca
560b34b
 
edf941b
560b34b
 
 
293933e
c4367ba
6f3a24a
 
 
596f579
c4367ba
560b34b
 
6f3a24a
 
 
 
 
 
560b34b
 
6f3a24a
c4367ba
 
6f3a24a
 
c533acd
6f3a24a
560b34b
c4367ba
 
560b34b
 
 
 
c0fee0a
560b34b
 
 
6f3a24a
560b34b
 
 
 
 
 
 
c4367ba
 
560b34b
 
6f3a24a
560b34b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6ad4064
c4367ba
560b34b
6f3a24a
560b34b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34d6098
560b34b
6f3a24a
560b34b
 
 
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
import gradio as gr
from PIL import Image, ImageDraw, ImageFont
import random
import time

def choose_move(board, player):
    valid = [(r, c) for r in range(8) for c in range(8) if get_flips(board, r, c, player)]
    return random.choice(valid) if valid else None

def initialize_board():
    b = [[0]*8 for _ in range(8)]
    b[3][3], b[4][4] = 1, 1
    b[3][4], b[4][3] = -1, -1
    return b

DIRECTIONS = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]

def get_flips(board, r, c, p):
    if board[r][c] != 0: return []
    flips = []
    for dr, dc in DIRECTIONS:
        rr, cc = r+dr, c+dc; buf = []
        while 0<=rr<8 and 0<=cc<8 and board[rr][cc] == -p:
            buf.append((rr, cc)); rr+=dr; cc+=dc
        if buf and 0<=rr<8 and 0<=cc<8 and board[rr][cc] == p:
            flips += buf
    return flips

def apply_move(board, r, c, p):
    f = get_flips(board, r, c, p)
    if not f: return False
    board[r][c] = p
    for rr, cc in f: board[rr][cc] = p
    return True

def count_score(board):
    b = sum(cell==-1 for row in board for cell in row)
    w = sum(cell==1  for row in board for cell in row)
    return b, w

def board_to_image(board, last_user, last_ai, player):
    size = 360; cell = size//8
    img = Image.new('RGB', (size, size+cell), 'darkgreen')
    draw = ImageDraw.Draw(img)
    # Scoreboard
    b, w = count_score(board)
    draw.rectangle([0,0,size,cell], fill='navy')
    font = ImageFont.load_default()
    draw.text((10,2), f"Black: {b}", font=font, fill='yellow')
    draw.text((size-80,2), f"White: {w}", font=font, fill='yellow')
    # Board
    for r in range(8):
        for c in range(8):
            x0, y0 = c*cell, cell + r*cell
            x1, y1 = x0+cell, y0+cell
            draw.rectangle([x0,y0,x1,y1], outline='black')
            # possible moves
            if board[r][c]==0 and get_flips(board, r, c, player):
                draw.ellipse([x0+cell*0.4, y0+cell*0.4, x0+cell*0.6, y0+cell*0.6], fill='yellow')
            if board[r][c]==1:
                draw.ellipse([x0+4, y0+4, x1-4, y1-4], fill='white')
            if board[r][c]==-1:
                draw.ellipse([x0+4, y0+4, x1-4, y1-4], fill='black')
    # markers
    if last_user:
        ur, uc = last_user
        x0, y0 = uc*cell, cell + ur*cell; x1, y1 = x0+cell, y0+cell
        draw.rectangle([x0,y0,x1,y1], outline='red', width=4)
    if last_ai:
        ar, ac = last_ai
        x0, y0 = ac*cell, cell + ar*cell; x1, y1 = x0+cell, y0+cell
        draw.rectangle([x0,y0,x1,y1], outline='blue', width=4)
    return img

def click_handler(evt: gr.SelectData, state):
    board, player, last_user, last_ai = state
    x, y = evt.index; cell = 360//8
    c, r = int(x//cell), int((y-cell)//cell)
    # invalid
    if not (0<=r<8 and 0<=c<8):
        yield board_to_image(board, last_user, last_ai, player), state
        return
    # user move
    if apply_move(board, r, c, player):
        last_user = (r, c); player = -player
        yield board_to_image(board, last_user, last_ai, player), state
    else:
        yield board_to_image(board, last_user, last_ai, player), state
        return
    # AI thinking indicator
    yield board_to_image(board, last_user, last_ai, player), (board, player, last_user, last_ai)
    time.sleep(2)
    # AI move
    ai_mv = choose_move(board, player)
    if ai_mv:
        apply_move(board, ai_mv[0], ai_mv[1], player)
        last_ai = ai_mv; player = -player
        yield board_to_image(board, last_user, last_ai, player), (board, player, last_user, last_ai)
    else:
        yield board_to_image(board, last_user, last_ai, player), (board, player, last_user, last_ai)

with gr.Blocks() as demo:
    state = gr.State((initialize_board(), -1, None, None))
    board_img = gr.Image(value=board_to_image(initialize_board(), None, None, -1), interactive=True)
    board_img.select(click_handler, inputs=[state], outputs=[board_img, state])
    demo.launch()