Renecto commited on
Commit
a487d57
·
verified ·
1 Parent(s): 51a55cb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -99
app.py CHANGED
@@ -2,137 +2,115 @@ import gradio as gr
2
  from PIL import Image, ImageDraw, ImageFont
3
  import random, time
4
 
5
- DIRECTIONS = [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]
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
- b = [[0]*8 for _ in range(8)]
19
- b[3][3], b[4][4] = 1, 1
20
- b[3][4], b[4][3] = -1, -1
21
- return b
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; buf=[]
28
- while 0<=rr<8 and 0<=cc<8 and board[rr][cc]==-p:
29
- buf.append((rr,cc)); rr+=dr; cc+=dc
30
- if buf and 0<=rr<8 and 0<=cc<8 and board[rr][cc]==p:
31
- flips+=buf
 
32
  return flips
33
 
 
34
  def apply_move(board, r, c, p):
35
- f=get_flips(board,r,c,p)
36
- if not f: return False
37
- board[r][c]=p
38
- for rr,cc in f: board[rr][cc]=p
 
39
  return True
40
 
41
- def choose_move(board, player):
42
- valid=[(r,c) for r in range(8) for c in range(8) if get_flips(board,r,c,player)]
 
43
  return random.choice(valid) if valid else None
44
 
 
45
  def count_score(board):
46
- b=sum(cell==-1 for row in board for cell in row)
47
- w=sum(cell==1 for row in board for cell in row)
48
- return b,w
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, history = state
55
- size, cell = 400, 400//8
56
- img=Image.new('RGB',(size,size+cell*5),'darkgreen')
57
- draw=ImageDraw.Draw(img)
58
-
59
- b,w=count_score(board_state)
60
- draw.rectangle([0,0,size,cell],fill='navy')
61
- draw.text((10,2),f"BLACK: {b}",font=FONT_L,fill='white')
62
- draw.text((size-200,2),f"WHITE: {w}",font=FONT_L,fill='white')
63
-
 
 
64
  if is_game_over(board_state):
65
- winner = "DRAW" if b==w else ("BLACK WINS" if b>w else "WHITE WINS")
66
- draw.rectangle([0,cell,size,cell*2],fill='darkred')
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*2+r*cell; x1,y1=x0+cell,y0+cell
73
- draw.rectangle([x0,y0,x1,y1],outline='black')
74
- if board_state[r][c]==0 and get_flips(board_state,r,c,player):
75
- draw.ellipse([x0+cell*0.4,y0+cell*0.4,x0+cell*0.6,y0+cell*0.6],fill='yellow')
76
- if board_state[r][c]==1: draw.ellipse([x0+4,y0+4,x1-4,y1-4],fill='white')
77
- if board_state[r][c]==-1: draw.ellipse([x0+4,y0+4,x1-4,y1-4],fill='black')
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, lu, la, history = state
96
- if callable(evt.index):
97
- x, y = evt.index()
98
- else:
99
- x, y = evt.index
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
- lu, player = (r, c), -player
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
- thinking_img = board_to_image(board, (board, player, lu, la, history))
117
- draw = ImageDraw.Draw(thinking_img)
118
- draw.text((150, 400 - 25), "AI Thinking...", font=FONT_S, fill='cyan')
119
- yield thinking_img, (board, player, lu, la, history)
120
- time.sleep(1.5)
 
 
121
 
122
- ai_mv = choose_move(board, player)
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
- def reset_handler():
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(),-1,None,None,[]))
134
- img=gr.Image(value=board_to_image(initialize_board(),(initialize_board(),-1,None,None,[])),interactive=True)
135
- new_btn=gr.Button("New Game")
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()