puz_parse/
types.rs

1use std::collections::HashMap;
2
3/// A complete crossword puzzle parsed from a .puz file.
4///
5/// This is the main data structure returned by the parsing functions.
6/// It contains all the information needed to display and interact with
7/// a crossword puzzle.
8///
9/// # Examples
10///
11/// ```rust,no_run
12/// use puz_parse::parse_file;
13///
14/// let puzzle = parse_file("puzzle.puz")?;
15/// println!("Title: {}", puzzle.info.title);
16/// println!("Grid size: {}x{}", puzzle.info.width, puzzle.info.height);
17/// println!("Number of across clues: {}", puzzle.clues.across.len());
18/// # Ok::<(), Box<dyn std::error::Error>>(())
19/// ```
20#[derive(Debug, Clone, PartialEq)]
21#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
22pub struct Puzzle {
23    /// Basic puzzle metadata (title, author, dimensions, etc.)
24    pub info: PuzzleInfo,
25    /// The puzzle grid (solution and blank grids)
26    pub grid: Grid,
27    /// Clues organized by direction and number
28    pub clues: Clues,
29    /// Optional puzzle extensions (rebus, circles, etc.)
30    pub extensions: Extensions,
31}
32
33/// Basic information about the puzzle.
34///
35/// Contains metadata like title, author, dimensions, and format information.
36#[derive(Debug, Clone, PartialEq)]
37#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
38pub struct PuzzleInfo {
39    /// Puzzle title
40    pub title: String,
41    /// Author name(s)
42    pub author: String,
43    /// Copyright information
44    pub copyright: String,
45    /// Additional notes or instructions
46    pub notes: String,
47    /// Grid width (number of columns)
48    pub width: u8,
49    /// Grid height (number of rows)
50    pub height: u8,
51    /// File format version
52    pub version: String,
53    /// Whether the puzzle solution is scrambled
54    pub is_scrambled: bool,
55}
56
57/// The puzzle grid containing both solution and blank layouts.
58///
59/// The grid is represented as vectors of strings, where each string is a row.
60/// Characters represent:
61/// - `.` = black/blocked square
62/// - `-` = empty square (in blank grid)
63/// - Letters/numbers = cell content
64#[derive(Debug, Clone, PartialEq)]
65#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
66pub struct Grid {
67    /// The blank grid as presented to the solver (with `-` for empty squares)
68    pub blank: Vec<String>,
69    /// The solution grid with all answers filled in
70    pub solution: Vec<String>,
71}
72
73/// Clues organized by direction and number.
74///
75/// Clue numbers correspond to the starting squares in the grid.
76/// The ordering follows standard crossword conventions.
77#[derive(Debug, Clone, PartialEq)]
78#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
79pub struct Clues {
80    /// Across clues mapped by clue number
81    pub across: HashMap<u16, String>,
82    /// Down clues mapped by clue number
83    pub down: HashMap<u16, String>,
84}
85
86/// Optional puzzle extensions for advanced features.
87///
88/// These fields contain additional puzzle information like rebus squares
89/// (multi-letter cells), circled squares, and given squares.
90#[derive(Debug, Clone, PartialEq)]
91#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
92pub struct Extensions {
93    /// Rebus squares (cells with multiple letters), if present
94    pub rebus: Option<Rebus>,
95    /// Grid indicating which squares are circled, if any
96    pub circles: Option<Vec<Vec<bool>>>,
97    /// Grid indicating which squares were given to the solver, if any
98    pub given: Option<Vec<Vec<bool>>>,
99}
100
101/// Rebus information for squares containing multiple letters.
102///
103/// A rebus allows a single square to contain multiple letters or words.
104/// The grid indicates which squares are rebus squares, and the table
105/// maps rebus keys to their string values.
106#[derive(Debug, Clone, PartialEq)]
107#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
108pub struct Rebus {
109    /// Grid indicating rebus keys (0 = no rebus, 1-255 = rebus key)
110    pub grid: Vec<Vec<u8>>,
111    /// Mapping of rebus keys to their string values
112    pub table: HashMap<u8, String>,
113}
114
115pub(crate) const FREE_SQUARE: char = '-';
116pub(crate) const TAKEN_SQUARE: char = '.';