Update app.py
Browse files
app.py
CHANGED
@@ -2,137 +2,115 @@ import gradio as gr
|
|
2 |
from PIL import Image, ImageDraw, ImageFont
|
3 |
import random, time
|
4 |
|
5 |
-
|
6 |
-
|
7 |
-
history_log = []
|
8 |
-
|
9 |
-
# Load custom fonts or fall back
|
10 |
-
try:
|
11 |
-
FONT_L = ImageFont.truetype("DejaVuSans-Bold.ttf", 36)
|
12 |
-
FONT_S = ImageFont.truetype("DejaVuSans-Bold.ttf", 20)
|
13 |
-
except:
|
14 |
-
FONT_L = ImageFont.load_default()
|
15 |
-
FONT_S = ImageFont.load_default()
|
16 |
|
|
|
17 |
def initialize_board():
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
return
|
22 |
|
|
|
23 |
def get_flips(board, r, c, p):
|
24 |
if board[r][c] != 0: return []
|
25 |
-
flips=[]
|
26 |
-
for dr,dc in DIRECTIONS:
|
27 |
-
rr,cc=r+dr,c+dc
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
|
|
32 |
return flips
|
33 |
|
|
|
34 |
def apply_move(board, r, c, p):
|
35 |
-
|
36 |
-
if not
|
37 |
-
board[r][c]=p
|
38 |
-
for rr,cc in
|
|
|
39 |
return True
|
40 |
|
41 |
-
|
42 |
-
|
|
|
43 |
return random.choice(valid) if valid else None
|
44 |
|
|
|
45 |
def count_score(board):
|
46 |
-
|
47 |
-
|
48 |
-
return
|
49 |
|
|
|
50 |
def is_game_over(board):
|
51 |
return not any(get_flips(board,r,c,p) for p in (-1,1) for r in range(8) for c in range(8))
|
52 |
|
|
|
53 |
def board_to_image(board, state):
|
54 |
-
board_state, player, last_user, last_ai
|
55 |
-
size, cell =
|
56 |
-
img=Image.new('RGB',(size,size+cell
|
57 |
-
draw=ImageDraw.Draw(img)
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
draw.text((
|
63 |
-
|
|
|
|
|
64 |
if is_game_over(board_state):
|
65 |
-
winner = "
|
66 |
-
draw.
|
67 |
-
draw.text((size//2-120,cell+2),winner,font=FONT_L,fill='yellow')
|
68 |
-
draw.text((size//2-120,cell+30),"Click 'New Game' to restart",font=FONT_S,fill='white')
|
69 |
|
|
|
70 |
for r in range(8):
|
71 |
for c in range(8):
|
72 |
-
x0,y0=c*cell,cell
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
for mark,clr in ((last_user,'red'),(last_ai,'blue')):
|
80 |
-
if mark:
|
81 |
-
mr,mc=mark; x0,y0=mc*cell,cell*2+mr*cell; x1,y1=x0+cell,y0+cell
|
82 |
-
draw.rectangle([x0,y0,x1,y1],outline=clr,width=4)
|
83 |
-
|
84 |
-
y=cell*2+8*cell+10
|
85 |
-
if history:
|
86 |
-
draw.text((10,y),"History:",font=FONT_S,fill='white'); y+=cell//2
|
87 |
-
for res in history[-5:]:
|
88 |
-
draw.text((10,y),res,font=FONT_S,fill='white'); y+=cell//2
|
89 |
-
|
90 |
return img
|
91 |
|
|
|
|
|
92 |
def click_handler(evt, state):
|
|
|
93 |
if state is None:
|
94 |
-
state = (initialize_board(), -1, None, None
|
95 |
-
board, player,
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
cell = 400 // 8
|
101 |
-
c, r = int(x // cell), int((y - cell * 2) // cell)
|
102 |
|
|
|
103 |
if 0 <= r < 8 and 0 <= c < 8 and not is_game_over(board):
|
104 |
if apply_move(board, r, c, player):
|
105 |
-
|
106 |
-
|
107 |
-
yield board_to_image(board, (board, player, lu, la, history)), (board, player, lu, la, history)
|
108 |
-
|
109 |
-
if is_game_over(board):
|
110 |
-
winner = "DRAW" if count_score(board)[0] == count_score(board)[1] else ("BLACK" if count_score(board)[0] > count_score(board)[1] else "WHITE")
|
111 |
-
history.append(f"Game {len(history)+1}: {winner}")
|
112 |
-
history_log.append(f"Game {len(history_log)+1}: {winner}")
|
113 |
-
yield board_to_image(board, (board, player, lu, la, history)), (board, player, lu, la, history)
|
114 |
-
return
|
115 |
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
|
|
|
|
121 |
|
122 |
-
|
123 |
-
if ai_mv:
|
124 |
-
apply_move(board, ai_mv[0], ai_mv[1], player)
|
125 |
-
la, player = ai_mv, -player
|
126 |
-
yield board_to_image(board, (board, player, lu, la, history)), (board, player, lu, la, history)
|
127 |
|
128 |
-
|
129 |
-
new_board = initialize_board()
|
130 |
-
return new_board, -1, None, None, history_log.copy()
|
131 |
|
132 |
with gr.Blocks() as demo:
|
133 |
-
state=gr.State((initialize_board()
|
134 |
-
img=gr.Image(value=board_to_image(initialize_board(),(initialize_board()
|
135 |
-
|
136 |
-
img.select(click_handler,inputs=[state],outputs=[img,state])
|
137 |
-
new_btn.click(fn=lambda: (initialize_board(), -1, None, None, history_log.copy()), outputs=[state, img])
|
138 |
demo.launch()
|
|
|
2 |
from PIL import Image, ImageDraw, ImageFont
|
3 |
import random, time
|
4 |
|
5 |
+
# Constants
|
6 |
+
dIRECTIONS = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
+
# Initialize board
|
9 |
def initialize_board():
|
10 |
+
board = [[0]*8 for _ in range(8)]
|
11 |
+
board[3][3], board[4][4] = 1, 1
|
12 |
+
board[3][4], board[4][3] = -1, -1
|
13 |
+
return board
|
14 |
|
15 |
+
# Get flips
|
16 |
def get_flips(board, r, c, p):
|
17 |
if board[r][c] != 0: return []
|
18 |
+
flips = []
|
19 |
+
for dr, dc in DIRECTIONS:
|
20 |
+
rr, cc = r+dr, c+dc
|
21 |
+
buf = []
|
22 |
+
while 0 <= rr < 8 and 0 <= cc < 8 and board[rr][cc] == -p:
|
23 |
+
buf.append((rr, cc)); rr += dr; cc += dc
|
24 |
+
if buf and 0 <= rr < 8 and 0 <= cc < 8 and board[rr][cc] == p:
|
25 |
+
flips.extend(buf)
|
26 |
return flips
|
27 |
|
28 |
+
# Apply move
|
29 |
def apply_move(board, r, c, p):
|
30 |
+
flips = get_flips(board, r, c, p)
|
31 |
+
if not flips: return False
|
32 |
+
board[r][c] = p
|
33 |
+
for rr, cc in flips:
|
34 |
+
board[rr][cc] = p
|
35 |
return True
|
36 |
|
37 |
+
# AI choose move
|
38 |
+
def choose_move(board, p):
|
39 |
+
valid = [(r,c) for r in range(8) for c in range(8) if get_flips(board,r,c,p)]
|
40 |
return random.choice(valid) if valid else None
|
41 |
|
42 |
+
# Count score
|
43 |
def count_score(board):
|
44 |
+
black = sum(cell==-1 for row in board for cell in row)
|
45 |
+
white = sum(cell==1 for row in board for cell in row)
|
46 |
+
return black, white
|
47 |
|
48 |
+
# Check game over
|
49 |
def is_game_over(board):
|
50 |
return not any(get_flips(board,r,c,p) for p in (-1,1) for r in range(8) for c in range(8))
|
51 |
|
52 |
+
# Render board image
|
53 |
def board_to_image(board, state):
|
54 |
+
board_state, player, last_user, last_ai = state
|
55 |
+
size, cell = 360, 360//8
|
56 |
+
img = Image.new('RGB', (size, size+cell), 'darkgreen')
|
57 |
+
draw = ImageDraw.Draw(img)
|
58 |
+
font = ImageFont.load_default()
|
59 |
+
|
60 |
+
# Scoreboard
|
61 |
+
b, w = count_score(board_state)
|
62 |
+
draw.text((10,2), f"B:{b}", font=font, fill='white')
|
63 |
+
draw.text((size-40,2), f"W:{w}", font=font, fill='white')
|
64 |
+
|
65 |
+
# Game end
|
66 |
if is_game_over(board_state):
|
67 |
+
winner = "Draw" if b==w else ("Black wins" if b>w else "White wins")
|
68 |
+
draw.text((size//2-40, size//2), winner, font=font, fill='yellow')
|
|
|
|
|
69 |
|
70 |
+
# Board grid and stones
|
71 |
for r in range(8):
|
72 |
for c in range(8):
|
73 |
+
x0, y0 = c*cell, cell + r*cell
|
74 |
+
x1, y1 = x0+cell, y0+cell
|
75 |
+
draw.rectangle([x0,y0,x1,y1], outline='black')
|
76 |
+
if board_state[r][c] == 1:
|
77 |
+
draw.ellipse([x0+4,y0+4,x1-4,y1-4], fill='white')
|
78 |
+
elif board_state[r][c] == -1:
|
79 |
+
draw.ellipse([x0+4,y0+4,x1-4,y1-4], fill='black')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
return img
|
81 |
|
82 |
+
# Click handler
|
83 |
+
|
84 |
def click_handler(evt, state):
|
85 |
+
# state: (board, player, last_user, last_ai)
|
86 |
if state is None:
|
87 |
+
state = (initialize_board(), -1, None, None)
|
88 |
+
board, player, last_user, last_ai = state
|
89 |
+
|
90 |
+
x, y = evt.index
|
91 |
+
cell = 360 // 8
|
92 |
+
c, r = int(x//cell), int((y-cell)//cell)
|
|
|
|
|
93 |
|
94 |
+
# Player move
|
95 |
if 0 <= r < 8 and 0 <= c < 8 and not is_game_over(board):
|
96 |
if apply_move(board, r, c, player):
|
97 |
+
last_user = (r, c)
|
98 |
+
player = -player
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
+
# AI move
|
101 |
+
if not is_game_over(board):
|
102 |
+
ai_mv = choose_move(board, player)
|
103 |
+
if ai_mv:
|
104 |
+
apply_move(board, ai_mv[0], ai_mv[1], player)
|
105 |
+
last_ai = ai_mv
|
106 |
+
player = -player
|
107 |
|
108 |
+
return board_to_image(board, (board, player, last_user, last_ai)), (board, player, last_user, last_ai)
|
|
|
|
|
|
|
|
|
109 |
|
110 |
+
# Main
|
|
|
|
|
111 |
|
112 |
with gr.Blocks() as demo:
|
113 |
+
state = gr.State((initialize_board(), -1, None, None))
|
114 |
+
img = gr.Image(value=board_to_image(initialize_board(), (initialize_board(), -1, None, None)), interactive=True)
|
115 |
+
img.select(click_handler, inputs=[state], outputs=[img, state])
|
|
|
|
|
116 |
demo.launch()
|