jigsawR / docs /PILES-notation.md
pjt222's picture
Upload folder using huggingface_hub
e232e39 verified
# PILES: Puzzle Input Line Entry System
A SMILES-inspired notation for specifying puzzle piece fusion groups in jigsawR.
## Overview
PILES (Puzzle Input Line Entry System) is a domain-specific notation for describing which puzzle pieces should be fused together. It is inspired by chemistry's [SMILES notation](https://en.wikipedia.org/wiki/Simplified_Molecular_Input_Line_Entry_System) for representing molecular structures.
Just as SMILES uses simple ASCII strings to represent complex molecular bonds, PILES uses simple strings to represent puzzle piece connections.
## Quick Reference
| Syntax | Meaning | Example |
|--------|---------|---------|
| `n` | Piece ID | `1`, `15`, `42` |
| `-` | Fusion bond | `1-2` (fuse pieces 1 and 2) |
| `,` | Separate groups | `1-2,3-4` (two independent groups) |
| `.` | Separate groups (alt) | `1-2.3-4` (same as comma) |
| `n:m` | Range | `1:6` (pieces 1 through 6) |
| `()` | Branching | `1-2(-3)-4` (2 bonds to 1, 3, and 4) |
| `@n` | Ring closure | `1-2-3-4@1` (4 connects back to 1) |
| `[D]` | Direction hint | `1-2[E]-3` (optional validation) |
| `ALL-n` | Exclusion | `ALL-5` (all except piece 5) |
| `!n` | Exclusion (alt) | `!5` (same as ALL-5) |
## Basic Syntax
### Piece IDs
Numbers represent piece IDs (1-indexed):
```
1 # Piece 1 alone
15 # Piece 15 alone
```
### Fusion Bonds (-)
Hyphens indicate pieces that should be fused together:
```
1-2 # Fuse pieces 1 and 2
1-2-3 # Linear chain: 1 + 2 + 3 fused together
1-2-3-4-5 # Longer chain
```
### Multiple Groups (,)
Commas separate independent fusion groups:
```
1-2,3-4 # Two groups: (1,2) and (3,4)
1-2-3,4-5,6-7 # Three groups
```
### Range Notation (:)
Colons specify consecutive piece ranges:
```
1:6 # Pieces 1, 2, 3, 4, 5, 6 fused together
10:15 # Pieces 10 through 15
```
## Advanced Syntax
### Branching
Parentheses define branches from a junction piece:
```
1-2(-3)-4 # Piece 2 connects to 1, 3, AND 4
# Forms a T-junction
1-2(-3)(-4)-5 # Piece 2 connects to 1, 3, 4, AND 5
# Multiple branches from piece 2
```
### Ring Closures
The `@` symbol with a piece number indicates a ring closure (connecting back to form a cycle):
```
1-2-3-4@1 # Piece 4 connects back to piece 1
# Forms a closed ring: 1-2-3-4-1
1-2-3-4-5-6@1 # Hexagonal ring closure
```
### Direction Specifiers (Optional)
Square brackets can specify connection directions for validation:
```
# Rectangular puzzles
1-2[E]-3 # 2's East edge connects to 3
1[S]-5 # 1's South edge connects to 5
# Directions: [N]orth, [E]ast, [S]outh, [W]est
# Hexagonal puzzles
1-2[0]-3 # Side 0 connection
# Sides: [0] through [5]
# Concentric puzzles
1-2[O]-3 # Outer edge connection
# Directions: [I]nner, [R]ight, [O]uter, [L]eft
```
## Special Keywords
PILES supports special keywords that expand to groups of pieces based on puzzle structure.
> **Note:** All keywords are **case-insensitive**. `all`, `ALL`, and `All` are equivalent.
### Universal Keywords
| Keyword | Meaning |
|---------|---------|
| `all` | All pieces in the puzzle (creates a single meta piece) |
| `boundary` | All boundary/edge pieces |
| `border` | Same as `boundary` |
| `edge` | Same as `boundary` |
| `inner` | All non-boundary pieces |
| `center` | Center piece (hexagonal/concentric) |
### The `all` Keyword - Single Meta Piece
The `all` keyword fuses every piece in the puzzle into a single "meta piece". This is useful for:
- Creating a puzzle where all internal edges are styled differently (dashed/hidden)
- Generating a single connected piece with complex internal structure
- Testing fusion rendering across all edges
```r
# Create a puzzle where all pieces are fused into one
result <- generate_puzzle(
type = "rectangular",
grid = c(3, 3),
size = c(300, 300),
fusion_groups = "all", # Fuse ALL pieces
fusion_style = "dashed", # Show internal edges as dashed
save_files = FALSE
)
# All 9 pieces will have the same fusion_group
# All internal edges will be rendered with dashed style
# Only the outer boundary remains solid
```
### Hexagonal & Concentric Keywords
| Keyword | Meaning |
|---------|---------|
| `ring0` | Center piece (same as `center`) |
| `ring1` | All pieces in ring 1 |
| `ring2` | All pieces in ring 2 |
| `ringN` | All pieces in ring N |
### Rectangular Keywords
| Keyword | Meaning |
|---------|---------|
| `R1` or `row1` | All pieces in row 1 (top) |
| `R2` or `row2` | All pieces in row 2 |
| `C1` or `col1` | All pieces in column 1 (left) |
| `C2` or `col2` | All pieces in column 2 |
### Keyword Examples
```r
# Fuse all boundary pieces together
parse_piles("boundary", puzzle_result)
# Fuse center with first ring
parse_piles("center-ring1", puzzle_result)
# Fuse entire first row
parse_piles("R1", puzzle_result)
# Fuse columns 1 and 2
parse_piles("C1,C2", puzzle_result)
```
## Exclusion Syntax
PILES supports exclusion patterns to fuse "all pieces except..." This is useful when you want to fuse most pieces but leave a few separate.
### Exclusion Patterns
| Syntax | Meaning | Example |
|--------|---------|---------|
| `ALL-n` | All pieces except n | `ALL-5` (all except piece 5) |
| `ALL-n-m` | All pieces except n and m | `ALL-1-9` (all except 1 and 9) |
| `!n` | All pieces except n | `!5` (same as `ALL-5`) |
| `!n!m` | All pieces except n and m | `!1!7` (all except 1 and 7) |
### Exclusion Examples
```r
# Create a 3x3 puzzle (9 pieces)
puzzle <- generate_puzzle(
type = "rectangular",
grid = c(3, 3),
seed = 42
)
# Fuse all except the center piece (piece 5)
parse_piles("ALL-5", puzzle)
# Returns: list(c(1L, 2L, 3L, 4L, 6L, 7L, 8L, 9L))
# Fuse all except corners (pieces 1, 3, 7, 9)
parse_piles("!1!3!7!9", puzzle)
# Returns: list(c(2L, 4L, 5L, 6L, 8L))
# Direct use with generate_puzzle
result <- generate_puzzle(
type = "rectangular",
grid = c(3, 3),
fusion_groups = "ALL-5", # Fuse all except center
save_files = FALSE
)
```
### Combining Exclusion with Other Syntax
Exclusion patterns create single fusion groups. To create multiple groups with exclusions, use comma separation:
```r
# NOT YET SUPPORTED: combining exclusion with regular groups
# "ALL-5,1-2" would need future implementation
```
**Note**: Exclusion syntax requires puzzle context to know the total number of pieces. It cannot be used with `parse_piles()` without providing a `puzzle_result`.
## R Functions
### Core Functions
#### `parse_piles()`
Parse PILES notation into fusion groups:
```r
parse_piles("1-2-3,4-5")
# Returns: list(c(1L, 2L, 3L), c(4L, 5L))
parse_piles("1:6")
# Returns: list(c(1L, 2L, 3L, 4L, 5L, 6L))
# With puzzle context for keywords
puzzle <- generate_puzzle(type = "rectangular", grid = c(3, 2))
parse_piles("R1", puzzle)
# Returns: list(c(1L, 2L, 3L)) # First row
```
#### `to_piles()`
Convert fusion groups back to PILES notation:
```r
to_piles(list(c(1, 2), c(3, 4, 5)))
# Returns: "1-2,3-4-5"
to_piles(list(1:6))
# Returns: "1:6" # Compact range notation
to_piles(list(c(3, 1, 2)), compact = FALSE)
# Returns: "1-2-3" # Sorted, hyphen-separated
```
#### `parse_fusion()`
Universal parser that auto-detects format:
```r
# PILES format
parse_fusion("1-2-3,4-5")
# Legacy format (also supported)
parse_fusion("(1,2),(3,4)")
# List format (also supported)
parse_fusion(list(c(1, 2), c(3, 4)))
```
#### `validate_piles_syntax()`
Validate PILES string syntax:
```r
validate_piles_syntax("1-2-3,4-5")
# Returns: list(valid = TRUE, message = "Valid PILES syntax", warnings = character())
validate_piles_syntax("1-2((3")
# Returns: list(valid = FALSE, message = "Unbalanced parentheses: 2 open, 1 close")
```
## Examples
### Rectangular Puzzle Fusions
```r
puzzle <- generate_puzzle(type = "rectangular", grid = c(4, 3), seed = 42)
# Fuse horizontal pairs
parse_piles("1-2,3-4,5-6,7-8,9-10,11-12", puzzle)
# Fuse entire rows
parse_piles("R1,R2,R3", puzzle)
# Create 2x2 meta-pieces
parse_piles("1-2-5-6,3-4-7-8,9-10,11-12", puzzle)
```
### Hexagonal Puzzle Fusions
```r
puzzle <- generate_puzzle(type = "hexagonal", grid = c(3), seed = 42)
# Fuse center with first ring
parse_piles("center-ring1", puzzle)
# Fuse adjacent pairs in outer ring
parse_piles("8-9,10-11,12-13,14-15,16-17,18-19", puzzle)
```
### Concentric Puzzle Fusions
```r
puzzle <- generate_puzzle(type = "concentric", grid = c(3), seed = 42)
# Fuse entire rings
parse_piles("ring0,ring1,ring2", puzzle)
# Fuse center to all neighbors
parse_piles("1-2-3-4-5-6-7", puzzle)
```
## Comparison with SMILES
| Feature | SMILES (Chemistry) | PILES (Puzzles) |
|---------|-------------------|-----------------|
| Atoms/Pieces | C, N, O... | 1, 2, 3... |
| Bonds | `-`, `=`, `#` | `-` only |
| Branching | `()` | `()` |
| Ring closure | Digit pairs | `@n` |
| Groups | `.` | `,` or `.` |
### Key Differences
1. **PILES uses explicit ring closure syntax** (`@n`) instead of SMILES' implicit digit matching
2. **PILES has puzzle-specific keywords** (`ring1`, `R1`, `boundary`, etc.)
3. **PILES only has single bonds** (fusion is binary: connected or not)
4. **PILES uses numeric IDs** instead of element symbols
## Technical Details
### Parsing Order
1. Split by group separators (`,` or `.`)
2. Check for special keywords
3. Handle range notation (`:`)
4. Process ring closures (`@n`)
5. Remove direction specifiers (`[...]`)
6. Parse structure with branching
7. Validate adjacency (optional)
### Auto-Detection
The `parse_fusion()` function auto-detects format:
- **Legacy format**: Starts with `(` or contains `(n,n)` pattern
- **PILES format**: Contains `-` or keywords
### Performance
- Tokenization is O(n) where n is string length
- Keyword expansion may require puzzle structure lookup
- Pre-allocated vectors used for O(n) performance
## References
- [SMILES Notation (Wikipedia)](https://en.wikipedia.org/wiki/Simplified_Molecular_Input_Line_Entry_System)
- [OpenSMILES Specification](http://opensmiles.org/opensmiles.html)
- [jigsawR Package Documentation](../README.md)