Files
statespaces/src/simulator/sliding_blocks/state.js

212 lines
4.8 KiB
JavaScript

import {
RIGHT,
DOWN,
LEFT,
UP,
DIRECTIONS,
invert_direction,
} from "../../constants.js";
import { key_of } from "../../main.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) => {
return key_of(state) === key_of(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);
delete new_state.name;
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;
};