Skip to content

Commit c3ec6f5

Browse files
committed
Refactor moves list into rust lib
1 parent b303046 commit c3ec6f5

File tree

15 files changed

+539
-414
lines changed

15 files changed

+539
-414
lines changed

Cargo.toml

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,26 @@ wasm-bindgen-futures = "0.4.50"
3737
[dependencies.web-sys]
3838
version = "0.3"
3939
features = [
40-
'console',
41-
'Document',
42-
'Window',
43-
'HtmlCanvasElement',
44-
'ResizeObserver',
45-
'ResizeObserverEntry',
46-
'ResizeObserverSize',
47-
'MouseEvent',
48-
'MouseScrollEvent',
49-
'CanvasRenderingContext2d',
50-
'OffscreenCanvas',
51-
'OffscreenCanvasRenderingContext2d',
52-
'WebGl2RenderingContext',
40+
"console",
41+
"Document",
42+
"Window",
43+
"HtmlCanvasElement",
44+
"HtmlDivElement",
45+
"ResizeObserver",
46+
"ResizeObserverEntry",
47+
"ResizeObserverSize",
48+
"PointerEvent",
49+
"MouseEvent",
50+
"MouseScrollEvent",
51+
"CanvasRenderingContext2d",
52+
"OffscreenCanvas",
53+
"OffscreenCanvasRenderingContext2d",
54+
"WebGl2RenderingContext",
5355
"WebGlVertexArrayObject",
54-
'WebGlProgram',
55-
'WebGlShader',
56-
'WebGlBuffer',
57-
'WebGlUniformLocation'
56+
"WebGlProgram",
57+
"WebGlShader",
58+
"WebGlBuffer",
59+
"WebGlUniformLocation",
60+
"DomTokenList",
61+
"CssStyleDeclaration",
5862
]

src/board/mod.rs

Lines changed: 47 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,27 @@ mod unittest;
77
use anyhow::{anyhow, Context, Result};
88
use itertools::Itertools;
99
use std::cmp::{Ordering, PartialEq};
10+
use std::fmt;
1011
use std::hash::{DefaultHasher, Hash, Hasher};
1112
use std::ops::Range;
12-
use wasm_bindgen::prelude::wasm_bindgen;
1313

14-
#[wasm_bindgen]
1514
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1615
pub struct Coordinates {
1716
pub x: i32,
1817
pub y: i32,
1918
}
2019

21-
#[wasm_bindgen]
2220
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
2321
pub struct Size {
2422
pub x: i32,
2523
pub y: i32,
2624
}
2725

