Implement Sliding-Blocks and Restricted-Sliding-Blocks
This commit is contained in:
207
src/simulator/sliding_blocks/state.js
Normal file
207
src/simulator/sliding_blocks/state.js
Normal file
@ -0,0 +1,207 @@
|
||||
import {
|
||||
RIGHT,
|
||||
DOWN,
|
||||
LEFT,
|
||||
UP,
|
||||
DIRECTIONS,
|
||||
invert_direction,
|
||||
} from "../../constants.js";
|
||||
|
||||
export const arrays_are_equal = (array, other_array) => {
|
||||
if (array.length != other_array.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
if (array[i] !== other_array[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export const state_contains_block = (state, block) => {
|
||||
return (
|
||||
state.board.length >= block[0] &&
|
||||
arrays_are_equal(state.board[block[0]], block)
|
||||
);
|
||||
|
||||
// for (let i = 0; i < state.board.length / 4; i++) {
|
||||
// const other_block = state.board.slice(i * 4, (i + 1) * 4);
|
||||
//
|
||||
// if (arrays_are_equal(block, other_block)) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
};
|
||||
|
||||
export const states_are_equal = (state, other_state) => {
|
||||
if (state.board.length != other_state.board.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < state.board.length; i++) {
|
||||
if (!arrays_are_equal(state.board[i], other_state.board[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
// for (let i = 0; i < state.board.length / 4; i++) {
|
||||
// const block = state.board.slice(i * 4, (i + 1) * 4);
|
||||
//
|
||||
// if (!state_contains_block(other_state, block)) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
};
|
||||
|
||||
export const index_of_state = (states, state) => {
|
||||
for (let i = 0; i < states.length; i++) {
|
||||
if (states_are_equal(states[i], state)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const remove_block = (state, block) => {
|
||||
let new_state = structuredClone(state);
|
||||
|
||||
new_state.board.splice(block[0], 1);
|
||||
|
||||
return new_state;
|
||||
|
||||
// for (let i = 0; i < state.board.length / 4; i++) {
|
||||
// const other_block = state.board.slice(i * 4, (i + 1) * 4);
|
||||
//
|
||||
// if (arrays_are_equal(block, other_block)) {
|
||||
// new_state.board.splice(i * 4, 4);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return new_state;
|
||||
};
|
||||
|
||||
export const insert_block = (state, block) => {
|
||||
state.board.splice(block[0], 0, block);
|
||||
};
|
||||
|
||||
export const move_block = (block, direction) => {
|
||||
const [id, x0, y0, x1, y1] = block;
|
||||
const [dx, dy] = direction;
|
||||
|
||||
return [id, x0 + dx, y0 + dy, x1 + dx, y1 + dy];
|
||||
};
|
||||
|
||||
export const move_state_block = (state, block, direction) => {
|
||||
const [id, x0, y0, x1, y1] = state.board[block[0]];
|
||||
const [dx, dy] = direction;
|
||||
|
||||
state.board[block[0]] = [id, x0 + dx, y0 + dy, x1 + dx, y1 + dy];
|
||||
};
|
||||
|
||||
export const block_collides_with_other_block = (block, other_block) => {
|
||||
const [id0, x0, y0, x1, y1] = block;
|
||||
const [id1, x2, y2, x3, y3] = other_block;
|
||||
|
||||
// Don't check for self-collisions
|
||||
if (id0 === id1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Creates a set containing all x or y coordinates occupied by the block
|
||||
const span = (a0, a1) => {
|
||||
const start = Math.min(a0, a1);
|
||||
const end = Math.max(a0, a1);
|
||||
|
||||
let set = new Set();
|
||||
for (let i = start; i <= end; i++) {
|
||||
set.add(i);
|
||||
}
|
||||
return set;
|
||||
};
|
||||
|
||||
// Checks if two sets intersect
|
||||
const intersects = (set0, set1) => {
|
||||
for (const e of set0)
|
||||
if (set1.has(e)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const xs0 = span(x0, x1);
|
||||
const ys0 = span(y0, y1);
|
||||
const xs1 = span(x2, x3);
|
||||
const ys1 = span(y2, y3);
|
||||
|
||||
// If block and other_block have a shared x and y coordinate, they intersect
|
||||
return intersects(xs0, xs1) && intersects(ys0, ys1);
|
||||
};
|
||||
|
||||
export const block_collides = (state, block) => {
|
||||
for (let i = 0; i < state.board.length; i++) {
|
||||
const other_block = state.board[i];
|
||||
|
||||
if (block_collides_with_other_block(block, other_block)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
export const block_is_movable = (state, block, direction) => {
|
||||
// Move the block, then check if the block would intersect or collide
|
||||
const [id, x0, y0, x1, y1] = move_block(block, direction);
|
||||
|
||||
// Check collisions with board borders
|
||||
if (x0 < 0 || x1 >= state.width) {
|
||||
return false;
|
||||
}
|
||||
if (y0 < 0 || y1 >= state.height) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check collisions with other blocks.
|
||||
// We remove the block being checked from the board so it doesn't self-collide,
|
||||
if (block_collides(state, [id, x0, y0, x1, y1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export const get_moves = (last_move, state) => {
|
||||
// Example move: [block, direction]
|
||||
let moves = [];
|
||||
|
||||
for (let i = 0; i < state.board.length; i++) {
|
||||
const block = state.board[i];
|
||||
|
||||
for (let direction of DIRECTIONS) {
|
||||
if (
|
||||
last_move !== null &&
|
||||
arrays_are_equal(last_move[0], block) &&
|
||||
arrays_are_equal(last_move[1], invert_direction(direction))
|
||||
) {
|
||||
// We don't want to move the block back to where we came from...
|
||||
continue;
|
||||
}
|
||||
|
||||
if (block_is_movable(state, block, direction)) {
|
||||
moves.push([block, direction]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return moves;
|
||||
};
|
Reference in New Issue
Block a user