gridit/
pattern.rs

1//! All patterns and Pattern Trait used for [pattern](crate::Grid::pattern).
2use crate::{Position, Step};
3
4/// This trait is there to create pattern for the [PatternIter](crate::iter::PatternIter).
5/// The implemntation should only return one variant of Action.
6/// # Variants
7/// * `Action::StepFromOrigin(step_x)` if `step_x` steps outside the grid, this Action will be ignored and next_action will be called again.
8/// * `Action::Jump(position_x)` if `position_x` is outside the grid, this Action will be ignored and next_action will be called again.
9/// this action will be ignored and the nexj
10/// # Panics
11/// * if different variants of `Action` are returned
12/// * if variant Action::StepFromOrigin does not implement `rest_steps`.
13/// * if variant Action::Jump does not implement `rest_positions`.
14pub trait Pattern {
15    /// Returns the next `Action` or None if there are no more `Action`.
16    fn next_action(&mut self) -> Option<Action>;
17
18    /// Peeks in the next `Action` and returns it or None if there is no more `Action`.
19    // This is needed to to calculate the position for PositionEnumerator.
20    fn next_action_peek(&self) -> Option<Action>;
21
22    /// Returns a reference to the `Repeat`.
23    fn repeat(&self) -> &Repeat;
24
25    // rest_step and rest_positon are kind of hacks to make
26    // PositionEnumerator work with pattern
27
28    /// Returns the rest of the steps. This must be implemented for `Action::StepFromOrigin`.
29    // This is needed to get the correct position in PositionEnumerator
30    // It is only needed for StepFromOrigin action and should be used so
31    fn rest_steps(&self) -> Option<Vec<Step>> {
32        if matches!(self.next_action_peek(), Some(Action::StepFromOrigin(_))) {
33            panic!("Action::StepFromOrigin must implement rest_step");
34        }
35        None
36    }
37
38    /// Returns the rest of the positions. This must be implemented for `Action::Jump`.
39    // This is needed to get the correct position in PositionEnumerator
40    // It is only needed for Jump action and should be used so
41    fn rest_positions(&self) -> Option<Vec<Position>> {
42        if matches!(self.next_action_peek(), Some(Action::Jump(_))) {
43            panic!("Action::Jump must implement rest_positions");
44        }
45        None
46    }
47}
48
49/// Movement action to perform.
50// For now Patterns should only use one variant per pattern
51#[derive(Copy, Clone, Debug, PartialEq, Eq)]
52pub enum Action {
53    /// Steps to next position from the previous one.
54    // Step from previous position
55    Step(Step),
56
57    /// Steps to the next position from the original position provided.
58    /// The original position does stay the same.
59    // Step from origin position, Steps which do not reach into the grid will be ignored
60    StepFromOrigin(Step),
61
62    /// Does jump to the position. No previous or original position are are considered.
63    // Jump to any position
64    Jump(Position),
65}
66
67/// How often a pattern is run.
68#[derive(Copy, Clone, Debug, PartialEq, Eq)]
69pub enum Repeat {
70    Once,
71    TillEnd,
72    Times(usize),
73}
74
75/// Steps in only one direction until end or grid or the repeat condition is meet.
76#[derive(Copy, Clone, Debug, PartialEq, Eq)]
77pub struct DirectionPattern {
78    pub(crate) step: Step,
79    pub(crate) repeat: Repeat,
80}
81
82impl DirectionPattern {
83    pub fn new<S: Into<Step>>(step: S, repeat: Repeat) -> Self {
84        Self {
85            step: step.into(),
86            repeat,
87        }
88    }
89}
90
91impl Pattern for DirectionPattern {
92    fn next_action(&mut self) -> Option<Action> {
93        Some(Action::Step(self.step))
94    }
95
96    fn next_action_peek(&self) -> Option<Action> {
97        Some(Action::Step(self.step))
98    }
99
100    fn repeat(&self) -> &Repeat {
101        &self.repeat
102    }
103}
104
105/// Walks the steps given, until one step leads outside the grid.
106pub struct StepsPattern {
107    pub(crate) steps: Vec<Step>,
108    pub(crate) idx: usize,
109}
110
111impl StepsPattern {
112    pub fn new<T: Copy + Into<Step>>(steps: Vec<T>) -> Self {
113        Self {
114            steps: steps.iter().map(|t| (*t).into()).collect(),
115            idx: 0,
116        }
117    }
118}
119
120impl Pattern for StepsPattern {
121    fn next_action(&mut self) -> Option<Action> {
122        self.idx += 1;
123        Some(Action::Step(*self.steps.get(self.idx - 1)?))
124    }
125
126    fn next_action_peek(&self) -> Option<Action> {
127        Some(Action::Step(*self.steps.get(self.idx)?))
128    }
129
130    fn repeat(&self) -> &Repeat {
131        &Repeat::TillEnd
132    }
133}
134
135/// A pattern which side steps from the original position.
136/// Steps which lead outside the grid are ignored.
137pub struct SideStepsPattern {
138    pub(crate) steps: Vec<Step>,
139    pub(crate) idx: usize,
140}
141
142impl SideStepsPattern {
143    pub fn new<I>(steps: I) -> Self
144    where
145        I: IntoIterator,
146        I::Item: Copy + Into<Step>,
147    {
148        Self {
149            steps: steps.into_iter().map(|t| t.into()).collect(),
150            idx: 0,
151        }
152    }
153}
154
155impl Pattern for SideStepsPattern {
156    fn next_action(&mut self) -> Option<Action> {
157        self.idx += 1;
158        Some(Action::StepFromOrigin(*self.steps.get(self.idx - 1)?))
159    }
160
161    fn next_action_peek(&self) -> Option<Action> {
162        Some(Action::StepFromOrigin(*self.steps.get(self.idx)?))
163    }
164
165    fn repeat(&self) -> &Repeat {
166        &Repeat::TillEnd
167    }
168
169    fn rest_steps(&self) -> Option<Vec<Step>> {
170        Some(self.steps[self.idx..].iter().copied().collect())
171    }
172}
173
174/// A pattern which jumps to the given positions.
175/// Positions outside the grid are ignored.
176pub struct JumpsPattern {
177    jumps: Vec<Position>,
178    idx: usize,
179}
180
181impl JumpsPattern {
182    pub fn new<I>(positions: I) -> Self
183    where
184        I: IntoIterator,
185        I::Item: Copy + Into<Position>,
186    {
187        Self {
188            jumps: positions.into_iter().map(|t| t.into()).collect(),
189            idx: 0,
190        }
191    }
192}
193
194impl Pattern for JumpsPattern {
195    fn next_action(&mut self) -> Option<Action> {
196        self.idx += 1;
197        Some(Action::Jump(*self.jumps.get(self.idx - 1)?))
198    }
199
200    fn next_action_peek(&self) -> Option<Action> {
201        Some(Action::Jump(*self.jumps.get(self.idx)?))
202    }
203
204    fn repeat(&self) -> &Repeat {
205        &Repeat::TillEnd
206    }
207
208    fn rest_positions(&self) -> Option<Vec<Position>> {
209        Some(self.jumps[self.idx..].iter().copied().collect())
210    }
211}