DarshanScripts commited on
Commit
ea07c2f
·
verified ·
1 Parent(s): 9c2f0ca

Upload stratego\web\utils\validators.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. stratego//web//utils//validators.py +126 -0
stratego//web//utils//validators.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Validators for move input and game state"""
2
+
3
+ import re
4
+ from typing import Tuple, Optional
5
+
6
+
7
+ # Move format: [A0 B0] where A-J are rows and 0-9 are columns
8
+ MOVE_PATTERN = r'^\s*\[\s*([A-J])(\d+)\s+([A-J])(\d+)\s*\]\s*$'
9
+
10
+
11
+ def validate_move_format(move_str: str, board_size: int = 10) -> Tuple[bool, Optional[str]]:
12
+ """
13
+ Validate move format and board boundaries.
14
+
15
+ Args:
16
+ move_str: Move string (e.g., "[A0 B0]")
17
+ board_size: Board size (4-10)
18
+
19
+ Returns:
20
+ (is_valid, error_message) - error_message is None if valid
21
+ """
22
+ if not move_str or not isinstance(move_str, str):
23
+ return False, "Move must be a non-empty string"
24
+
25
+ move_str = move_str.strip().upper()
26
+
27
+ match = re.match(MOVE_PATTERN, move_str)
28
+ if not match:
29
+ return False, "Invalid format. Use [A0 B0] where A-J are rows and 0-9 are columns"
30
+
31
+ src_row, src_col, dst_row, dst_col = match.groups()
32
+ src_col = int(src_col)
33
+ dst_col = int(dst_col)
34
+
35
+ # Check row bounds
36
+ src_row_idx = ord(src_row) - ord('A')
37
+ dst_row_idx = ord(dst_row) - ord('A')
38
+
39
+ if src_row_idx >= board_size or dst_row_idx >= board_size:
40
+ return False, f"Row out of bounds (board size: {board_size}x{board_size})"
41
+
42
+ # Check column bounds
43
+ if src_col >= board_size or dst_col >= board_size or src_col < 0 or dst_col < 0:
44
+ return False, f"Column out of bounds (board size: {board_size}x{board_size})"
45
+
46
+ # Source and destination must be different
47
+ if src_row == dst_row and src_col == dst_col:
48
+ return False, "Source and destination must be different"
49
+
50
+ return True, None
51
+
52
+
53
+ def normalize_move(move_str: str) -> str:
54
+ """
55
+ Normalize move string to standard format: [A0 B0]
56
+
57
+ Args:
58
+ move_str: Raw move string from user
59
+
60
+ Returns:
61
+ Normalized move string in uppercase
62
+ """
63
+ if not move_str:
64
+ return ""
65
+
66
+ move_str = move_str.strip().upper()
67
+
68
+ # Try to parse and reformat
69
+ match = re.match(MOVE_PATTERN, move_str)
70
+ if match:
71
+ src_row, src_col, dst_row, dst_col = match.groups()
72
+ return f"[{src_row}{src_col} {dst_row}{dst_col}]"
73
+
74
+ return move_str
75
+
76
+
77
+ def extract_move_coordinates(move_str: str) -> Optional[Tuple[Tuple[int, int], Tuple[int, int]]]:
78
+ """
79
+ Extract coordinates from move string.
80
+
81
+ Args:
82
+ move_str: Move string (e.g., "[A0 B0]")
83
+
84
+ Returns:
85
+ ((src_row, src_col), (dst_row, dst_col)) or None if invalid
86
+ """
87
+ move_str = move_str.strip().upper()
88
+ match = re.match(MOVE_PATTERN, move_str)
89
+
90
+ if not match:
91
+ return None
92
+
93
+ src_row, src_col, dst_row, dst_col = match.groups()
94
+ src_col = int(src_col)
95
+ dst_col = int(dst_col)
96
+
97
+ src_row_idx = ord(src_row) - ord('A')
98
+ dst_row_idx = ord(dst_row) - ord('A')
99
+
100
+ return ((src_row_idx, src_col), (dst_row_idx, dst_col))
101
+
102
+
103
+ def is_valid_move_string(move_str: str, legal_moves: list, board_size: int = 10) -> Tuple[bool, Optional[str]]:
104
+ """
105
+ Complete validation: format + legal moves list.
106
+
107
+ Args:
108
+ move_str: Move string from user
109
+ legal_moves: List of legal moves from observation
110
+ board_size: Board size
111
+
112
+ Returns:
113
+ (is_valid, error_message)
114
+ """
115
+ # First check format
116
+ is_valid_format, format_error = validate_move_format(move_str, board_size)
117
+ if not is_valid_format:
118
+ return False, format_error
119
+
120
+ # Normalize and check against legal moves
121
+ normalized_move = normalize_move(move_str)
122
+
123
+ if legal_moves and normalized_move not in legal_moves:
124
+ return False, f"Move {normalized_move} is not in legal moves"
125
+
126
+ return True, None