SmokeyBandit commited on
Commit
007713f
·
verified ·
1 Parent(s): ce61b08

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +213 -0
app.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ from enum import Enum
4
+ import random
5
+
6
+ class Difficulty(Enum):
7
+ EASY = "Easy"
8
+ MEDIUM = "Medium"
9
+ HARD = "Hard"
10
+
11
+ class GoGame:
12
+ def __init__(self, size=9):
13
+ self.size = size
14
+ self.board = np.zeros((size, size))
15
+ self.current_player = 1 # 1 for black, -1 for white
16
+ self.last_move = None
17
+ self.pass_count = 0
18
+
19
+ def is_valid_move(self, x, y):
20
+ if x < 0 or x >= self.size or y < 0 or y >= self.size:
21
+ return False
22
+ if self.board[x][y] != 0:
23
+ return False
24
+ # Make move temporarily to check for suicide rule
25
+ self.board[x][y] = self.current_player
26
+ has_liberties = self.has_liberties(x, y)
27
+ self.board[x][y] = 0
28
+ return has_liberties
29
+
30
+ def get_neighbors(self, x, y):
31
+ neighbors = []
32
+ for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
33
+ nx, ny = x + dx, y + dy
34
+ if 0 <= nx < self.size and 0 <= ny < self.size:
35
+ neighbors.append((nx, ny))
36
+ return neighbors
37
+
38
+ def has_liberties(self, x, y):
39
+ color = self.board[x][y]
40
+ checked = set()
41
+
42
+ def check_group(x, y):
43
+ if (x, y) in checked:
44
+ return False
45
+ checked.add((x, y))
46
+
47
+ for nx, ny in self.get_neighbors(x, y):
48
+ if self.board[nx][ny] == 0:
49
+ return True
50
+ if self.board[nx][ny] == color and check_group(nx, ny):
51
+ return True
52
+ return False
53
+
54
+ return check_group(x, y)
55
+
56
+ def make_move(self, x, y):
57
+ if not self.is_valid_move(x, y):
58
+ return False
59
+
60
+ self.board[x][y] = self.current_player
61
+ self.last_move = (x, y)
62
+ self.pass_count = 0
63
+ self.current_player *= -1
64
+ return True
65
+
66
+ def ai_move(self, difficulty):
67
+ if difficulty == Difficulty.EASY:
68
+ return self.random_move()
69
+ elif difficulty == Difficulty.MEDIUM:
70
+ return self.medium_move()
71
+ else:
72
+ return self.hard_move()
73
+
74
+ def random_move(self):
75
+ valid_moves = []
76
+ for i in range(self.size):
77
+ for j in range(self.size):
78
+ if self.is_valid_move(i, j):
79
+ valid_moves.append((i, j))
80
+
81
+ if not valid_moves:
82
+ return None
83
+
84
+ move = random.choice(valid_moves)
85
+ self.make_move(*move)
86
+ return move
87
+
88
+ def medium_move(self):
89
+ # Medium difficulty tries to play near the last human move
90
+ if self.last_move is None:
91
+ return self.random_move()
92
+
93
+ last_x, last_y = self.last_move
94
+ for radius in range(1, self.size):
95
+ valid_moves = []
96
+ for dx in range(-radius, radius + 1):
97
+ for dy in range(-radius, radius + 1):
98
+ if abs(dx) + abs(dy) == radius:
99
+ x, y = last_x + dx, last_y + dy
100
+ if 0 <= x < self.size and 0 <= y < self.size and self.is_valid_move(x, y):
101
+ valid_moves.append((x, y))
102
+
103
+ if valid_moves:
104
+ move = random.choice(valid_moves)
105
+ self.make_move(*move)
106
+ return move
107
+
108
+ return self.random_move()
109
+
110
+ def hard_move(self):
111
+ # Hard difficulty tries to control the center and corners
112
+ center = self.size // 2
113
+ priority_moves = [
114
+ (center, center),
115
+ (1, 1), (1, self.size-2), (self.size-2, 1), (self.size-2, self.size-2),
116
+ (center, 1), (1, center), (center, self.size-2), (self.size-2, center)
117
+ ]
118
+
119
+ for x, y in priority_moves:
120
+ if self.is_valid_move(x, y):
121
+ self.make_move(x, y)
122
+ return (x, y)
123
+
124
+ return self.medium_move()
125
+
126
+ def create_board_image(board):
127
+ # Convert board to RGB image
128
+ image = np.zeros((board.shape[0], board.shape[1], 3), dtype=np.uint8)
129
+ image.fill(222) # Wooden background color
130
+
131
+ # Draw grid lines
132
+ for i in range(board.shape[0]):
133
+ image[i, :] = [150, 150, 150]
134
+ image[:, i] = [150, 150, 150]
135
+
136
+ # Draw stones
137
+ for i in range(board.shape[0]):
138
+ for j in range(board.shape[1]):
139
+ if board[i, j] == 1: # Black stone
140
+ image[i, j] = [0, 0, 0]
141
+ elif board[i, j] == -1: # White stone
142
+ image[i, j] = [255, 255, 255]
143
+
144
+ return image
145
+
146
+ class GradioGoGame:
147
+ def __init__(self):
148
+ self.game = GoGame()
149
+ self.difficulty = Difficulty.EASY
150
+
151
+ def make_move(self, x, y, difficulty):
152
+ if x is None or y is None:
153
+ return create_board_image(self.game.board), "Invalid move"
154
+
155
+ x, y = int(x), int(y)
156
+ self.difficulty = Difficulty(difficulty)
157
+
158
+ if not self.game.make_move(x, y):
159
+ return create_board_image(self.game.board), "Invalid move"
160
+
161
+ # AI move
162
+ ai_move = self.game.ai_move(self.difficulty)
163
+ if ai_move is None:
164
+ return create_board_image(self.game.board), "Game Over"
165
+
166
+ return create_board_image(self.game.board), f"AI moved to: {ai_move}"
167
+
168
+ def reset_game(self):
169
+ self.game = GoGame()
170
+ return create_board_image(self.game.board), "Game reset"
171
+
172
+ def create_interface():
173
+ game = GradioGoGame()
174
+
175
+ with gr.Blocks() as interface:
176
+ gr.Markdown("# Go Game vs AI")
177
+
178
+ with gr.Row():
179
+ with gr.Column():
180
+ board_output = gr.Image(
181
+ create_board_image(game.game.board),
182
+ shape=(400, 400),
183
+ label="Go Board"
184
+ )
185
+ msg_output = gr.Textbox(label="Message", value="Click on the board to make a move")
186
+
187
+ with gr.Column():
188
+ x_input = gr.Number(label="X coordinate (0-8)")
189
+ y_input = gr.Number(label="Y coordinate (0-8)")
190
+ difficulty = gr.Radio(
191
+ choices=[d.value for d in Difficulty],
192
+ value=Difficulty.EASY.value,
193
+ label="Difficulty"
194
+ )
195
+ move_btn = gr.Button("Make Move")
196
+ reset_btn = gr.Button("Reset Game")
197
+
198
+ move_btn.click(
199
+ game.make_move,
200
+ inputs=[x_input, y_input, difficulty],
201
+ outputs=[board_output, msg_output]
202
+ )
203
+
204
+ reset_btn.click(
205
+ game.reset_game,
206
+ outputs=[board_output, msg_output]
207
+ )
208
+
209
+ return interface
210
+
211
+ if __name__ == "__main__":
212
+ interface = create_interface()
213
+ interface.launch()