File size: 8,407 Bytes
67acd34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# Puzzle Verifier - How to Use

## Overview

The `verifier.py` script verifies whether an ASCII representation of a puzzle state is correctly solved. It supports five puzzle types: **bridges**, **undead**, **galaxies**, **pattern**, and **loopy**.

## Supported Puzzle Types

| Puzzle Type | Default Argument | Solved Field | Notes |
|------------|------------------|--------------|-------|
| **bridges** | `5x5deL` | `completed` | Checks structural validity before verification |
| **undead** | `4x4` | `solved` | Checks structural validity before verification |
| **galaxies** | `4x4` | `completed` | Direct verification |
| **pattern** | `5x5` | `completed` | Direct verification |
| **loopy** | `5x5t0` | `solved` | Handles dimension validation errors gracefully |

## How It Works

The verifier uses a **parse → load → check** pipeline:

1. **Parse**: Converts ASCII text to a structured state dictionary using puzzle-specific parsers
2. **Load**: Loads the state dictionary into the puzzle's C backend
3. **Check**: Queries the puzzle's solved/completed flag to determine if the state is valid

### Verification Process

For each puzzle type:

1. **Bridges & Undead**: 
   - First performs structural validity checks (ensures no broken lines, modified clues, etc.)
   - If structurally invalid, returns "NOT SOLVED" immediately
   - Otherwise, parses and verifies the state

2. **Galaxies, Pattern, Loopy**:
   - Directly parses the ASCII state
   - For loopy, handles dimension validation errors (treats malformed responses as "NOT SOLVED")

3. **Error Handling**:
   - Dimension validation errors (invalid canvas width/height) are treated as "NOT SOLVED" (model mistakes)
   - Other parsing errors are re-raised as exceptions

## Usage

### Basic Usage

#### From Command Line Argument

```bash
# Bridges
python verifier.py bridges "3|.|2\n..."

# Undead
python verifier.py undead "G: 3 V: 1 Z: 6\n\n   2 3 1 1  \n..."

# Galaxies
python verifier.py galaxies "+-+-+\n|o o|\n+-+-+\n|o o|\n+-+-+\n"

# Pattern
python verifier.py pattern " 1 2 3\n 4 5 6\n 7 8 9\n"

# Loopy
python verifier.py loopy " x x x - x \nx x0x |3| x\n..."
```

#### From Standard Input

```bash
# Read from file
python verifier.py bridges < ascii_state.txt

# Pipe from another command
echo "3|.|2\n..." | python verifier.py bridges

# Multi-line input
cat <<EOF | python verifier.py undead
G: 3 V: 1 Z: 6

   2 3 1 1  
   1 2 3 4
EOF
```

### With Custom Puzzle Arguments

Use the `--arg` flag to specify puzzle initialization parameters:

```bash
# Bridges with custom size and difficulty
python verifier.py bridges --arg "7x7dm" "..."

# Undead with custom size
python verifier.py undead --arg "5x5" "..."

# Galaxies with custom size
python verifier.py galaxies --arg "6x6" "..."

# Pattern with custom size
python verifier.py pattern --arg "10x10" "..."

# Loopy with custom grid (square grid, type 0)
python verifier.py loopy --arg "7x7t0" "..."
```

### Escape Sequences

The verifier automatically converts escape sequences in command-line arguments:

```bash
# \n is converted to actual newlines
python verifier.py bridges "3|.|2\n4|.|3\n5|.|2"
```

## Output

The verifier prints one of two results:

- **`SOLVED`** - The puzzle state is correctly solved (exit code 0)
- **`NOT SOLVED`** - The puzzle state is not solved or invalid (exit code 1)

### Example Output

```bash
$ python verifier.py bridges "3|.|2\n..."
SOLVED

$ echo $?
0

$ python verifier.py bridges "3|.|2\n..."  # Invalid state
NOT SOLVED

$ echo $?
1
```

## Puzzle-Specific Details

### Bridges

- **Structural Validity**: Checks for broken lines, modified clues, and invalid connections
- **Solved Field**: Uses `completed` flag
- **Default Arg**: `5x5deL` (5x5, difficulty easy, left-right symmetry)

### Undead

- **Structural Validity**: Checks for missing header, invalid grid format, and malformed state
- **Solved Field**: Uses `solved` flag (not `completed`)
- **Default Arg**: `4x4` (4x4 grid)

### Galaxies

- **Direct Verification**: No structural validity pre-check
- **Solved Field**: Uses `completed` flag
- **Default Arg**: `4x4` (4x4 grid)

