1use std::{fmt::Display, ops::Deref};
2
3pub mod words;
4pub mod state;
5pub mod game;
6pub mod iter;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub enum Match {
11 Exact,
13 Close,
15 Wrong,
17}
18
19#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
21pub struct Matches(pub [Match; 5]);
22
23impl Matches {
24 pub fn win(self) -> bool {
25 self.0 == [Match::Exact; 5]
26 }
27}
28
29impl Display for Match {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 match self {
32 Match::Exact => write!(f, "🟩"),
33 Match::Close => write!(f, "🟨"),
34 Match::Wrong => write!(f, "⬛"),
35 }
36 }
37}
38
39impl Display for Matches {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 for m in self.0 {
42 write!(f, "{}", m)?;
43 }
44 write!(f, "")
45 }
46}
47
48impl Deref for Matches {
49 type Target = [Match; 5];
50
51 fn deref(&self) -> &Self::Target {
52 &self.0
53 }
54}
55
56pub fn diff(input: &str, solution: &str) -> Matches {
57 debug_assert!(
58 input.is_ascii(),
59 "input guess should only be 5 ascii letters"
60 );
61 debug_assert_eq!(input.len(), 5, "input guess should only be 5 ascii letters");
62 debug_assert!(solution.is_ascii());
63 debug_assert_eq!(solution.len(), 5);
64
65 let input = input.as_bytes();
66 let mut solution = solution.as_bytes().to_owned();
67
68 let mut diff = [Match::Wrong; 5];
69
70 for (i, &b) in input.iter().enumerate() {
72 if solution[i] == b {
73 solution[i] = 0; diff[i] = Match::Exact;
75 }
76 }
77
78 for (i, &b) in input.iter().enumerate() {
80 if diff[i] != Match::Wrong {
81 continue;
82 }
83 if let Some(j) = solution.iter().position(|&x| x == b) {
84 solution[j] = 0; diff[i] = Match::Close;
86 }
87 }
88
89 Matches(diff)
90}
91
92#[cfg(test)]
93mod tests {
94 use super::{
95 diff,
96 Match::{self, *},
97 };
98 use test_case::test_case;
99
100 #[test_case("class", "crest", [Exact, Wrong, Wrong, Exact, Wrong]; "double letter, one exact, one wrong")]
101 #[test_case("stars", "crest", [Close, Close, Wrong, Close, Wrong]; "double letter, one close, one wrong")]
102 #[test_case("kills", "skill", [Close, Close, Close, Exact, Close]; "double letter, one exact, one close")]
103 fn test_diff(input: &str, solution: &str, matches: [Match; 5]) {
104 assert_eq!(diff(input, solution).0, matches);
105 }
106}