Skip to main content

slidy/
lib.rs

1//! A crate containing various utilities for working with sliding puzzles. The only sliding puzzles
2//! supported are arbitrary-sized versions of the
3//! [15 puzzle](https://en.wikipedia.org/wiki/15_puzzle), other puzzles such as higher dimensional
4//! variants of the 15 puzzle, bandaged sliding puzzles, klotski, sokoban, etc. are not supported.
5//!
6//! # Examples
7//!
8//! ## Apply a sequence of moves to a puzzle
9//!
10//! ```
11//! use std::str::FromStr as _;
12//!
13//! use slidy::{
14//!     algorithm::algorithm::Algorithm,
15//!     puzzle::{puzzle::Puzzle, sliding_puzzle::SlidingPuzzle},
16//! };
17//!
18//! fn main() -> Result<(), Box<dyn std::error::Error>> {
19//!     let mut puzzle = Puzzle::from_str("8 2 0/4 6 1/3 7 5")?;
20//!     let algorithm = Algorithm::from_str("R2U2LDLDRURDLULDRULURDLU")?;
21//!     puzzle.apply_alg(&algorithm);
22//!
23//!     assert!(puzzle.is_solved());
24//!
25//!     Ok(())
26//! }
27//! ```
28//!
29//! ## Generate random state scrambles
30//!
31//! ```
32//! use slidy::puzzle::{
33//!     puzzle::Puzzle,
34//!     scrambler::{RandomState, Scrambler},
35//!     size::Size,
36//! };
37//!
38//! # #[cfg(feature = "thread_rng")]
39//! fn main() -> Result<(), Box<dyn std::error::Error>> {
40//!     let mut p = Puzzle::new(Size::new(5, 5)?);
41//!
42//!     for _ in 0..10 {
43//!         // Requires the `thread_rng` feature to be enabled.
44//!         // Otherwise, `scramble_with_rng` can be used with a custom `Rng`.
45//!         RandomState.scramble(&mut p);
46//!         println!("{p}");
47//!     }
48//!
49//!     Ok(())
50//! }
51//!
52//! # #[cfg(not(feature = "thread_rng"))]
53//! # fn main() {}
54//! ```
55//!
56//! ## Find an optimal solution
57//!
58//! ```
59//! use std::str::FromStr as _;
60//!
61//! use slidy::{
62//!     puzzle::{puzzle::Puzzle, sliding_puzzle::SlidingPuzzle},
63//!     solver::solver::Solver,
64//! };
65//!
66//! fn main() -> Result<(), Box<dyn std::error::Error>> {
67//!     let mut puzzle = Puzzle::from_str("0 10 6 4/1 5 14 15/13 11 8 7/3 2 9 12")?;
68//!
69//!     let mut solver = Solver::default();
70//!     let solution = solver.solve(&puzzle)?;
71//!
72//!     println!("Solution: {} ({} moves)", solution, solution.len_stm::<u64>());
73//!
74//!     puzzle.apply_alg(&solution);
75//!     assert!(puzzle.is_solved());
76//!
77//!     Ok(())
78//! }
79//! ```
80//!
81//! ## Create an SVG image of a puzzle
82//!
83//! ```
84//! use palette::rgb::Rgba;
85//! use slidy::puzzle::{
86//!     color_scheme::{ColorScheme, Scheme},
87//!     coloring::{Monochrome, Rainbow},
88//!     label::label::{SplitFringe, Trivial},
89//!     puzzle::Puzzle,
90//!     render::{Borders, RendererBuilder, Text},
91//! };
92//!
93//! fn main() -> Result<(), Box<dyn std::error::Error>> {
94//!     let scheme = Box::new(Scheme::new(
95//!         Trivial,
96//!         Monochrome::new(Rgba::new(0.15, 0.15, 0.15, 1.0)),
97//!     )) as Box<dyn ColorScheme>;
98//!
99//!     let border_scheme =
100//!         Box::new(Scheme::new(SplitFringe, Rainbow::default())) as Box<dyn ColorScheme>;
101//!
102//!     let text_scheme = Box::new(Scheme::new(
103//!         Trivial,
104//!         Monochrome::new(Rgba::new(1.0, 1.0, 1.0, 1.0)),
105//!     )) as Box<dyn ColorScheme>;
106//!
107//!     let renderer = RendererBuilder::with_dyn_scheme(scheme)
108//!         .borders(Borders::with_scheme(border_scheme).thickness(5.0))
109//!         .text(Text::with_scheme(text_scheme).font_size(40.0))
110//!         .background_color(Rgba::new(0.05, 0.05, 0.05, 1.0))
111//!         .tile_size(75.0)
112//!         .tile_gap(5.0)
113//!         .tile_rounding(10.0)
114//!         .padding(10.0)
115//!         .build();
116//!
117//!     let puzzle = Puzzle::default();
118//!
119//!     let svg = renderer.render(&puzzle)?;
120//!     svg::save("out.svg", &svg)?;
121//!
122//!     Ok(())
123//! }
124//! ```
125//!
126//! # Safe, panicking, and unsafe functions
127//!
128//! Some functions defined in this crate have variants with names of the form `foo`, `try_foo`, and
129//! `foo_unchecked`, with the following behavior:
130//!
131//! - The functions `foo` may panic, return invalid results, or create invalid states when given
132//!   invalid arguments.
133//! - The functions `try_foo` should return `None` when given invalid arguments, and should never
134//!   panic. In most cases, the default implementations of these functions call `foo` with the
135//!   appropriate checks included.
136//! - The functions `foo_unchecked` should be considered `unsafe` and are intended for situations
137//!   where performance is important. The default implementations of these functions do not contain
138//!   any unsafe code, and most of them are just a call to `foo` or a re-implementation of `foo`
139//!   using other unchecked functions.
140
141#![cfg_attr(feature = "nightly", feature(test))]
142#![deny(missing_docs)]
143#![deny(rustdoc::broken_intra_doc_links)]
144
145pub mod algorithm;
146pub mod puzzle;
147pub mod solver;