28-
#[wasm_bindgen]
26+
pub enum Axis {
27+
Horizontal,
28+
Vertical,
29+
}
30+
2931
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
3032
pub enum SlideDirection {
3133
Up,
@@ -34,15 +36,13 @@ pub enum SlideDirection {
3436
Right,
3537
}
3638

37-
#[wasm_bindgen]
3839
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
3940
pub struct SlideMove {
4041
pub start: Coordinates,
4142
pub direction: SlideDirection,
4243
pub distance: u8,
4344
}
4445

45-
#[wasm_bindgen]
4646
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
4747
pub struct Piece {
4848
/// The coordinates of the piece's bottom left most tile
@@ -52,13 +52,9 @@ pub struct Piece {
5252
}
5353

5454
/// A game board filled with all tiles
55-
#[wasm_bindgen]
5655
#[derive(Debug, Clone, Copy)]
5756
pub struct Board {
5857
pub size: Size,
59-
// TODO(Menno 18.12.2024) https://github.com/rustwasm/wasm-bindgen/issues/122
60-
// Wasm bindgen doesn't support arrays at the moment, work around with custom getter.
61-
#[wasm_bindgen(skip)]
6258
pub pieces: [Piece; 10],
6359
}
6460

@@ -75,6 +71,46 @@ pub fn to_id(board: &Board) -> BoardId {
7571
/// Standard Klotski board is 4 by 5 tiles
7672
const SIZE: Size = Size { x: 4, y: 5 };
7773

74+
impl fmt::Display for Coordinates {
75+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76+
write!(
77+
f,
78+
"{}{}",
79+
Self::axis_to_string(Axis::Horizontal, self.x as u8),
80+
Self::axis_to_string(Axis::Vertical, self.y as u8)
81+
)
82+
}
83+
}
84+
85+
impl Coordinates {
86+
pub fn axis_to_string(axis: Axis, coordinate: u8) -> String {
87+
match axis {
88+
Axis::Horizontal => ((b'A' + coordinate) as char).to_string(),
89+
Axis::Vertical => (coordinate + 1).to_string(),
90+
}
91+
}
92+
}
93+
94+
impl fmt::Display for SlideMove {
95+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96+
write!(f, "{}⮕{}", self.start, self.get_endpoint())
97+
}
98+
}
99+
100+
impl SlideMove {
101+
fn get_endpoint(&self) -> Coordinates {
102+
let mut end = self.start;
103+
let distance = self.distance as i32;
104+
match self.direction {
105+
SlideDirection::Up => end.y += distance,
106+
SlideDirection::Down => end.y -= distance,
107+
SlideDirection::Left => end.x -= distance,
108+
SlideDirection::Right => end.x += distance,
109+
}
110+
end
111+
}
112+
}
113+
78114
impl Eq for Board {}
79115

80116
impl PartialEq<Self> for Board {
@@ -102,14 +138,6 @@ impl Hash for Board {
102138
}
103139
}
104140

105-
#[wasm_bindgen]
106-
impl Board {
107-
#[wasm_bindgen(getter)]
108-
pub fn pieces(&self) -> Vec<Piece> {
109-
self.pieces.to_vec()
110-
}
111-
}
112-
113141
pub fn get_start_board() -> Board {
114142
/// Standard Klotski board is:
115143
/// ABBC
@@ -304,13 +332,7 @@ pub fn make_move(board: &Board, slide_move: &SlideMove) -> Result<Board> {
304332
.context("No piece to move")?;
305333

306334
// move the piece by specified distance
307-
let distance: i32 = slide_move.distance as i32;
308-
match slide_move.direction {
309-
SlideDirection::Up => piece_to_move.position.y += distance,
310-
SlideDirection::Down => piece_to_move.position.y -= distance,
311-
SlideDirection::Left => piece_to_move.position.x -= distance,
312-
SlideDirection::Right => piece_to_move.position.x += distance,
313-
}
335+
piece_to_move.position = slide_move.get_endpoint();
314336

315337
// After modifying the board, we need to sort it to ensure correct ID calculation.
316338
new_board.pieces.sort();

src/graph/mod.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,16 @@ mod unittest;
66

77
use crate::board::{to_id, Board, BoardId, SlideMove};
88
use std::collections::{HashMap, VecDeque};
9-
use wasm_bindgen::prelude::wasm_bindgen;
109

11-
#[wasm_bindgen]
1210
#[derive(Clone)]
1311
pub struct Node {
1412
pub board: Board,
15-
#[wasm_bindgen(getter_with_clone)]
1613
pub edges: Vec<Edge>,
1714
pub distance_to_start: Option<u32>,
1815
pub distance_to_solution: Option<u32>,
1916
pub on_shortest_path: bool,
2017
}
2118

22-
#[wasm_bindgen]
2319
#[derive(Clone)]
2420
pub struct Edge {
2521
pub neighbor: BoardId,

src/lib.rs

Lines changed: 10 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,12 @@ mod graph;
66
mod solver;
77
mod views;
88

9-
use crate::board::{BoardId, SlideMove};
109
use crate::solver::Solver;
1110
use crate::views::StatefulViews;
12-
use js_sys::Function;
1311
use std::cell::RefCell;
1412
use std::rc::Rc;
1513
use wasm_bindgen::prelude::*;
1614

17-
#[wasm_bindgen]
18-
#[derive(Clone, Copy)]
19-
pub enum MoveEffectiveness {
20-
Positive,
21-
Neutral,
22-
Negative,
23-
}
24-
25-
#[wasm_bindgen]
26-
pub struct MoveInfo {
27-
pub slide_move: SlideMove,
28-
pub resulting_id: BoardId,
29-
pub resulting_distance: u32,
30-
pub effectiveness: MoveEffectiveness,
31-
}
32-
3315
#[wasm_bindgen]
3416
pub struct WiggersGraaf {
3517
stateful_views: Rc<RefCell<StatefulViews>>,
@@ -41,21 +23,27 @@ impl WiggersGraaf {
4123
pub fn new(
4224
meta_canvas_id: &str,
4325
board_canvas_id: &str,
44-
on_highlight: Function,
26+
moves_div_id: &str,
27+
restart_div_id: &str,
28+
solve_div_id: &str,
4529
) -> Result<Self, JsValue> {
4630
console_error_panic_hook::set_once();
4731
env_logger::init();
4832

4933
let solver = Solver::new();
5034

51-
Ok(Self {
35+
let instance = Self {
5236
stateful_views: StatefulViews::new(
5337
solver.graph,
5438
meta_canvas_id,
5539
board_canvas_id,
56-
on_highlight,
40+
moves_div_id,
41+
restart_div_id,
42+
solve_div_id,
5743
)?,
58-
})
44+
};
45+
StatefulViews::restart(&instance.stateful_views);
46+
Ok(instance)
5947
}
6048

6149
pub fn accumulate_translation(&self, delta_x: f32, delta_y: f32) {
@@ -69,22 +57,4 @@ impl WiggersGraaf {
6957
.borrow()
7058
.accumulate_zoom(zoom_movement, target_x, target_y);
7159
}
72-
73-
pub fn preview_move(&self, move_info: &MoveInfo) {
74-
self.stateful_views.borrow().preview_move(move_info);
75-
}
76-
77-
pub fn cancel_preview(&self) {
78-
self.stateful_views.borrow().cancel_preview();
79-
}
80-
81-
pub async fn do_move(&self, move_info: &MoveInfo) -> Option<Vec<MoveInfo>> {
82-
// TODO(Menno 11.08.2025) I'm getting really annoyed at all this refcell trickery and struggling with async.
83-
// Dear future me, please review this code and clean it up?
84-
StatefulViews::do_move(&self.stateful_views, move_info).await
85-
}
86-
87-
pub fn restart(&self) -> Option<Vec<MoveInfo>> {
88-
self.stateful_views.borrow().restart()
89-
}
9060
}

src/solver.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ use crate::board::{
66
SlideDirection, SlideMove,
77
};
88
use crate::graph::Graph;
9-
use wasm_bindgen::prelude::wasm_bindgen;
109

11-
#[wasm_bindgen]
1210
pub struct Solver {
1311
// We only want the graph to be publicly accessible from Rust code, disable wasm binding
14-
#[wasm_bindgen(skip)]
1512
pub graph: Graph,
1613
start_board: Board,
1714
solution_node: Board,

src/views/board_view/layout.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
// SPDX-FileCopyrightText: 2025 Menno van der Graaf <mennovandergraaf@hotmail.com>
22
// SPDX-License-Identifier: MIT
33

4+
use crate::board::Axis;
45
use crate::views::board_view::visual_board::{VisualCoordinates, VisualPiece, VisualSize};
56
use crate::views::utils::{Coordinates, Size};
67

78
const AXIS_PADDING: f64 = 4.0;
89
const AXIS_GIRTH: f64 = 16.0;
910
const PIECE_PADDING: f64 = 1.0;
1011

11-
pub enum Axis {
12-
Horizontal,
13-
Vertical,
14-
}
15-
1612
/// Layout of a board in canvas space, note we flip the Y-axis for this layout, 0 is at the bottom.
1713
#[derive(PartialEq, Copy, Clone)]
1814
pub struct Layout {

src/views/board_view/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@ use crate::views::frame_scheduler::FrameScheduler;
1616
use crate::views::mouse_handler::{MouseEvent, MouseHandler};
1717
use crate::views::resize_observer::ResizeObserver;
1818
use crate::views::utils;
19-
use crate::views::utils::get_canvas;
19+
use crate::views::utils::get_element_of_type;
2020
use futures::channel::oneshot;
2121
use keyframe::{keyframes, AnimationSequence};
2222
use std::cell::RefCell;
2323
use std::rc::{Rc, Weak};
2424
use std::time::Duration;
2525
use wasm_bindgen::JsValue;
26+
use web_sys::HtmlCanvasElement;
2627

2728
pub type OnDragMoveCb = dyn FnMut(DragMove) -> graph::Node;
2829

@@ -41,7 +42,7 @@ impl BoardView {
4142
canvas_id: &str,
4243
on_drag_move_cb: Box<OnDragMoveCb>,
4344
) -> Result<Rc<RefCell<Self>>, JsValue> {
44-
let canvas = get_canvas(canvas_id)?;
45+
let canvas: HtmlCanvasElement = get_element_of_type(canvas_id)?;
4546
Ok(Rc::new_cyclic(|self_ref: &Weak<RefCell<BoardView>>| {
4647
let self_ref_for_on_frame_cb = self_ref.clone();
4748
let self_ref_for_resize_observer_cb = self_ref.clone();
@@ -85,7 +86,7 @@ impl BoardView {
8586
}))
8687
}
8788

88-
pub fn preview_move(&mut self, target_move: Option<&SlideMove>) {
89+
pub fn preview_move(&mut self, target_move: Option<SlideMove>) {
8990
let animation_done = match target_move {
9091
None => {
9192
self.visual_board.highlight(&None);

src/views/board_view/renderer.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// SPDX-FileCopyrightText: 2025 Menno van der Graaf <mennovandergraaf@hotmail.com>
22
// SPDX-License-Identifier: MIT
33

4-
use crate::views::board_view::layout::Axis::{Horizontal, Vertical};
5-
use crate::views::board_view::layout::{Axis, Layout};
4+
use crate::board;
5+
use crate::board::Axis;
6+
use crate::views::board_view::layout::Layout;
67
use crate::views::board_view::visual_board::{VisualBoard, VisualSize};
78
use crate::views::utils::Coordinates;
89
use wasm_bindgen::{JsCast, JsValue};
@@ -99,8 +100,8 @@ impl Renderer {
99100
ctx.fill_rect(pos.x, pos.y, size.width, size.height);
100101
}
101102
};
102-
draw_ticks(Horizontal, board_size.width as u32);
103-
draw_ticks(Vertical, board_size.height as u32);
103+
draw_ticks(Axis::Horizontal, board_size.width as u32);
104+
draw_ticks(Axis::Vertical, board_size.height as u32);
104105

105106
// Draw a label
106107
let draw_label = |position: Coordinates, label: String| {
@@ -110,14 +111,14 @@ impl Renderer {
110111

111112
// draw X axis labes
112113
for x in 0..board_size.width as u32 {
113-
let label = ((b'A' + x as u8) as char).to_string();
114-
draw_label(self.layout.apply_to_axis_label(x, &Horizontal), label);
114+
let label = board::Coordinates::axis_to_string(Axis::Horizontal, x as u8);
115+
draw_label(self.layout.apply_to_axis_label(x, &Axis::Horizontal), label);
115116
}
116117

117118
// draw Y axis labels
118119
for y in 0..board_size.height as u32 {
119-
let label = (y + 1).to_string();
120-
draw_label(self.layout.apply_to_axis_label(y, &Vertical), label);
120+
let label = board::Coordinates::axis_to_string(Axis::Vertical, y as u8);
121+
draw_label(self.layout.apply_to_axis_label(y, &Axis::Vertical), label);
121122
}
122123
}
123124

0 commit comments

Comments
 (0)