212 lines
4.8 KiB
JavaScript
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;
|
|
};
|