File size: 3,851 Bytes
c4367ba
93ed0ca
c533acd
 
edf941b
17edf34
293933e
c533acd
c4367ba
a487d57
 
 
 
c4367ba
93ed0ca
cc9d79f
a487d57
 
c533acd
 
 
 
 
c4367ba
 
cc9d79f
c533acd
 
a487d57
c533acd
c4367ba
 
a487d57
c533acd
 
c0fee0a
93ed0ca
c533acd
 
 
c0fee0a
 
c4c68cc
c0fee0a
c533acd
c0fee0a
a487d57
c533acd
 
a487d57
c533acd
 
 
 
 
a487d57
 
c533acd
 
 
23f367b
c533acd
 
 
 
 
c4367ba
 
c533acd
 
a487d57
 
c533acd
 
a487d57
c533acd
a487d57
6ad4064
c4367ba
c533acd
 
a487d57
c533acd
 
 
 
 
 
 
 
 
 
 
 
a487d57
c0fee0a
c533acd
 
34d6098
c533acd
b8ed266
a487d57
c533acd
 
a487d57
c533acd
9b082e6
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
import gradio as gr
from PIL import Image, ImageDraw, ImageFont
import random
time

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

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

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 choose_move(board, p):
    moves = [(r,c) for r in range(8) for c in range(8) if get_flips(board,r,c,p)]
    return random.choice(moves) if moves else None

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 is_game_over(board):
    return not any(get_flips(board,r,c,p) for p in (-1,1) for r in range(8) for c in range(8))

# Rendering
def board_to_image(board, state):
    board_state, player, last_user, last_ai = state
    size = 400; board_size = 360; cell = board_size//8
    img = Image.new('RGB',(size, size), 'darkgreen')
    draw = ImageDraw.Draw(img)
    # Load font
    try:
        font = ImageFont.truetype('arial.ttf', 24)
    except:
        font = ImageFont.load_default()
    # Scoreboard
    b, w = count_score(board_state)
    draw.text((10, 10), f"Black: {b}", font=font, fill='white')
    draw.text((size-150, 10), f"White: {w}", font=font, fill='white')
    # Winner display
    if is_game_over(board_state):
        result = 'DRAW' if b==w else ('BLACK WINS' if b>w else 'WHITE WINS')
        w_font = ImageFont.truetype('arial.ttf', 36) if hasattr(ImageFont, 'truetype') else font
        draw.text((size//2 - 100, size//2 - 18), result, font=w_font, fill='yellow')
    # Draw grid and stones
    offset = 40
    for r in range(8):
        for c in range(8):
            x0 = offset + c*cell
            y0 = offset + r*cell
            x1, y1 = x0+cell, y0+cell
            draw.rectangle([x0,y0,x1,y1], outline='black')
            val = board_state[r][c]
            if val == 1:
                draw.ellipse([x0+4,y0+4,x1-4,y1-4], fill='white')
            elif val == -1:
                draw.ellipse([x0+4,y0+4,x1-4,y1-4], fill='black')
    return img

# Handlers
def click_handler(evt: gr.SelectData, state):
    board, player, last_user, last_ai = state
    # Calculate cell
    x,y = evt.index; offset=40; cell=360//8
    c = int((x-offset)//cell); r = int((y-offset)//cell)
    if 0<=r<8 and 0<=c<8 and not is_game_over(board):
        if apply_move(board, r, c, player): last_user=(r,c); player=-player
        # AI move after delay
        time.sleep(1)
        if not is_game_over(board):
            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
    return board_to_image(board, (board, player, last_user, last_ai)), (board, player, last_user, last_ai)

def reset_game():
    return (initialize_board(), -1, None, None)

# UI
with gr.Blocks() as demo:
    state = gr.State((initialize_board(), -1, None, None))
    img = gr.Image(value=board_to_image(initialize_board(), (initialize_board(),-1,None,None)), interactive=True)
    new_game = gr.Button("New Game")
    img.select(click_handler, inputs=[state], outputs=[img, state])
    new_game.click(fn=lambda: (initialize_board(), -1, None, None), outputs=[state])
    demo.launch()