1use crate::util::bitboard::BitBoard8;
2use crate::util::coord::Coord8;
3use std::fmt::{Display, Formatter};
4
5#[derive(Debug, Default, Copy, Clone)]
6pub struct Mask {
7 one: u64,
8 zero: u64,
9}
10
11pub fn cover_masks(requirements: &[Mask]) -> Vec<(Mask, Vec<usize>)> {
14 let mut result: Vec<(Mask, Vec<usize>)> = vec![];
17 'outer: for (req_index, &req) in requirements.iter().enumerate() {
18 for (cand, map) in &mut result {
19 if let Some(new) = cand.merge(req) {
20 *cand = new;
21 map.push(req_index);
22 continue 'outer;
23 }
24 }
25 result.push((req, vec![req_index]));
26 }
27 result
28}
29
30impl Mask {
31 fn new(one: u64, zero: u64) -> Option<Self> {
32 if one & zero == 0 {
33 Some(Mask { one, zero })
34 } else {
35 None
36 }
37 }
38
39 fn merge(self, other: Mask) -> Option<Mask> {
40 Mask::new(self.one | other.one, self.zero | other.zero)
41 }
42
43 pub fn one(&self) -> u64 {
44 self.one
45 }
46
47 pub fn zero(&self) -> u64 {
48 self.zero
49 }
50}
51
52pub type Operation = fn(BitBoard8) -> BitBoard8;
53
54pub fn find_requirements(ops: &[(i32, Operation)], result_mask: u64) -> Vec<Mask> {
55 let mut requirements = vec![];
56
57 for &(shift, op) in ops {
58 let mut mask_one = 0;
59 let mut mask_zero = 0;
60
61 for coord in Coord8::all() {
62 let before = BitBoard8::coord(coord).0 & result_mask;
63 let after_correct = op(BitBoard8(before)).0 & result_mask;
64 let after_shift = apply_shift(before, shift) & result_mask;
65
66 assert_eq!(after_correct & !after_shift, 0, "Shift must cover correct");
67 mask_one |= after_correct;
68 mask_zero |= after_shift & !after_correct;
69 }
70
71 requirements.push(Mask::new(mask_one, mask_zero).unwrap());
72 }
73
74 requirements
75}
76
77impl Display for Mask {
78 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
79 for y in (0..8).rev() {
80 for x in 0..8 {
81 let coord = Coord8::from_xy(x, y);
82
83 let c = match (BitBoard8(self.one).has(coord), BitBoard8(self.zero).has(coord)) {
84 (true, false) => '1',
85 (false, true) => '0',
86 (false, false) => '.',
87 (true, true) => 'x',
88 };
89
90 write!(f, "{}", c)?;
91 }
92 writeln!(f)?;
93 }
94 Ok(())
95 }
96}
97
98fn apply_shift(x: u64, delta: i32) -> u64 {
99 if delta >= 0 {
100 x << delta as u32
101 } else {
102 x >> (-delta) as u32
103 }
104}