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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//! All patterns and Pattern Trait used for [pattern](crate::Grid::pattern).
use crate::{Position, Step};

/// This trait is there to create pattern for the [PatternIter](crate::iter::PatternIter).
/// The implemntation should only return one variant of Action.
/// # Variants
/// * `Action::StepFromOrigin(step_x)` if `step_x` steps outside the grid, this Action will be ignored and next_action will be called again.
/// * `Action::Jump(position_x)` if `position_x` is outside the grid, this Action will be ignored and next_action will be called again.
/// this action will be ignored and the nexj
/// # Panics
/// * if different variants of `Action` are returned
/// * if variant Action::StepFromOrigin does not implement `rest_steps`.
/// * if variant Action::Jump does not implement `rest_positions`.
pub trait Pattern {
    /// Returns the next `Action` or None if there are no more `Action`.
    fn next_action(&mut self) -> Option<Action>;

    /// Peeks in the next `Action` and returns it or None if there is no more `Action`.
    // This is needed to to calculate the position for PositionEnumerator.
    fn next_action_peek(&self) -> Option<Action>;

    /// Returns a reference to the `Repeat`.
    fn repeat(&self) -> &Repeat;

    // rest_step and rest_positon are kind of hacks to make
    // PositionEnumerator work with pattern

    /// Returns the rest of the steps. This must be implemented for `Action::StepFromOrigin`.
    // This is needed to get the correct position in PositionEnumerator
    // It is only needed for StepFromOrigin action and should be used so
    fn rest_steps(&self) -> Option<Vec<Step>> {
        if matches!(self.next_action_peek(), Some(Action::StepFromOrigin(_))) {
            panic!("Action::StepFromOrigin must implement rest_step");
        }
        None
    }

    /// Returns the rest of the positions. This must be implemented for `Action::Jump`.
    // This is needed to get the correct position in PositionEnumerator
    // It is only needed for Jump action and should be used so
    fn rest_positions(&self) -> Option<Vec<Position>> {
        if matches!(self.next_action_peek(), Some(Action::Jump(_))) {
            panic!("Action::Jump must implement rest_positions");
        }
        None
    }
}

/// Movement action to perform.
// For now Patterns should only use one variant per pattern
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Action {
    /// Steps to next position from the previous one.
    // Step from previous position
    Step(Step),

    /// Steps to the next position from the original position provided.
    /// The original position does stay the same.
    // Step from origin position, Steps which do not reach into the grid will be ignored
    StepFromOrigin(Step),

    /// Does jump to the position. No previous or original position are are considered.
    // Jump to any position
    Jump(Position),
}

/// How often a pattern is run.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Repeat {
    Once,
    TillEnd,
    Times(usize),
}

/// Steps in only one direction until end or grid or the repeat condition is meet.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct DirectionPattern {
    pub(crate) step: Step,
    pub(crate) repeat: Repeat,
}

impl DirectionPattern {
    pub fn new<S: Into<Step>>(step: S, repeat: Repeat) -> Self {
        Self {
            step: step.into(),
            repeat,
        }
    }
}

impl Pattern for DirectionPattern {
    fn next_action(&mut self) -> Option<Action> {
        Some(Action::Step(self.step))
    }

    fn next_action_peek(&self) -> Option<Action> {
        Some(Action::Step(self.step))
    }

    fn repeat(&self) -> &Repeat {
        &self.repeat
    }
}

/// Walks the steps given, until one step leads outside the grid.
pub struct StepsPattern {
    pub(crate) steps: Vec<Step>,
    pub(crate) idx: usize,
}

impl StepsPattern {
    pub fn new<T: Copy + Into<Step>>(steps: Vec<T>) -> Self {
        Self {
            steps: steps.iter().map(|t| (*t).into()).collect(),
            idx: 0,
        }
    }
}

impl Pattern for StepsPattern {
    fn next_action(&mut self) -> Option<Action> {
        self.idx += 1;
        Some(Action::Step(*self.steps.get(self.idx - 1)?))
    }

    fn next_action_peek(&self) -> Option<Action> {
        Some(Action::Step(*self.steps.get(self.idx)?))
    }

    fn repeat(&self) -> &Repeat {
        &Repeat::TillEnd
    }
}

/// A pattern which side steps from the original position.
/// Steps which lead outside the grid are ignored.
pub struct SideStepsPattern {
    pub(crate) steps: Vec<Step>,
    pub(crate) idx: usize,
}

impl SideStepsPattern {
    pub fn new<I>(steps: I) -> Self
    where
        I: IntoIterator,
        I::Item: Copy + Into<Step>,
    {
        Self {
            steps: steps.into_iter().map(|t| t.into()).collect(),
            idx: 0,
        }
    }
}

impl Pattern for SideStepsPattern {
    fn next_action(&mut self) -> Option<Action> {
        self.idx += 1;
        Some(Action::StepFromOrigin(*self.steps.get(self.idx - 1)?))
    }

    fn next_action_peek(&self) -> Option<Action> {
        Some(Action::StepFromOrigin(*self.steps.get(self.idx)?))
    }

    fn repeat(&self) -> &Repeat {
        &Repeat::TillEnd
    }

    fn rest_steps(&self) -> Option<Vec<Step>> {
        Some(self.steps[self.idx..].iter().copied().collect())
    }
}

/// A pattern which jumps to the given positions.
/// Positions outside the grid are ignored.
pub struct JumpsPattern {
    jumps: Vec<Position>,
    idx: usize,
}

impl JumpsPattern {
    pub fn new<I>(positions: I) -> Self
    where
        I: IntoIterator,
        I::Item: Copy + Into<Position>,
    {
        Self {
            jumps: positions.into_iter().map(|t| t.into()).collect(),
            idx: 0,
        }
    }
}

impl Pattern for JumpsPattern {
    fn next_action(&mut self) -> Option<Action> {
        self.idx += 1;
        Some(Action::Jump(*self.jumps.get(self.idx - 1)?))
    }

    fn next_action_peek(&self) -> Option<Action> {
        Some(Action::Jump(*self.jumps.get(self.idx)?))
    }

    fn repeat(&self) -> &Repeat {
        &Repeat::TillEnd
    }

    fn rest_positions(&self) -> Option<Vec<Position>> {
        Some(self.jumps[self.idx..].iter().copied().collect())
    }
}