### Pattern

- **Direct Verification**: No structural validity pre-check
- **Solved Field**: Uses `completed` flag
- **Default Arg**: `5x5` (5x5 grid)
- **Note**: Leading spaces are significant for clue alignment

### Loopy

- **Dimension Validation**: Handles invalid canvas dimensions gracefully (treats as "NOT SOLVED")
- **Solved Field**: Uses `solved` flag
- **Default Arg**: `5x5t0` (5x5 square grid, type 0)
- **Grid Type**: Currently only supports square grids (`grid_type=0`)
- **Note**: Reuses existing puzzle instances to avoid conflicts when called programmatically

## Programmatic Usage

The verifier can also be used as a Python module:

```python
from rlp.puzzle import Puzzle
from verifier import verify_ascii_state

# Create and initialize puzzle
puzzle = Puzzle('bridges', arg='5x5deL', headless=True)
puzzle.new_game()

# Verify ASCII state
ascii_text = "3|.|2\n..."
result = verify_ascii_state(puzzle, ascii_text)

if result == "SOLVED":
    print("Puzzle is solved!")
else:
    print("Puzzle is not solved.")
```

### Important Notes for Programmatic Usage

1. **Puzzle Instance**: The puzzle must be initialized with `new_game()` before calling `verify_ascii_state()`
2. **Loopy Puzzles**: When verifying loopy puzzles, the verifier automatically reuses the provided puzzle instance to avoid creating temporary instances (prevents conflicts)
3. **Memory Management**: The verifier automatically frees loaded states after verification
4. **Error Handling**: Dimension validation errors are caught and treated as "NOT SOLVED" for loopy puzzles

## Error Handling

### Dimension Validation Errors

For loopy puzzles, if the ASCII text has invalid dimensions (e.g., malformed model responses), the verifier returns "NOT SOLVED" instead of raising an exception. This handles cases where:

- Canvas width doesn't satisfy `W = 2*w + 2` (W-2 must be even)
- Canvas height doesn't satisfy `H = 2*h + 1` (H-1 must be even)
- Dimensions don't match expected relationships

### Other Errors

- **Parsing Errors**: If the ASCII text cannot be parsed (except dimension errors), an exception is raised
- **Invalid Puzzle Type**: If an unsupported puzzle type is specified, an error is raised
- **Missing Input**: If no ASCII state is provided, the script exits with an error

## Examples

### Example 1: Verify a Bridges Puzzle

```bash
# Create a solved bridges state
cat > bridges_solved.txt <<EOF
3|.|2
-+-+-
.|.|.
-+-+-
2|.|3
EOF

# Verify it
python verifier.py bridges < bridges_solved.txt
# Output: SOLVED
```

### Example 2: Verify Multiple Puzzles

```bash
# Verify bridges
echo "..." | python verifier.py bridges

# Verify undead
echo "..." | python verifier.py undead

# Verify galaxies
echo "..." | python verifier.py galaxies
```

### Example 3: Use in Scripts

```bash
#!/bin/bash
result=$(python verifier.py bridges "$ascii_state")
if [ "$result" == "SOLVED" ]; then
    echo "Correct!"
else
    echo "Incorrect or invalid state"
fi
```

## Integration with Evaluation Scripts

The verifier is used by:

- **`evaluate-predictions.py`**: Evaluates model predictions from CSV files
- **`evaluate_puzzle_type_worker.py`**: Worker script for parallel evaluation
- **`test_verifier.py`**: Test suite for verifier functionality

These scripts use `verify_ascii_state()` programmatically to check if model-generated puzzle solutions are correct.

## Troubleshooting

### Issue: "Error: No ASCII state provided"

**Solution**: Ensure you're providing ASCII input either via command-line argument or stdin.

### Issue: Dimension validation errors for loopy

**Solution**: This is expected behavior for malformed model responses. The verifier correctly treats these as "NOT SOLVED".

### Issue: Parsing errors

**Solution**: Check that the ASCII format matches the expected puzzle format. Each puzzle type has a specific ASCII representation format.

### Issue: Puzzle instance conflicts (loopy)

**Solution**: The verifier automatically handles this by reusing puzzle instances. If you're creating multiple puzzle instances programmatically, ensure proper cleanup.

## See Also

- `test_verifier.py` - Test suite with examples
- `evaluate-predictions.py` - Evaluation script using the verifier
- `rlp/ascii_parser.py` - ASCII parsing implementations for each puzzle type