File size: 4,313 Bytes
c4367ba
93ed0ca
c0fee0a
edf941b
c0fee0a
 
edf941b
c4367ba
cc9d79f
 
 
 
c4367ba
93ed0ca
cc9d79f
c0fee0a
 
 
 
 
 
 
c4367ba
 
cc9d79f
c0fee0a
93ed0ca
c0fee0a
 
c4367ba
 
c0fee0a
 
 
 
93ed0ca
c0fee0a
 
 
 
 
 
 
 
 
 
93ed0ca
c0fee0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cc9d79f
c4367ba
 
c0fee0a
 
 
 
 
 
 
cc9d79f
c0fee0a
 
 
 
 
 
 
 
6ad4064
c4367ba
c0fee0a
 
 
 
 
 
 
 
 
 
b8ed266
c0fee0a
 
b8ed266
c0fee0a
 
 
 
 
 
34d6098
b8ed266
c0fee0a
 
 
 
 
c4367ba
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
import gradio as gr
from PIL import Image, ImageDraw, ImageFont
import random, time

# Game logic as before
DIRECTIONS = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]

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

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, 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 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):
    if any(get_flips(board,r,c,p) for p in [-1,1] for r in range(8) for c in range(8)): return False
    return True

# Image renderer
FONT = ImageFont.truetype("arial.ttf", 24)

def board_to_image(board, state):
    board, player, last_user, last_ai, history = state
    size=360; cell=size//8
    img=Image.new('RGB',(size,size+cell*2),'darkgreen')
    draw=ImageDraw.Draw(img)
    # Scoreboard top
    b,w=count_score(board)
    draw.rectangle([0,0,size,cell],fill='navy')
    draw.text((10,2),f"BLACK: {b}",font=FONT,fill='white')
    draw.text((size-160,2),f"WHITE: {w}",font=FONT,fill='white')
    # Game end highlight
    if is_game_over(board):
        winner = "Draw" if b==w else ("Black Wins" if b>w else "White Wins")
        draw.rectangle([0,cell,size,cell*2],fill='maroon')
        draw.text((size//2-80,cell+2),winner,font=FONT,fill='yellow')
    # Board
    for r in range(8):
        for c in range(8):
            x0,y0=c*cell,cell*2+r*cell; x1,y1=x0+cell,y0+cell
            draw.rectangle([x0,y0,x1,y1],outline='black')
            # candidate
            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
    for mark,clr in ((state[2],'red'),(state[3],'blue')):
        if mark:
            mr,mc=mark; x0,y0=mc*cell,cell*2+mr*cell; x1,y1=x0+cell,y0+cell
            draw.rectangle([x0,y0,x1,y1],outline=clr,width=4)
    # history display
    y=text_y=cell*2+8*cell+2
    for i,res in enumerate(history[-5:]):
        draw.text((10,y+i*(cell//2)),res,font=ImageFont.truetype("arial.ttf",16),fill='white')
    return img

# Handlers

def click_handler(evt,state):
    board,player,lu,la,history=state
    x,y=evt.index; cell=360//8; c,r=int(x//cell),int((y-cell*2)//cell)
    if 0<=r<8 and 0<=c<8 and not is_game_over(board):
        if apply_move(board,r,c,player): lu=(r,c); player=-player
    yield board_to_image(board,(board,player,lu,la,history)),(board,player,lu,la,history)
    if is_game_over(board):
        history.append(f"Game {len(history)+1}: {'Black' if count_score(board)[0]>count_score(board)[1] else 'White' if count_score(board)[1]>count_score(board)[0] else 'Draw'}")
        return
    # AI
    yield board_to_image(board,(board,player,lu,la,history)),(board,player,lu,la,history)
    time.sleep(2)
    ai_mv=choose_move(board,player)
    if ai_mv: apply_move(board,ai_mv[0],ai_mv[1],player); la=ai_mv; player=-player
    yield board_to_image(board,(board,player,lu,la,history)),(board,player,lu,la,history)

def reset_handler():
    return initialize_board(),-1,None,None,[]

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_btn=gr.Button("New Game")
    img.select(click_handler,inputs=[state],outputs=[img,state])
    new_btn.click(fn=reset_handler,outputs=[state,img])
    demo.launch()