diff --git a/src/card.rs b/src/card.rs index 3dfbfe1..c562557 100644 --- a/src/card.rs +++ b/src/card.rs @@ -114,19 +114,177 @@ impl Card { /// Cuts this Card on the given line. Returns two cards pub fn cut(self, line: CutLine) -> (Self, Self) { - todo!(); + let is_cut: fn(usize, usize) -> bool = match line { + CutLine::VertLeft => |x, _| x > 0, + CutLine::VertRight => |x, _| x > 1, + CutLine::HorizUpper => |_, y| y > 0, + CutLine::HorizLower => |_, y| y > 1, + }; + + let mut first_card = Self::default(); + let mut second_card = Self::default(); + + macro_rules! perform_cut { + ( $dir:ident, $index:literal ) => { + if is_cut($index % 3, $index / 3) { + second_card.cells[$index] = self.cells[$index]; + second_card.$dir = self.$dir; + } else { + first_card.cells[$index] = self.cells[$index]; + first_card.$dir = self.$dir; + } + }; + + ( $index:literal ) => { + if is_cut($index % 3, $index / 3) { + second_card.cells[$index] = self.cells[$index]; + } else { + first_card.cells[$index] = self.cells[$index]; + } + }; + } + + perform_cut!(nw, 0); + perform_cut!(n, 1); + perform_cut!(ne, 2); + perform_cut!(w, 3); + perform_cut!(4); + perform_cut!(e, 5); + perform_cut!(sw, 6); + perform_cut!(s, 7); + perform_cut!(se, 8); + + (first_card, second_card) } pub fn flip(self, flip: FlipDir) -> Self { - todo!(); + let mut new_card = Self::default(); + + // Check for doors + macro_rules! assign_cell { + ( ($source_dir:ident, $source_index:literal), ($dest_dir:ident, $dest_index:literal), $repeat:expr ) => { + new_card.cells[$dest_index] = self.cells[$source_index]; + new_card.$dest_dir = self.$source_dir; + if $repeat == true { + new_card.cells[$source_index] = self.cells[$dest_index]; + new_card.$source_dir = self.$dest_dir; + } + }; + } + + match flip { + FlipDir::Horizontal => { + assign_cell!((nw, 0), (ne, 2), true); + assign_cell!((w, 3), (e, 5), true); + assign_cell!((sw, 6), (se, 8), true); + assign_cell!((n, 1), (n, 1), false); + assign_cell!((s, 7), (s, 7), false); + } + FlipDir::Vertical => { + assign_cell!((nw, 0), (sw, 6), true); + assign_cell!((n, 1), (s, 7), true); + assign_cell!((ne, 2), (se, 8), true); + assign_cell!((w, 3), (w, 3), false); + assign_cell!((e, 5), (e, 5), false); + } + } + + new_card.cells[4] = self.cells[4]; + + new_card } pub fn transpose(self, other: Self, selection: TransposeSelection) -> (Self, Self) { - todo!(); + let is_transposed: fn(usize, usize) -> bool = match selection { + TransposeSelection::Column(TransposeIndex::First) => |x, _| x == 0, + TransposeSelection::Column(TransposeIndex::Second) => |x, _| x == 1, + TransposeSelection::Column(TransposeIndex::Third) => |x, _| x == 2, + TransposeSelection::Row(TransposeIndex::First) => |_, y| y == 0, + TransposeSelection::Row(TransposeIndex::Second) => |_, y| y == 1, + TransposeSelection::Row(TransposeIndex::Third) => |_, y| y == 2, + }; + + let mut first_card = Self::default(); + let mut second_card = Self::default(); + + macro_rules! perform_transpose { + ( $dir:ident, $index:literal ) => { + if is_transposed($index % 3, $index / 3) { + first_card.cells[$index] = other.cells[$index]; + second_card.cells[$index] = self.cells[$index]; + + first_card.$dir = other.$dir; + second_card.$dir = self.$dir; + } else { + first_card.cells[$index] = self.cells[$index]; + second_card.cells[$index] = other.cells[$index]; + + first_card.$dir = self.$dir; + second_card.$dir = other.$dir; + } + }; + + ( $index:literal ) => { + if is_transposed($index % 3, $index / 3) { + first_card.cells[$index] = other.cells[$index]; + second_card.cells[$index] = self.cells[$index]; + } else { + first_card.cells[$index] = self.cells[$index]; + second_card.cells[$index] = other.cells[$index]; + } + }; + } + + perform_transpose!(nw, 0); + perform_transpose!(n, 1); + perform_transpose!(ne, 2); + perform_transpose!(w, 3); + perform_transpose!(4); + perform_transpose!(e, 5); + perform_transpose!(sw, 6); + perform_transpose!(s, 7); + perform_transpose!(se, 8); + + (first_card, second_card) } - pub fn rotate(self, dir: RotationDir) { - todo!(); + pub fn rotate(self, dir: RotationDir) -> Self { + let mut new_card = Self::default(); + + // Check for doors + macro_rules! assign_cell { + ( ($source_dir:ident, $source_index:literal), ($dest_dir:ident, $dest_index:literal) ) => { + new_card.cells[$dest_index] = self.cells[$source_index]; + new_card.$dest_dir = self.$source_dir; + }; + } + + match dir { + RotationDir::Clockwise => { + assign_cell!((nw, 0), (n, 1)); + assign_cell!((n, 1), (ne, 2)); + assign_cell!((ne, 2), (e, 5)); + assign_cell!((e, 5), (se, 8)); + assign_cell!((se, 8), (s, 7)); + assign_cell!((s, 7), (sw, 6)); + assign_cell!((sw, 6), (w, 3)); + assign_cell!((w, 3), (nw, 0)); + } + RotationDir::CounterClockwise => { + assign_cell!((nw, 0), (w, 3)); + assign_cell!((w, 3), (sw, 6)); + assign_cell!((sw, 6), (s, 7)); + assign_cell!((s, 7), (se, 8)); + assign_cell!((se, 8), (e, 5)); + assign_cell!((e, 5), (ne, 2)); + assign_cell!((ne, 2), (n, 1)); + assign_cell!((n, 1), (nw, 0)); + } + } + + new_card.cells[4] = self.cells[4]; + + new_card } }