diff --git a/index.html b/index.html
index d6663c2..2afceb9 100644
--- a/index.html
+++ b/index.html
@@ -18,6 +18,7 @@
+
diff --git a/src/main.js b/src/main.js
index e772d40..ff91202 100644
--- a/src/main.js
+++ b/src/main.js
@@ -101,6 +101,34 @@ const clear_visualization = () => {
canvas.height = vh - 43;
context.clearRect(0, 0, canvas.width, canvas.height);
+
+ draw_grid();
+};
+
+const draw_grid = () => {
+ const canvas = document.getElementById("model_canvas");
+ const context = canvas.getContext("2d");
+
+ const [vw, vh] = get_viewport_dims();
+ canvas.width = vw / 2 - 9.5;
+ canvas.height = vh - 43;
+
+ const square_width = canvas.width / current_state.width;
+ const square_height = canvas.height / current_state.height;
+
+ // Horizontal lines
+ for (let y = 1; y < current_state.height; y += 1) {
+ context.moveTo(0, y * square_height);
+ context.lineTo(canvas.width, y * square_height);
+ context.stroke();
+ }
+
+ // Vertical lines
+ for (let x = 1; x < current_state.width; x += 1) {
+ context.moveTo(x * square_width, 0);
+ context.lineTo(x * square_width, canvas.height);
+ context.stroke();
+ }
};
//
@@ -138,6 +166,76 @@ const node_click_view_state = (node, graph) => {
// Set up model event-handlers
//
+let editing = false;
+let startpos = null;
+
+document
+ .getElementById("model_canvas")
+ .addEventListener("mousedown", (event) => {
+ if (model.select(current_state, event.offsetX, event.offsetY) === null) {
+ startpos = [event.offsetX, event.offsetY];
+ }
+ });
+
+document.getElementById("model_canvas").addEventListener("mouseup", (event) => {
+ if (startpos === null) {
+ return;
+ }
+
+ let endpos = [event.offsetX, event.offsetY];
+
+ const canvas = document.getElementById("model_canvas");
+
+ const square_width = canvas.width / current_state.width;
+ const square_height = canvas.height / current_state.height;
+
+ // Coordinates
+ const startx = Math.floor(startpos[0] / square_width);
+ const starty = Math.floor(startpos[1] / square_height);
+ const endx = Math.floor(endpos[0] / square_width);
+ const endy = Math.floor(endpos[1] / square_height);
+
+ // Check that the block to be added doesn't collide with anything
+ for (let ix = startx; ix <= endx; ix++) {
+ for (let iy = starty; iy <= endy; iy++) {
+ if (
+ model.select(current_state, ix * square_width, iy * square_height) !==
+ null
+ ) {
+ startpos = null;
+ return;
+ }
+ }
+ }
+
+ // Add block
+ let new_block = model.add_block(
+ current_state,
+ Math.min(startx, endx),
+ Math.min(starty, endy),
+ Math.max(startx, endx),
+ Math.max(starty, endy),
+ );
+
+ if (new_block === null) {
+ startpos = null;
+ return;
+ }
+
+ // Clear graph + visualize
+ selected_element = new_block;
+ clear_visualization();
+ model.visualize(current_state);
+ model.highlight(current_state, selected_element);
+
+ // Generate graph for new state
+ clear_graph();
+ model.generate(states, initial_state, graph, null);
+ reset_graph_view(graph);
+
+ startpos = null;
+});
+
document.getElementById("model_canvas").addEventListener("click", (event) => {
const element = model.select(current_state, event.offsetX, event.offsetY);
@@ -218,6 +316,7 @@ document.getElementById("select_model_button").addEventListener("click", () => {
clear_graph();
clear_visualization();
model.visualize(initial_state);
+ editing = false;
document.getElementById("model_name").innerHTML = model.name;
document.getElementById("state_name").innerHTML = initial_state.name;
});
@@ -232,12 +331,29 @@ document.getElementById("select_state_button").addEventListener("click", () => {
states.add(initial_state);
clear_graph();
clear_visualization();
- // graph = null;
- // graph = generate_graph(data, node_click_view_state);
model.visualize(initial_state);
+ editing = false;
document.getElementById("state_name").innerHTML = initial_state.name;
});
+document.getElementById("edit_state_button").addEventListener("click", () => {
+ if (editing === false) {
+ current_initial_state = 0;
+ initial_state = model.empty_state;
+ current_state = initial_state;
+ selected_element = null;
+ clear_states();
+ states.add(initial_state);
+ clear_graph();
+ clear_visualization();
+ model.visualize(initial_state);
+ editing = true;
+ document.getElementById("state_name").innerHTML = initial_state.name;
+ } else {
+ editing = false;
+ }
+});
+
document
.getElementById("generate_graph_button")
.addEventListener("click", () => {
diff --git a/src/simulator/restricted_sliding_blocks/model.js b/src/simulator/restricted_sliding_blocks/model.js
index 104ba6b..fe160fc 100644
--- a/src/simulator/restricted_sliding_blocks/model.js
+++ b/src/simulator/restricted_sliding_blocks/model.js
@@ -183,6 +183,22 @@ const visualize_path = (from_state, to_state) => {
// For each state in path: visualize(state)
};
+const add_block = (state, x0, y0, x1, y1) => {
+ let dir;
+ if (x1 - x0 > y1 - y0) {
+ dir = HORIZONTAL;
+ } else if (x1 - x0 < y1 - y0) {
+ dir = VERTICAL;
+ } else {
+ // No square blocks for this model
+ return null;
+ }
+
+ let new_block = [state.board.length, dir, x0, y0, x1, y1];
+ state.board.push(new_block);
+ return new_block;
+};
+
export const restricted_sliding_blocks_model = {
name: "Restricted Sliding Blocks",
generate,
@@ -192,4 +208,11 @@ export const restricted_sliding_blocks_model = {
initial_states,
select,
move,
+ empty_state: {
+ name: "Custom",
+ width: 5,
+ height: 5,
+ board: [],
+ },
+ add_block,
};
diff --git a/src/simulator/sliding_blocks/model.js b/src/simulator/sliding_blocks/model.js
index f018d5f..10bb7b8 100644
--- a/src/simulator/sliding_blocks/model.js
+++ b/src/simulator/sliding_blocks/model.js
@@ -162,6 +162,12 @@ const visualize_path = (from_state, to_state) => {
// For each state in path: visualize(state)
};
+const add_block = (state, x0, y0, x1, y1) => {
+ let new_block = [state.board.length, x0, y0, x1, y1];
+ state.board.push(new_block);
+ return new_block;
+};
+
export const sliding_blocks_model = {
name: "Sliding Blocks",
generate,
@@ -171,4 +177,11 @@ export const sliding_blocks_model = {
initial_states,
select,
move,
+ empty_state: {
+ name: "Custom",
+ width: 5,
+ height: 6,
+ board: [],
+ },
+ add_block,
};