diff --git a/crates/ascend/src/models/semantics.rs b/crates/ascend/src/models/semantics.rs index 56e8746..75c47ef 100644 --- a/crates/ascend/src/models/semantics.rs +++ b/crates/ascend/src/models/semantics.rs @@ -23,21 +23,37 @@ impl Pattern { } #[must_use] - pub fn apply_transformation(&self, transformation: Transformation) -> Self { - let mut holds = self.clone(); - if transformation.shift_right > 0 { - holds = holds.shift_right(transformation.shift_right); + pub fn shift_left(&self, shift: u64) -> Option { + // Out of bounds check + if let Some(min_col) = self.pattern.iter().map(|(hold_position, _)| hold_position.col).min() { + if shift > min_col { + return None; + } } - if transformation.mirror { - holds = holds.mirror(); - } - holds + + let pattern: BTreeMap = self + .pattern + .iter() + .map(|(hold_position, hold_role)| { + let mut hold_position = hold_position.clone(); + hold_position.col -= shift; + (hold_position, *hold_role) + }) + .collect(); + + Some(Self { pattern }) } #[must_use] - pub fn shift_right(&self, shift: u64) -> Self { - let mut pattern = self.clone(); - pattern.pattern = pattern + pub fn shift_right(&self, wall_dimensions: WallDimensions, shift: u64) -> Option { + // Out of bounds check + if let Some(max_col) = self.pattern.iter().map(|(hold_position, _)| hold_position.col).max() { + if max_col + shift >= wall_dimensions.cols { + return None; + } + } + + let pattern: BTreeMap = self .pattern .iter() .map(|(hold_position, hold_role)| { @@ -46,7 +62,8 @@ impl Pattern { (hold_position, *hold_role) }) .collect(); - pattern + + Some(Self { pattern }) } #[must_use] diff --git a/crates/ascend/src/pages/wall.rs b/crates/ascend/src/pages/wall.rs index 03a8f71..358496f 100644 --- a/crates/ascend/src/pages/wall.rs +++ b/crates/ascend/src/pages/wall.rs @@ -187,7 +187,6 @@ fn View() -> impl IntoView {
-
@@ -196,7 +195,8 @@ fn View() -> impl IntoView {
{move || ctx.problem.get().map(|problem| view! { })} - + +
@@ -214,25 +214,49 @@ fn Transformations() -> impl IntoView { let ctx = use_context::().unwrap(); - let on_left = Callback::new(move |()| { - tracing::debug!("left"); + let left = Signal::derive(move || { + let mut problem = ctx.problem.get()?; + let new_pattern = problem.pattern.shift_left(1)?; + problem.pattern = new_pattern; + Some(problem) }); - let on_mirror = Callback::new(move |()| { + + let right = Signal::derive(move || { + let mut problem = ctx.problem.get()?; + let wall_dimensions = ctx.wall.read().wall_dimensions; + let new_pattern = problem.pattern.shift_right(wall_dimensions, 1)?; + problem.pattern = new_pattern; + Some(problem) + }); + + let on_click_left = Callback::new(move |()| { + tracing::debug!("left"); + if let Some(problem) = left.get() { + ctx.cb_set_problem.run(problem); + } + }); + let on_click_mirror = Callback::new(move |()| { tracing::debug!("mirror"); if let Some(mut problem) = ctx.problem.get() { problem.pattern = problem.pattern.mirror(); ctx.cb_set_problem.run(problem); } }); - let on_right = Callback::new(move |()| { + let on_click_right = Callback::new(move |()| { tracing::debug!("right"); + if let Some(problem) = right.get() { + ctx.cb_set_problem.run(problem); + } }); + let left_disabled = Signal::derive(move || left.read().is_none()); + let right_disabled = Signal::derive(move || right.read().is_none()); + view! {
-
} } @@ -261,7 +285,7 @@ fn NextProblemButton() -> impl IntoView { let ctx = use_context::().unwrap(); let on_click = Callback::new(move |_| ctx.cb_next_problem.run(())); - view! {