Spaces:
Sleeping
Sleeping
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(
|