hangman_solver_lib/
lib.rs1#![warn(
3 clippy::missing_const_for_fn,
4 clippy::nursery,
5 clippy::pedantic,
6 clippy::todo
7)]
8#![deny(clippy::indexing_slicing, clippy::panic, clippy::unwrap_used)]
9#![allow(clippy::missing_errors_doc, clippy::option_if_let_else)]
10#![deny(unsafe_code)]
11mod language;
12mod solver;
13
14pub use crate::solver::{
15 CharCollection, HangmanResult, InfallibleCharCollection, Pattern,
16};
17
18pub use crate::language::{Language, StringChunkIter, WordSequence};
19
20#[cfg(feature = "wasm-bindgen")]
21pub use crate::solver::WasmHangmanResult;
22#[cfg(feature = "wasm-bindgen")]
23use js_sys::JsString;
24#[cfg(feature = "pyo3")]
25use pyo3::types::PyString;
26#[cfg(feature = "wasm-bindgen")]
27use wasm_bindgen::prelude::*;
28
29#[cfg(feature = "pyo3")]
30pub use crate::language::UnknownLanguageError;
31#[cfg(feature = "pyo3")]
32use pyo3::prelude::*;
33
34#[cfg(feature = "pyo3")]
35#[derive(FromPyObject)]
36pub enum InvalidLetters<'py> {
37 String(Bound<'py, PyString>),
38 Chars(Vec<char>),
39}
40
41#[cfg(feature = "pyo3")]
42#[pyfunction]
43#[pyo3(signature = (pattern_string, invalid_letters, language, max_words_to_collect))]
44#[allow(clippy::needless_pass_by_value)]
45pub fn solve(
46 pattern_string: Bound<'_, PyString>,
47 invalid_letters: InvalidLetters<'_>,
48 language: Language,
49 max_words_to_collect: usize,
50) -> PyResult<HangmanResult> {
51 match invalid_letters {
52 InvalidLetters::String(invalid_letters) => crate::solver::solve(
53 &pattern_string,
54 &invalid_letters,
55 true,
56 language,
57 Some(max_words_to_collect),
58 ),
59 InvalidLetters::Chars(invalid_letters) => crate::solver::solve(
60 &pattern_string,
61 &invalid_letters,
62 true,
63 language,
64 Some(max_words_to_collect),
65 ),
66 }
67}
68
69#[cfg(feature = "pyo3")]
70#[pyfunction]
71#[pyo3(signature = (pattern_string, invalid_letters, language, max_words_to_collect))]
72#[allow(clippy::needless_pass_by_value)]
73pub fn solve_crossword(
74 pattern_string: Bound<'_, PyString>,
75 invalid_letters: InvalidLetters<'_>,
76 language: Language,
77 max_words_to_collect: usize,
78) -> PyResult<HangmanResult> {
79 match invalid_letters {
80 InvalidLetters::String(invalid_letters) => crate::solver::solve(
81 &pattern_string,
82 &invalid_letters,
83 false,
84 language,
85 Some(max_words_to_collect),
86 ),
87 InvalidLetters::Chars(invalid_letters) => crate::solver::solve(
88 &pattern_string,
89 &invalid_letters,
90 false,
91 language,
92 Some(max_words_to_collect),
93 ),
94 }
95}
96
97#[must_use]
98#[cfg(feature = "pyo3")]
99#[pyfunction]
100#[pyo3(signature = (language, word_length))]
101pub const fn read_words_with_length(
102 language: Language,
103 word_length: usize,
104) -> WordSequence {
105 language.read_words(word_length)
106}
107
108#[cfg(feature = "pyo3")]
109#[pymodule]
110#[pyo3(name = "_solver")]
111pub fn hangman_solver(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
112 m.add_function(wrap_pyfunction!(solve, m)?)?;
113 m.add_function(wrap_pyfunction!(solve_crossword, m)?)?;
114 m.add_function(wrap_pyfunction!(read_words_with_length, m)?)?;
115 m.add(
116 "UnknownLanguageError",
117 py.get_type::<UnknownLanguageError>(),
118 )?;
119 m.add_class::<HangmanResult>()?;
120 m.add_class::<Language>()?;
121 Ok(())
122}
123
124#[cfg(feature = "wasm-bindgen")]
125#[wasm_bindgen]
126#[allow(clippy::needless_pass_by_value)]
127pub fn solve_hangman(
128 all_words: Vec<JsString>,
129 pattern_string: JsString,
130 invalid_letters: JsString,
131 max_words_to_collect: usize,
132 crossword_mode: bool,
133) -> Result<WasmHangmanResult, JsValue> {
134 use crate::solver::solve_js;
135
136 Ok(solve_js(
137 &mut all_words.iter(),
138 &pattern_string,
139 &invalid_letters,
140 Some(max_words_to_collect),
141 crossword_mode,
142 ))
143}