Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -40,7 +40,7 @@ Specify the column letter (a–g) for your next move.
|
|
40 |
def extract_xml_move(text: str) -> str:
|
41 |
"""
|
42 |
Extracts the move (a single column letter a–g) from the XML format
|
43 |
-
using regex.
|
44 |
"""
|
45 |
match = re.search(r'<move>\s*([a-g])\s*</move>', text)
|
46 |
if match:
|
@@ -66,7 +66,7 @@ def convert_moves_to_coordinate_list(moves_list: List[str]) -> str:
|
|
66 |
grid[row][col] = 'X' if i % 2 == 0 else 'O'
|
67 |
break
|
68 |
|
69 |
-
# Build coordinate list: Only include cells with a piece
|
70 |
coords = []
|
71 |
for row in range(6):
|
72 |
for col in range(7):
|
@@ -84,7 +84,6 @@ def parse_coordinate_list(board_str: str) -> List[List[str]]:
|
|
84 |
grid = [['.' for _ in range(7)] for _ in range(6)]
|
85 |
if not board_str.strip() or board_str == "Empty Board":
|
86 |
return grid
|
87 |
-
|
88 |
coords = board_str.split(",")
|
89 |
for coord in coords:
|
90 |
coord = coord.strip()
|
@@ -103,8 +102,12 @@ def parse_coordinate_list(board_str: str) -> List[List[str]]:
|
|
103 |
grid[row][col] = piece
|
104 |
return grid
|
105 |
|
106 |
-
def get_available_positions(
|
107 |
"""Returns the next available position (lowest empty spot) for each column."""
|
|
|
|
|
|
|
|
|
108 |
available = []
|
109 |
for col in range(7):
|
110 |
col_letter = chr(ord('a') + col)
|
@@ -133,11 +136,13 @@ class ConnectFour:
|
|
133 |
|
134 |
# Find the lowest empty row in the selected column
|
135 |
for row in range(5, -1, -1):
|
136 |
-
if self.board[5-row][col] == 0:
|
137 |
self.board[5-row][col] = self.current_player
|
|
|
|
|
|
|
|
|
138 |
|
139 |
-
# Record the move
|
140 |
-
move = f"{chr(ord('a') + col)}{row+1}"
|
141 |
if self.current_player == 1:
|
142 |
self.player_moves.append(move)
|
143 |
else:
|
@@ -191,37 +196,17 @@ class ConnectFour:
|
|
191 |
piece = "X" if self.board[row][col] == 1 else "O"
|
192 |
moves.append(f"{col_letter}{row_num}({piece})")
|
193 |
return ", ".join(moves) if moves else "Empty Board"
|
194 |
-
|
195 |
-
def get_grid_from_board(self):
|
196 |
-
grid = [['.' for _ in range(7)] for _ in range(6)]
|
197 |
-
for row in range(6):
|
198 |
-
for col in range(7):
|
199 |
-
if self.board[row][col] == 1:
|
200 |
-
grid[5-row][col] = 'X' # Convert to the format used by helper functions
|
201 |
-
elif self.board[row][col] == 2:
|
202 |
-
grid[5-row][col] = 'O'
|
203 |
-
return grid
|
204 |
|
205 |
-
def parse_ai_move(self, move_str):
|
206 |
-
# Parse move like 'a', 'b', etc.
|
207 |
-
try:
|
208 |
-
col = ord(move_str.strip().lower()) - ord('a')
|
209 |
-
if 0 <= col <= 6:
|
210 |
-
return col
|
211 |
-
return -1
|
212 |
-
except:
|
213 |
-
return -1
|
214 |
-
|
215 |
def format_game_state(self):
|
216 |
board_str = self.board_to_string()
|
217 |
-
|
218 |
-
available_positions = get_available_positions(grid)
|
219 |
|
220 |
-
# Format
|
221 |
player_moves_str = ", ".join(self.player_moves) if self.player_moves else ""
|
222 |
ai_moves_str = ", ".join(self.ai_moves) if self.ai_moves else ""
|
223 |
|
224 |
-
|
|
|
225 |
- You are playing as: O
|
226 |
- Your previous moves: {ai_moves_str}
|
227 |
- Opponent's moves: {player_moves_str}
|
@@ -230,6 +215,17 @@ class ConnectFour:
|
|
230 |
{available_positions}
|
231 |
|
232 |
Make your move."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
233 |
|
234 |
def create_interface():
|
235 |
game = ConnectFour()
|
@@ -352,8 +348,10 @@ def create_interface():
|
|
352 |
# AI move
|
353 |
game.current_player = 2
|
354 |
|
355 |
-
#
|
356 |
game_state = game.format_game_state()
|
|
|
|
|
357 |
|
358 |
# Get AI response
|
359 |
response = model.create_chat_completion(
|
|
|
40 |
def extract_xml_move(text: str) -> str:
|
41 |
"""
|
42 |
Extracts the move (a single column letter a–g) from the XML format
|
43 |
+
using an improved regex. This function is kept simple for reuse.
|
44 |
"""
|
45 |
match = re.search(r'<move>\s*([a-g])\s*</move>', text)
|
46 |
if match:
|
|
|
66 |
grid[row][col] = 'X' if i % 2 == 0 else 'O'
|
67 |
break
|
68 |
|
69 |
+
# Build coordinate list: Only include cells with a piece.
|
70 |
coords = []
|
71 |
for row in range(6):
|
72 |
for col in range(7):
|
|
|
84 |
grid = [['.' for _ in range(7)] for _ in range(6)]
|
85 |
if not board_str.strip() or board_str == "Empty Board":
|
86 |
return grid
|
|
|
87 |
coords = board_str.split(",")
|
88 |
for coord in coords:
|
89 |
coord = coord.strip()
|
|
|
102 |
grid[row][col] = piece
|
103 |
return grid
|
104 |
|
105 |
+
def get_available_positions(board_str: str) -> str:
|
106 |
"""Returns the next available position (lowest empty spot) for each column."""
|
107 |
+
# Parse the board state
|
108 |
+
grid = parse_coordinate_list(board_str)
|
109 |
+
|
110 |
+
# Find next available position in each column
|
111 |
available = []
|
112 |
for col in range(7):
|
113 |
col_letter = chr(ord('a') + col)
|
|
|
136 |
|
137 |
# Find the lowest empty row in the selected column
|
138 |
for row in range(5, -1, -1):
|
139 |
+
if self.board[5-row][col] == 0:
|
140 |
self.board[5-row][col] = self.current_player
|
141 |
+
# Store the move
|
142 |
+
col_letter = chr(ord('a') + col)
|
143 |
+
row_num = row + 1
|
144 |
+
move = f"{col_letter}{row_num}"
|
145 |
|
|
|
|
|
146 |
if self.current_player == 1:
|
147 |
self.player_moves.append(move)
|
148 |
else:
|
|
|
196 |
piece = "X" if self.board[row][col] == 1 else "O"
|
197 |
moves.append(f"{col_letter}{row_num}({piece})")
|
198 |
return ", ".join(moves) if moves else "Empty Board"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
200 |
def format_game_state(self):
|
201 |
board_str = self.board_to_string()
|
202 |
+
available_positions = get_available_positions(board_str)
|
|
|
203 |
|
204 |
+
# Format player and AI moves
|
205 |
player_moves_str = ", ".join(self.player_moves) if self.player_moves else ""
|
206 |
ai_moves_str = ", ".join(self.ai_moves) if self.ai_moves else ""
|
207 |
|
208 |
+
# Format according to the new template
|
209 |
+
game_state = f"""Game State:
|
210 |
- You are playing as: O
|
211 |
- Your previous moves: {ai_moves_str}
|
212 |
- Opponent's moves: {player_moves_str}
|
|
|
215 |
{available_positions}
|
216 |
|
217 |
Make your move."""
|
218 |
+
return game_state
|
219 |
+
|
220 |
+
def parse_ai_move(self, move_str):
|
221 |
+
# Parse move like 'a', 'b', etc.
|
222 |
+
try:
|
223 |
+
col = ord(move_str.strip().lower()) - ord('a')
|
224 |
+
if 0 <= col <= 6:
|
225 |
+
return col
|
226 |
+
return -1
|
227 |
+
except:
|
228 |
+
return -1
|
229 |
|
230 |
def create_interface():
|
231 |
game = ConnectFour()
|
|
|
348 |
# AI move
|
349 |
game.current_player = 2
|
350 |
|
351 |
+
# NEW FORMAT: Use the new game state formatting
|
352 |
game_state = game.format_game_state()
|
353 |
+
print("Sending game state to model:")
|
354 |
+
print(game_state)
|
355 |
|
356 |
# Get AI response
|
357 |
response = model.create_chat_completion(
|