Spaces:
Sleeping
Sleeping
File size: 22,537 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 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 | # ASCII Parser Implementation Template
This template provides step-by-step instructions for implementing ASCII parsers for puzzle games. Use this guide to create parsers for new puzzle types following the established pattern from bridges and undead implementations.
## Table of Contents
1. [Overview](#overview)
2. [Prerequisites](#prerequisites)
3. [Step-by-Step Implementation](#step-by-step-implementation)
4. [Code Structure](#code-structure)
5. [Testing Strategy](#testing-strategy)
6. [Integration Checklist](#integration-checklist)
7. [Common Patterns and Examples](#common-patterns-and-examples)
8. [Troubleshooting](#troubleshooting)
---
## Overview
### Purpose
The ASCII parser converts ASCII text representations of puzzle states into Python dictionaries that match the format produced by `get_puzzle_state_<puzzle_name>()` functions. This enables:
- **Verification**: Check if an ASCII state (from LLM or other sources) is solved
- **State Loading**: Load arbitrary puzzle states from ASCII text
- **Round-trip Testing**: Verify ASCII → state dict → load → format → ASCII works correctly
- **Integration**: Use ASCII states with existing `load_state_dict` functionality
### Pipeline
```
ASCII Text → Structural Validation → Parse (Python) → State Dict → Load (C) → Game State → Verify/Format
```
1. **Structural Validation** (Python): Quick check if ASCII looks valid
2. **Parse ASCII** (Python): Convert ASCII text to state dictionary
3. **Load State Dict** (C): Use existing `load_state_dict_<puzzle>()` function
4. **Verify/Format** (C): Check `completed`/`solved` flag or format back to ASCII
---
## Prerequisites
Before starting, you need:
1. **Access to C source code**: `puzzles/<puzzle_name>.c`
2. **Understanding of ASCII format**: Study `game_text_format()` function in C
3. **Understanding of state dict format**: Review `get_puzzle_state_<puzzle_name>()` in `rlp/specific_api.py`
4. **Understanding of load function**: Review `load_state_dict_<puzzle_name>()` in `rlp/specific_api.py`
5. **Example ASCII states**: Have sample problem and solution states to test with
---
## Step-by-Step Implementation
### Phase 1: Research and Understanding
#### Step 1.1: Study the C ASCII Format Function
**Location**: `puzzles/<puzzle_name>.c`
**Function**: `game_text_format()`
**What to look for**:
- How the function formats the puzzle state to ASCII
- What characters represent different cell types
- How dimensions are represented
- What the header/prefix looks like (if any)
- How multi-line structures are formatted
**Example questions to answer**:
- What characters represent different cell states?
- Are there special characters for different values?
- How are dimensions encoded?
- Is there a header line (like "G: X V: Y Z: Z" for undead)?
- How are edge clues/borders represented?
**Document your findings**:
```python
# ASCII Format for <puzzle_name>:
# - Header: <description>
# - Cell types:
# - <char1>: <meaning>
# - <char2>: <meaning>
# - Grid structure: <description>
```
#### Step 1.2: Study the State Dict Format
**Location**: `rlp/specific_api.py`
**Function**: `get_puzzle_state_<puzzle_name>()`
**What to look for**:
- Required top-level fields
- Nested structures (like `common` for undead)
- Array types and lengths
- Field names and types
- Which fields are canonical (required) vs derived (computed by C)
**Key insight**: Only include canonical fields in the parser output. Derived fields should be initialized to zeros/False and computed by C code.
**Document the structure**:
```python
# State dict format for <puzzle_name>:
{
"field1": <type>, # Required
"field2": <type>, # Required
"nested": { # If applicable
"subfield1": <type>,
},
"derived_array": [0] * size, # Will be computed by C
}
```
#### Step 1.3: Study Cell Type Constants
**Location**: `puzzles/<puzzle_name>.c`
**What to look for**:
- `#define` statements for grid flags
- `enum` definitions for cell types
- Any constants used to represent cell states
**Example**:
```c
// From undead.c:
enum {
CELL_EMPTY,
CELL_MIRROR_L,
CELL_MIRROR_R,
CELL_GHOST,
CELL_VAMPIRE,
CELL_ZOMBIE,
};
```
**Action**: Copy these exact values to Python constants in `rlp/ascii_parser.py`
#### Step 1.4: Study the Load Function
**Location**: `rlp/specific_api.py`
**Function**: `load_state_dict_<puzzle_name>()`
**What to look for**:
- Required fields validation
- Array length requirements
- Type requirements
- Which fields are optional vs required
**This tells you**: What fields your parser MUST produce for the state dict to load successfully.
---
### Phase 2: Structural Validity Checker (Optional but Recommended)
#### Step 2.1: Implement `check_<puzzle_name>_structural_validity()`
**Purpose**: Quick validation before parsing to catch obviously invalid inputs.
**Location**: `rlp/ascii_parser.py`
**What to check**:
- [ ] Has required header/prefix (if applicable)
- [ ] Has grid structure present
- [ ] Grid has minimum dimensions
- [ ] Not empty text
- [ ] Not just long unstructured text
- [ ] Basic format sanity checks
**Template**:
```python
def check_<puzzle_name>_structural_validity(ascii_text: str) -> bool:
"""
Check structural validity of a <puzzle_name> ASCII state.
Validates:
1. <Check 1>
2. <Check 2>
3. <Check 3>
Args:
ascii_text: The ASCII representation of the puzzle state
Returns:
bool: True if structurally valid, False otherwise
"""
if not ascii_text or not ascii_text.strip():
return False
lines = ascii_text.strip().split('\n')
if len(lines) == 0:
return False
# Check for required header/prefix
# <implementation>
# Check for grid structure
# <implementation>
# Check minimum dimensions
# <implementation>
# Check for invalid patterns (long text, etc.)
# <implementation>
return True
```
**Testing**: Create test cases with valid and invalid inputs.
---
### Phase 3: Parser Implementation
#### Step 3.1: Add Constants
**Location**: `rlp/ascii_parser.py`
Add cell type constants matching C definitions:
```python
# Cell types matching <puzzle_name>.c enum/defines
CONSTANT_NAME_1 = <value>
CONSTANT_NAME_2 = <value>
# ... etc
```
**Important**: Values must match C exactly (copy hex values, enum values, etc.)
#### Step 3.2: Implement Dimension Inference
**Pattern**:
```python
# First pass: infer dimensions
lines = ascii_text.strip().split('\n')
h = len(lines)
if h == 0:
raise ValueError("ASCII text must contain at least one line")
# Find maximum width (handle variable line lengths)
max_w = 0
for line in lines:
stripped = line.rstrip()
w = len(stripped)
if w > max_w:
max_w = w
if max_w == 0:
raise ValueError("ASCII text must contain at least one non-whitespace character")
w = max_w
```
**Variations**:
- Some puzzles have fixed-width cells (e.g., undead: 2 characters per cell)
- Some puzzles have headers to skip
- Some puzzles have border cells to account for
#### Step 3.3: Implement Cell-by-Cell Parsing
**Pattern**:
```python
# Initialize arrays
wh = w * h # or (w+2)*(h+2) if including border
grid = [0] * wh
other_array = [0] * wh
structures = [] # For puzzle-specific structures (islands, etc.)
# Parse each cell
for y, line in enumerate(lines):
stripped = line.rstrip()
for x in range(w):
if x >= len(stripped):
# Line is shorter, treat as empty
continue
c = stripped[x] # or cell_str = stripped[x*2:(x+1)*2] for fixed-width
idx = y * w + x # or y * grid_w + x if including border
# Parse based on character/cell
if c == '<char1>':
grid[idx] = CONSTANT_1
# ... set other fields
elif c == '<char2>':
grid[idx] = CONSTANT_2
# ... set other fields
# ... etc
```
**Key considerations**:
- Handle variable line lengths gracefully
- Map ASCII characters to cell type constants
- Build puzzle-specific structures (islands, monsters, etc.)
- Track indices correctly (especially if grid includes border)
#### Step 3.4: Build State Dict
**Pattern**:
```python
state_dict = {
# Required top-level fields
"field1": value1,
"field2": value2,
# Nested structures (if applicable)
"nested": {
"params": {
"w": w,
"h": h,
# Only include canonical params, omit generation params
},
"array1": array1,
"array2": array2,
},
# Derived arrays - initialized to zeros, computed by C code
"derived_array": [0] * size,
# Status flags - will be computed by C code
"completed": False,
"solved": False,
}
```
**Important**:
- Only include canonical fields (required for `load_state_dict`)
- Initialize derived arrays to zeros
- Set `completed`/`solved` to False (C will compute)
- Omit generation params (islands, expansion, difficulty, etc.)
#### Step 3.5: Add Error Handling
**Pattern**:
```python
def parse_ascii_<puzzle_name>(ascii_text: str) -> dict:
"""
Parse ASCII text representation of a <puzzle_name> puzzle and return a state dict.
Args:
ascii_text: The ASCII representation of the puzzle state
Returns:
dict: State dictionary matching get_puzzle_state_<puzzle_name> format
Raises:
ValueError: If the ASCII text is invalid or empty
"""
if not ascii_text or not ascii_text.strip():
raise ValueError("ASCII text cannot be empty")
# ... parsing logic ...
# Validate dimensions
if w < 1 or h < 1:
raise ValueError(f"Invalid grid dimensions: w={w}, h={h}")
# ... return state_dict ...
```
---
### Phase 4: Testing
#### Step 4.1: Create Test File
**Location**: `test_ascii_parser_<puzzle_name>.py`
**Template structure**:
```python
"""
Test script for <puzzle_name> ASCII parser round-trip functionality.
"""
import sys
import os
import pandas as pd
from rlp import puzzle as rp
from rlp.ascii_parser import parse_ascii_<puzzle_name>, check_<puzzle_name>_structural_validity
def test_parse_example():
"""Test parsing with a known example."""
# <example ASCII>
# ... test logic ...
def test_structural_validity():
"""Test structural validity checker."""
# Valid examples
# Invalid examples
# ... test logic ...
def test_round_trip():
"""Test round-trip: ASCII → parse → load → format → ASCII."""
# ... test logic ...
def test_csv_predictions_round_trip():
"""Test round-trip for all problems and solutions in CSV."""
# ... test logic ...
if __name__ == "__main__":
# Run all tests
# ... test runner ...
```
#### Step 4.2: Test Cases to Include
1. **Basic parsing test**: Known valid ASCII state
2. **Structural validity test**: Valid and invalid examples
3. **Round-trip test**: Generate puzzle → get ASCII → parse → load → format → compare
4. **Edge cases**: Empty states, single cell, maximum size, special characters
5. **CSV round-trip**: Test all problems/solutions from dataset
#### Step 4.3: Round-Trip Test Pattern
**Critical test**:
```python
# 1. Get ASCII from a puzzle state
ascii_original = game.text_format(state).decode('utf-8')
# 2. Parse with Python parser
state_dict = parse_ascii_<puzzle_name>(ascii_original)
# 3. Load into C
loaded_state_ptr = puzzle.load_state_dict(state_dict)
# 4. Format back to ASCII
ascii_loaded = game.text_format(loaded_state_ptr.contents).decode('utf-8')
# 5. Compare (should match exactly)
assert ascii_original.strip() == ascii_loaded.strip()
```
---
### Phase 5: Integration
#### Step 5.1: Update Verifier
**Location**: `verifier.py`
**Changes needed**:
1. Import parser function: `from rlp.ascii_parser import parse_ascii_<puzzle_name>, check_<puzzle_name>_structural_validity`
2. Add puzzle type case in `verify_ascii_state()`:
```python
elif puzzle_type == "<puzzle_name>":
# First check structural validity
if not check_<puzzle_name>_structural_validity(str(ascii_text)):
return "NOT SOLVED"
# Parse ASCII with Python parser
state_dict = parse_ascii_<puzzle_name>(str(ascii_text))
# Load state dict
loaded_state_ptr = puzzle.load_state_dict(state_dict)
# Get free_game function
me = puzzle.fe.contents.me.contents
game = me.ourgame.contents
free_game_func = game.free_game
try:
# Check if solved (use correct field: completed or solved)
is_solved = loaded_state_ptr.contents.<field> # completed or solved
if is_solved:
return "SOLVED"
else:
return "NOT SOLVED"
finally:
if loaded_state_ptr:
free_game_func(loaded_state_ptr)
```
**Important**: Check which field the puzzle uses (`completed` for bridges, `solved` for undead)
#### Step 5.2: Update Test Verifier
**Location**: `test_verifier.py`
**Changes needed**:
1. Add puzzle type parameter to test functions
2. Add puzzle-specific configuration (difficulty args, puzzle name in CSV)
3. Add puzzle type to command-line argument choices
#### Step 5.3: Update Evaluate Predictions (if applicable)
**Location**: `evaluate-predictions.py`
**Changes needed**:
1. Add puzzle type to command-line arguments
2. Add puzzle-specific configuration
3. Update puzzle name filtering
---
## Code Structure
### File: `rlp/ascii_parser.py`
**Structure**:
```python
# Constants for puzzle 1
CONSTANT_1 = value1
CONSTANT_2 = value2
# Structural validity for puzzle 1
def check_puzzle1_structural_validity(ascii_text: str) -> bool:
...
# Parser for puzzle 1
def parse_ascii_puzzle1(ascii_text: str) -> dict:
...
# Constants for puzzle 2
CONSTANT_3 = value3
# Structural validity for puzzle 2
def check_puzzle2_structural_validity(ascii_text: str) -> bool:
...
# Parser for puzzle 2
def parse_ascii_puzzle2(ascii_text: str) -> dict:
...
```
### Function Signature Template
```python
def parse_ascii_<puzzle_name>(ascii_text: str) -> dict:
"""
Parse ASCII text representation of a <puzzle_name> puzzle and return a state dict.
ASCII Format:
- <Description of format>
- <Cell types and meanings>
- <Special structures>
Args:
ascii_text: The ASCII representation of the puzzle state
Returns:
dict: State dictionary matching get_puzzle_state_<puzzle_name> format
Raises:
ValueError: If the ASCII text is invalid or empty
"""
# Implementation
```
---
## Testing Strategy
### Unit Tests (Parser-Specific)
**File**: `test_ascii_parser_<puzzle_name>.py`
**Test categories**:
1. **Basic parsing**: Valid ASCII states parse correctly
2. **Structural validity**: Valid vs invalid inputs
3. **Edge cases**: Empty, single cell, max size, special characters
4. **Round-trip**: ASCII → parse → load → format → ASCII (must match)
5. **CSV integration**: Test with real dataset
### Integration Tests (Verifier)
**File**: `test_verifier.py`
**Test categories**:
1. **CSV predictions**: Problems return `solved=False`, solutions return `solved=True`
2. **State comparison**: Compare two similar ASCII states
3. **Large-scale testing**: Test all problems/solutions from dataset
---
## Integration Checklist
### Parser Implementation
- [ ] Constants defined matching C values
- [ ] Structural validity checker implemented (optional but recommended)
- [ ] Parser function implemented
- [ ] State dict format matches `get_puzzle_state_<puzzle_name>()` exactly
- [ ] Error handling added
- [ ] Documentation added
### Testing
- [ ] Unit tests created (`test_ascii_parser_<puzzle_name>.py`)
- [ ] Structural validity tests pass
- [ ] Round-trip tests pass
- [ ] Edge case tests pass
- [ ] CSV round-trip tests pass (if applicable)
### Integration
- [ ] Verifier updated (`verifier.py`)
- [ ] Test verifier updated (`test_verifier.py`)
- [ ] Evaluate predictions updated (if applicable)
- [ ] All tests pass
---
## Common Patterns and Examples
### Pattern 1: Simple Grid (like bridges)
```python
# Dimension inference
lines = ascii_text.strip().split('\n')
h = len(lines)
w = max(len(line.rstrip()) for line in lines)
# Cell-by-cell parsing
for y, line in enumerate(lines):
for x in range(w):
c = line[x] if x < len(line.rstrip()) else None
idx = y * w + x
# Parse character
```
### Pattern 2: Grid with Border (like undead)
```python
# Grid is (w+2) x (h+2) including border
grid_w = max_cells # from parsing
grid_h = len(grid_lines)
w = grid_w - 2
h = grid_h - 2
# Cell-by-cell parsing with border
for y, line in enumerate(grid_lines):
for x in range(grid_w):
cell_str = line[x*2:(x+1)*2] # 2-character cells
idx = y * grid_w + x
# Parse cell
```
### Pattern 3: Header + Grid
```python
# Parse header
first_line = lines[0].strip()
# Extract header information
# Find grid start
grid_start = 1
if len(lines) > 1 and lines[1].strip() == '':
grid_start = 2
grid_lines = lines[grid_start:]
# Parse grid
```
### Pattern 4: Helper Functions
```python
def helper_function_for_puzzle(x, y, w, h):
"""
Helper function ported from C.
Args:
x, y: Coordinates
w, h: Dimensions
Returns:
<return type>
"""
# Ported logic from C
pass
```
---
## Troubleshooting
### Common Issues and Solutions
#### Issue 1: State Dict Format Mismatch
**Symptom**: `load_state_dict()` raises ValueError about missing fields
**Solution**:
- Compare your state dict with output from `get_puzzle_state_<puzzle_name>()`
- Ensure all required fields are present
- Check field names match exactly (case-sensitive)
- Verify array lengths match requirements
#### Issue 2: Round-Trip Mismatch
**Symptom**: ASCII after round-trip doesn't match original
**Solution**:
- Check dimension inference is correct
- Verify cell parsing maps characters correctly
- Ensure border cells are handled correctly (if applicable)
- Check if whitespace differences matter (use `.strip()` for comparison)
#### Issue 3: Grid Flags Don't Match
**Symptom**: Parsed state doesn't behave correctly
**Solution**:
- Verify constants match C `#define` values exactly
- Check hex values are correct (0x0001 vs 0x001, etc.)
- Ensure bitwise operations are correct
#### Issue 4: Derived Arrays Issues
**Symptom**: Errors about array access or computation
**Solution**:
- Initialize derived arrays to zeros (don't try to compute in Python)
- Let C code recompute them
- Ensure array lengths are correct
#### Issue 5: Memory Leaks
**Symptom**: Memory usage grows over time
**Solution**:
- Always use try/finally to free loaded states
- Call `free_game_func(loaded_state_ptr)` in finally block
- Don't forget to free states in test loops
#### Issue 6: Structural Validity Too Strict/Loose
**Symptom**: Valid states rejected or invalid states accepted
**Solution**:
- Adjust validation criteria
- Test with edge cases
- Balance between catching errors and being lenient
---
## Quick Reference
### Key Files
- **Parser implementation**: `rlp/ascii_parser.py`
- **State dict format**: `rlp/specific_api.py` (`get_puzzle_state_<puzzle_name>()`)
- **Load function**: `rlp/specific_api.py` (`load_state_dict_<puzzle_name>()`)
- **C ASCII format**: `puzzles/<puzzle_name>.c` (`game_text_format()`)
- **C state structure**: `puzzles/<puzzle_name>.c` (struct definitions)
- **Verifier**: `verifier.py`
- **Tests**: `test_ascii_parser_<puzzle_name>.py`, `test_verifier.py`
### Key Functions
- `parse_ascii_<puzzle_name>(ascii_text: str) -> dict`: Main parser
- `check_<puzzle_name>_structural_validity(ascii_text: str) -> bool`: Quick validation
- `verify_ascii_state(puzzle, ascii_text: str) -> str`: Verifier integration
- `puzzle.load_state_dict(state_dict: dict)`: Load state into C
### Key Principles
1. **Match formats exactly**: State dict must match `get_puzzle_state_<puzzle_name>()` exactly
2. **Minimal canonical fields**: Only include what's needed for reconstruction
3. **Let C compute derived fields**: Initialize derived arrays to zeros
4. **Round-trip testing is critical**: ASCII → parse → load → format → ASCII must match
5. **Handle edge cases**: Variable line lengths, special characters, empty states
6. **Memory management**: Always free loaded states
7. **Test with real data**: Use actual problems and solutions from datasets
---
## Example: Complete Implementation Checklist
For a new puzzle called "example":
### Phase 1: Research
- [ ] Study `puzzles/example.c` `game_text_format()` function
- [ ] Review `get_puzzle_state_example()` in `rlp/specific_api.py`
- [ ] Review `load_state_dict_example()` in `rlp/specific_api.py`
- [ ] Identify all ASCII characters and their meanings
- [ ] Identify cell type constants from C source
- [ ] Understand the puzzle's state structure
### Phase 2: Implementation
- [ ] Add constants to `rlp/ascii_parser.py`
- [ ] Implement `check_example_structural_validity()` (optional)
- [ ] Implement `parse_ascii_example()` function
- [ ] Test with known examples
### Phase 3: Testing
- [ ] Create `test_ascii_parser_example.py`
- [ ] Test structural validity (if implemented)
- [ ] Test basic parsing
- [ ] Test round-trip
- [ ] Test edge cases
- [ ] Test with CSV (if applicable)
### Phase 4: Integration
- [ ] Update `verifier.py` to use new parser
- [ ] Update `test_verifier.py` to test example puzzle
- [ ] Update `evaluate-predictions.py` (if applicable)
- [ ] Verify all tests pass
---
## References
- Bridges parser: `rlp/ascii_parser.py` (`parse_ascii_bridges`, `check_bridges_structural_validity`)
- Undead parser: `rlp/ascii_parser.py` (`parse_ascii_undead`, `check_undead_structural_validity`)
- Original guide: `ASCII_PARSER_IMPLEMENTATION_GUIDE_new.md`
- State dict format: `rlp/specific_api.py`
- C text format: `puzzles/<puzzle_name>.c` (`game_text_format()`)
- Tests: `test_ascii_parser.py`, `test_ascii_parser_undead.py`, `test_verifier.py`
---
## Notes
- This template is based on successful implementations for bridges and undead puzzles
- Adapt patterns to your specific puzzle's requirements
- When in doubt, refer to existing implementations (bridges, undead) as examples
- Test thoroughly with real data before considering implementation complete
- Round-trip testing is the most important validation
|