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