Merge pull request 'api redesign' (#10) from dev into master
Reviewed-on: #10
This commit is contained in:
commit
f887b7bd18
2053
package-lock.json
generated
2053
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,9 @@
|
||||
"build": "vite build",
|
||||
"serve": "vite preview",
|
||||
"lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src",
|
||||
"format": "prettier . --write"
|
||||
"format": "prettier . --write",
|
||||
"coverage": "vitest run --coverage",
|
||||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-vue": "^3.2.0",
|
||||
@ -17,10 +19,13 @@
|
||||
"vue": "3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/vue": "^6.6.1",
|
||||
"eslint": "^8.28.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-vue": "^9.8.0",
|
||||
"prettier": "2.8.0"
|
||||
"happy-dom": "^8.1.1",
|
||||
"prettier": "2.8.0",
|
||||
"vitest": "^0.26.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
@ -16,8 +16,8 @@
|
||||
const onResize = () => {
|
||||
nextTick(() => {
|
||||
windowWidth.value = window.innerWidth;
|
||||
store.canvasWidth = window.innerWidth;
|
||||
store.canvasHeight = window.innerHeight;
|
||||
// TODO: changing the width will clear the canvas. Find something else
|
||||
store.renderer.resize(window.innerWidth, window.innerHeight);
|
||||
store.setBoardWidth();
|
||||
store.setBoardHeight();
|
||||
});
|
||||
|
@ -2,9 +2,6 @@
|
||||
import { onMounted, watch } from "vue";
|
||||
import { globalStore } from "../stores/index.js";
|
||||
import {
|
||||
create1dState,
|
||||
create1dStateOneCell,
|
||||
create2dState,
|
||||
createBoard,
|
||||
conwayRules,
|
||||
overpopulationRules,
|
||||
@ -13,18 +10,14 @@
|
||||
highLifeRules,
|
||||
servietteRules,
|
||||
evolve2d,
|
||||
} from "../modules/automata.js";
|
||||
import { getRandomInt } from "../modules/common.js";
|
||||
import { boardToPic, picToBoard } from "../modules/picture.js";
|
||||
} from "../modules/core.js";
|
||||
import {
|
||||
create1dInitialState,
|
||||
create2dRandomGrid,
|
||||
} from "../modules/board.js";
|
||||
import { picToBoard } from "../modules/picture.js";
|
||||
|
||||
const store = globalStore();
|
||||
|
||||
// TODO: Do we really need to declare a work canvas in this scope?
|
||||
// Do we really need to declare a canvas here at all?
|
||||
let canvas = null;
|
||||
let workCanvas = null;
|
||||
let workCtx = null;
|
||||
let ctx = null;
|
||||
const available2dRules = {
|
||||
conway: conwayRules,
|
||||
overpopulation: overpopulationRules,
|
||||
@ -35,8 +28,9 @@
|
||||
};
|
||||
|
||||
// used to determine the dimensions of the board
|
||||
// TODO: should be a Board method
|
||||
const max = () => {
|
||||
return Math.max(store.boardWidth, store.boardHeight);
|
||||
return Math.max(store.board.width, store.board.height);
|
||||
};
|
||||
|
||||
const selectedRules = () => {
|
||||
@ -79,66 +73,46 @@
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
canvas = Object.freeze(document.getElementById("board-canvas"));
|
||||
workCanvas = Object.freeze(document.getElementById("work-canvas"));
|
||||
ctx = canvas.getContext("2d", { willReadFrequently: true });
|
||||
workCtx = workCanvas.getContext("2d", {
|
||||
// TODO : butt ugly.
|
||||
const canvas = document.getElementById("board-canvas");
|
||||
store.renderer.width = canvas.parentElement.clientWidth;
|
||||
store.renderer.height = canvas.parentElement.clientHeight;
|
||||
store.renderer.canvas = canvas;
|
||||
store.renderer.ctx = store.renderer.canvas.getContext("2d", {
|
||||
willReadFrequently: true,
|
||||
});
|
||||
store.renderer.workCanvas = new OffscreenCanvas(
|
||||
canvas.parentElement.clientWidth,
|
||||
canvas.parentElement.clientHeight
|
||||
);
|
||||
store.renderer.workCtx = store.renderer.workCanvas.getContext("2d", {
|
||||
willReadFrequently: true,
|
||||
});
|
||||
store.canvasWidth = canvas.parentElement.clientWidth;
|
||||
store.canvasHeight = canvas.parentElement.clientHeight;
|
||||
store.setBoardWidth();
|
||||
store.setBoardHeight();
|
||||
});
|
||||
|
||||
// draws the board on the canvas
|
||||
const drawCanvas = async (board, width, height) => {
|
||||
const d = store.cellProperties.size;
|
||||
// bool to RGBA colors
|
||||
const img = await boardToPic(board, width, height, store.cellProperties);
|
||||
// rescale and draw
|
||||
ctx.save();
|
||||
ctx.clearRect(0, 0, store.canvasWidth, store.canvasHeight);
|
||||
workCtx.putImageData(img, 0, 0);
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
ctx.scale(d, d);
|
||||
ctx.drawImage(workCanvas, 0, 0, store.canvasWidth, store.canvasHeight);
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
// create a first state, either a single living cell
|
||||
// at the center or random ones
|
||||
const compute1dInitialState = () => {
|
||||
if (store.initial1dState === "onecell")
|
||||
return create1dStateOneCell(store.boardWidth);
|
||||
return create1dState(store.boardWidth, getRandomInt, [0, 2]);
|
||||
};
|
||||
|
||||
// initialize board with random cells
|
||||
const randomInitialState = () => {
|
||||
return create2dState(
|
||||
store.boardWidth,
|
||||
store.boardHeight,
|
||||
getRandomInt,
|
||||
[0, 2]
|
||||
);
|
||||
const drawCanvas = async (board) => {
|
||||
store.renderer.render(board);
|
||||
};
|
||||
|
||||
// draw elementary automaton on the canvas based on selected ruleset
|
||||
const draw1d = () => {
|
||||
const initialState = compute1dInitialState();
|
||||
const initialState = create1dInitialState(
|
||||
store.board,
|
||||
store.initial1dState
|
||||
);
|
||||
const board = createBoard(initialState, store.ruleset1d.rules, max());
|
||||
store.lastBoard = Object.freeze(board);
|
||||
// TODO: the board clearly could be an object
|
||||
drawCanvas(store.lastBoard, store.boardWidth, store.boardHeight);
|
||||
store.board.grid = Object.freeze(board);
|
||||
drawCanvas(store.board);
|
||||
store.toggleStop();
|
||||
};
|
||||
|
||||
// draw 2D automaton on the canvas in a loop
|
||||
const draw2d = (board) => {
|
||||
const newBoard = evolve2d(board, selectedRules());
|
||||
drawCanvas(newBoard, store.boardWidth, store.boardHeight);
|
||||
store.lastBoard = Object.freeze(newBoard);
|
||||
store.board.grid = Object.freeze(evolve2d(board.grid, selectedRules()));
|
||||
drawCanvas(store.board);
|
||||
};
|
||||
|
||||
// draw 2d automaton in a loop, starting from passed state
|
||||
@ -147,7 +121,7 @@
|
||||
requestAnimationFrame(() => {
|
||||
if (!store.canDraw) return;
|
||||
draw2d(board);
|
||||
return draw2dNext(store.lastBoard);
|
||||
return draw2dNext(store.board);
|
||||
});
|
||||
}, store.refreshRate);
|
||||
};
|
||||
@ -155,74 +129,57 @@
|
||||
// draw 2d automaton from a new state
|
||||
const draw2dNew = async () => {
|
||||
if (!store.canDraw) return;
|
||||
const initialState = randomInitialState();
|
||||
const board = evolve2d(initialState, selectedRules());
|
||||
if (store.loop) return draw2dNext(board);
|
||||
else draw2d(board);
|
||||
const initialGrid = create2dRandomGrid(
|
||||
store.board.width,
|
||||
store.board.height
|
||||
);
|
||||
store.board.grid = Object.freeze(evolve2d(initialGrid, selectedRules()));
|
||||
if (store.loop) return draw2dNext(store.board);
|
||||
else draw2d(store.board);
|
||||
store.toggleStop();
|
||||
};
|
||||
|
||||
// draw 2d automaton from the last known generated board
|
||||
const draw2dLast = async () => {
|
||||
if (!store.canDraw) return;
|
||||
if (store.loop) return draw2dNext(store.lastBoard);
|
||||
else draw2d(store.lastBoard);
|
||||
if (store.loop) return draw2dNext(store.board);
|
||||
else draw2d(store.board);
|
||||
store.toggleStop();
|
||||
};
|
||||
|
||||
// draw 2d automaton from an uploaded picture.
|
||||
// use the picture representation as an initial state
|
||||
const draw2dPicture = () => {
|
||||
// draw image on canvas
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillRect(0, 0, store.canvasWidth, store.canvasHeight);
|
||||
ctx.drawImage(
|
||||
const draw2dPicture = async () => {
|
||||
store.renderer.renderImage(
|
||||
store.picture,
|
||||
Math.floor((store.canvasWidth - store.picture.width) / 2),
|
||||
Math.floor((store.canvasHeight - store.picture.height) / 2),
|
||||
store.picture.width,
|
||||
store.picture.height
|
||||
store.renderer.ctx,
|
||||
store.renderer.width,
|
||||
store.renderer.height
|
||||
);
|
||||
|
||||
// draw the image back on the work canvas with the dimensions of the board
|
||||
workCtx.drawImage(store.picture, 0, 0, store.boardWidth, store.boardHeight);
|
||||
|
||||
// get the resized image data from work canvas
|
||||
const resized = workCtx.getImageData(
|
||||
0,
|
||||
0,
|
||||
store.boardWidth,
|
||||
store.boardHeight
|
||||
const resized = store.renderer.renderImage(
|
||||
store.picture,
|
||||
store.renderer.workCtx,
|
||||
store.board.width,
|
||||
store.board.height
|
||||
);
|
||||
|
||||
// convert the image into a 2D board of boolean based on pixel value
|
||||
store.lastBoard = Object.freeze(
|
||||
picToBoard(resized.data, store.boardWidth, store.boardHeight)
|
||||
);
|
||||
|
||||
const newBoard = picToBoard(resized.data, store.board);
|
||||
store.board.grid = Object.freeze(newBoard);
|
||||
store.toggleStop();
|
||||
};
|
||||
|
||||
// stop drawing routines and clear the canvas
|
||||
const reset = () => {
|
||||
store.toggleStop();
|
||||
store.lastBoard = null;
|
||||
ctx.clearRect(0, 0, store.canvasWidth, store.canvasHeight);
|
||||
store.reset = false;
|
||||
store.board.grid = null;
|
||||
store.renderer.reset();
|
||||
store.toggleReset();
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<canvas
|
||||
id="board-canvas"
|
||||
ref="board-canvas"
|
||||
:width="store.canvasWidth"
|
||||
:height="store.canvasHeight"
|
||||
/>
|
||||
<canvas
|
||||
id="work-canvas"
|
||||
ref="work-canvas"
|
||||
:width="store.canvasWidth"
|
||||
:height="store.canvasHeight"
|
||||
:width="store.renderer.width"
|
||||
:height="store.renderer.height"
|
||||
/>
|
||||
</template>
|
||||
<style>
|
||||
|
@ -5,17 +5,14 @@
|
||||
const store = globalStore();
|
||||
|
||||
const updateCellProperties = (event) => {
|
||||
const elem = event.target;
|
||||
store.cellProperties[elem.name] = elem.value;
|
||||
const { name, value } = event.target;
|
||||
store.setCellProperties(name, value);
|
||||
store.setBoardWidth();
|
||||
store.setBoardHeight();
|
||||
};
|
||||
|
||||
const switchColor = () => {
|
||||
[store.cellProperties["liveColor"], store.cellProperties["deadColor"]] = [
|
||||
store.cellProperties["deadColor"],
|
||||
store.cellProperties["liveColor"],
|
||||
];
|
||||
store.switchColor();
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -27,7 +24,7 @@
|
||||
<input
|
||||
name="liveColor"
|
||||
type="color"
|
||||
:value="store.cellProperties.liveColor"
|
||||
:value="store.board.cellProperties.liveColor"
|
||||
@input="updateCellProperties"
|
||||
/>
|
||||
</div>
|
||||
@ -36,7 +33,7 @@
|
||||
<input
|
||||
name="deadColor"
|
||||
type="color"
|
||||
:value="store.cellProperties.deadColor"
|
||||
:value="store.board.cellProperties.deadColor"
|
||||
@input="updateCellProperties"
|
||||
/>
|
||||
</div>
|
||||
@ -49,7 +46,7 @@
|
||||
name="size"
|
||||
type="number"
|
||||
min="1"
|
||||
:value="store.cellProperties.size"
|
||||
:value="store.board.cellProperties.size"
|
||||
@click="updateCellProperties"
|
||||
/>
|
||||
</div>
|
||||
|
@ -6,17 +6,17 @@
|
||||
|
||||
const updateCanvasHeight = (event) => {
|
||||
const elem = event.target;
|
||||
store.canvasHeight = elem.value;
|
||||
store.renderer.resize(elem.value, store.renderer.width);
|
||||
};
|
||||
|
||||
const updateCanvasWidth = (event) => {
|
||||
const elem = event.target;
|
||||
store.canvasWidth = elem.value;
|
||||
store.renderer.resize(elem.value, store.renderer.height);
|
||||
};
|
||||
|
||||
const updateRefreshRate = (event) => {
|
||||
const elem = event.target;
|
||||
store.refreshRate = elem.value;
|
||||
store.renderer.refreshRate = elem.value;
|
||||
};
|
||||
|
||||
const updateDrawingDirection = (event) => {
|
||||
@ -39,7 +39,7 @@
|
||||
name="canvasWidth"
|
||||
type="number"
|
||||
step="10"
|
||||
:value="store.canvasWidth"
|
||||
:value="store.renderer.width"
|
||||
@input="updateCanvasWidth"
|
||||
/>
|
||||
</div>
|
||||
@ -50,7 +50,7 @@
|
||||
name="canvasHeight"
|
||||
type="number"
|
||||
step="10"
|
||||
:value="store.canvasHeight"
|
||||
:value="store.renderer.height"
|
||||
@input="updateCanvasHeight"
|
||||
/>
|
||||
</div>
|
||||
@ -64,7 +64,7 @@
|
||||
type="number"
|
||||
min="100"
|
||||
step="100"
|
||||
:value="store.refreshRate"
|
||||
:value="store.renderer.refreshRate"
|
||||
@input="updateRefreshRate"
|
||||
/>
|
||||
</div>
|
||||
|
28
src/modules/board.js
Normal file
28
src/modules/board.js
Normal file
@ -0,0 +1,28 @@
|
||||
import { create2dState, create1dStateOneCell, create1dState } from "./core.js";
|
||||
|
||||
import { getRandomInt } from "./common.js";
|
||||
|
||||
function Board(width, height, grid = []) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
(this.cellProperties = {
|
||||
size: 3,
|
||||
liveColor: "#000000",
|
||||
deadColor: "#F5F5F5",
|
||||
}),
|
||||
(this.grid = grid);
|
||||
}
|
||||
|
||||
// create a first state, either a single living cell
|
||||
// at the center or random ones
|
||||
const create1dInitialState = (board, type = "onecell") => {
|
||||
if (type === "onecell") return create1dStateOneCell(board.width);
|
||||
return create1dState(board.width, getRandomInt, [0, 2]);
|
||||
};
|
||||
|
||||
// initialize 2d board with random cells
|
||||
const create2dRandomGrid = (width, height) => {
|
||||
return create2dState(width, height, getRandomInt, [0, 2]);
|
||||
};
|
||||
|
||||
export { Board, create1dInitialState, create2dRandomGrid };
|
@ -1,3 +1,5 @@
|
||||
// core functions to generate initial states and evolve them
|
||||
|
||||
// handles negative index and index bigger than its array length
|
||||
function guard(index, arrayLength) {
|
||||
if (index > arrayLength - 1) return 0;
|
||||
@ -15,7 +17,6 @@ function evolve1d(state, rules) {
|
||||
const cells = [getCell(x - 1), getCell(x), getCell(x + 1)];
|
||||
return rules[cells.join("")];
|
||||
});
|
||||
|
||||
return newState.map(Number);
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ export function picToBlackAndWhite(pixels, width, height) {
|
||||
}
|
||||
|
||||
// convert an ImageData into a 2D array of boolean (0, 1) values
|
||||
export function picToBoard(pixels, width, height) {
|
||||
export function picToBoard(pixels, board) {
|
||||
const flat = pixels.reduce((acc, pixel, index) => {
|
||||
const i = index * 4;
|
||||
const count = pixels[i] + pixels[i + 1] + pixels[i + 2];
|
||||
@ -44,19 +44,21 @@ export function picToBoard(pixels, width, height) {
|
||||
acc[index] = value;
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
return toMatrix(flat, width, height);
|
||||
// TODO: The representation has to be 2D, not the data structure
|
||||
// (change to flat)
|
||||
return toMatrix(flat, board.width, board.height);
|
||||
}
|
||||
|
||||
// convert board to ImageData
|
||||
// TODO : different cell to color functions
|
||||
// (binary, intermediate states, camaieux, etc)
|
||||
export function boardToPic(board, width, height, cellProperties) {
|
||||
const live = cellProperties.liveColor;
|
||||
const dead = cellProperties.deadColor;
|
||||
const img = new ImageData(width, height);
|
||||
export function boardToPic(board) {
|
||||
const live = board.cellProperties.liveColor;
|
||||
const dead = board.cellProperties.deadColor;
|
||||
const img = new ImageData(board.width, board.height);
|
||||
const colors = [hexToRGB(live), hexToRGB(dead)];
|
||||
board.flat().reduce((acc, cell, index) => {
|
||||
board.grid.flat().reduce((acc, cell, index) => {
|
||||
// TODO : bitshift operation instead of ternary
|
||||
const color = cell === 1 ? colors[0] : colors[1];
|
||||
const i = index * 4;
|
||||
acc[i] = color[0];
|
||||
@ -67,3 +69,13 @@ export function boardToPic(board, width, height, cellProperties) {
|
||||
}, img.data);
|
||||
return img;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/3332237/image-resizing-algorithm
|
||||
export function scaleToTargetSize(w1, h1, w2, h2) {
|
||||
const sourceRatio = w1 / h1;
|
||||
const targetRatio = w2 / h2;
|
||||
if (sourceRatio > targetRatio) {
|
||||
return [w2, w2 / sourceRatio];
|
||||
}
|
||||
return [h2 * sourceRatio, h2];
|
||||
}
|
||||
|
67
src/modules/renderer.js
Normal file
67
src/modules/renderer.js
Normal file
@ -0,0 +1,67 @@
|
||||
import { boardToPic, scaleToTargetSize } from "./picture.js";
|
||||
|
||||
function scaleAndApply(context, ratio, callback) {
|
||||
context.save();
|
||||
// rescale
|
||||
context.imageSmoothingEnabled = false;
|
||||
context.scale(ratio, ratio);
|
||||
// apply
|
||||
callback();
|
||||
context.restore();
|
||||
}
|
||||
|
||||
// draws the board representation on the canvas
|
||||
function render(board) {
|
||||
const d = board.cellProperties.size;
|
||||
// bool to RGBA colors
|
||||
const img = boardToPic(board);
|
||||
this.ctx.clearRect(0, 0, this.width, this.height);
|
||||
scaleAndApply(this.ctx, d, () => {
|
||||
this.workCtx.putImageData(img, 0, 0);
|
||||
this.ctx.drawImage(this.workCanvas, 0, 0, this.width, this.height);
|
||||
});
|
||||
}
|
||||
|
||||
// draw image on canvas
|
||||
function renderImage(image, ctx, tw, th) {
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillRect(0, 0, tw, th);
|
||||
const dimensions = scaleToTargetSize(image.width, image.height, tw, th);
|
||||
ctx.drawImage(
|
||||
image,
|
||||
Math.floor((tw - dimensions[0]) / 2),
|
||||
Math.floor((th - dimensions[1]) / 2),
|
||||
dimensions[0],
|
||||
dimensions[1]
|
||||
);
|
||||
return ctx.getImageData(0, 0, tw, th);
|
||||
}
|
||||
|
||||
function resize(width, height) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.canvas.height = height;
|
||||
this.canvas.width = width;
|
||||
this.workCanvas.height = height;
|
||||
this.workCanvas.width = width;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
this.ctx.clearRect(0, 0, this.width, this.height);
|
||||
}
|
||||
|
||||
function Renderer() {
|
||||
this.canvas = null;
|
||||
this.workCanvas = null;
|
||||
this.workCtx = null;
|
||||
this.width = null;
|
||||
this.height = null;
|
||||
this.ctx = null;
|
||||
this.refreshRate = 300;
|
||||
this.render = render;
|
||||
this.renderImage = renderImage;
|
||||
this.reset = reset;
|
||||
this.resize = resize;
|
||||
}
|
||||
|
||||
export { Renderer };
|
@ -1,4 +1,6 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { Board } from "../modules/board.js";
|
||||
import { Renderer } from "../modules/renderer.js";
|
||||
|
||||
export const globalStore = defineStore("globalStore", {
|
||||
state: () => {
|
||||
@ -21,19 +23,9 @@ export const globalStore = defineStore("globalStore", {
|
||||
name: "Conway's Game of Life",
|
||||
description: "The most popular 2d automata",
|
||||
},
|
||||
cellProperties: {
|
||||
size: 3,
|
||||
liveColor: "#000000",
|
||||
deadColor: "#F5F5F5",
|
||||
},
|
||||
canvasWidth: 0,
|
||||
canvasHeight: 0,
|
||||
boardWidth: 0,
|
||||
boardHeight: 0,
|
||||
refreshRate: 300,
|
||||
initial1dState: "onecell",
|
||||
drawingDirection: "y",
|
||||
lastBoard: null,
|
||||
board: new Board(),
|
||||
draw1d: false,
|
||||
draw2d: false,
|
||||
draw2dLast: false,
|
||||
@ -45,46 +37,61 @@ export const globalStore = defineStore("globalStore", {
|
||||
activeSubMenu: "",
|
||||
loop: false,
|
||||
lastAction: "drawfromlast",
|
||||
renderer: new Renderer(),
|
||||
};
|
||||
},
|
||||
actions: {
|
||||
setBoardWidth() {
|
||||
this.boardWidth = Math.floor(this.canvasWidth / this.cellProperties.size);
|
||||
this.board.width = Math.floor(
|
||||
this.renderer.width / this.board.cellProperties.size
|
||||
);
|
||||
},
|
||||
setBoardHeight() {
|
||||
this.boardHeight = Math.floor(
|
||||
this.canvasHeight / this.cellProperties.size
|
||||
this.board.height = Math.floor(
|
||||
this.renderer.height / this.board.cellProperties.size
|
||||
);
|
||||
},
|
||||
setCellProperties(name, value) {
|
||||
this.board.cellProperties[name] = value;
|
||||
},
|
||||
switchColor() {
|
||||
[
|
||||
this.board.cellProperties["liveColor"],
|
||||
this.board.cellProperties["deadColor"],
|
||||
] = [
|
||||
this.board.cellProperties["deadColor"],
|
||||
this.board.cellProperties["liveColor"],
|
||||
];
|
||||
},
|
||||
toggleDraw1d() {
|
||||
this.setActiveSubMenu("");
|
||||
this.setMainMenu(false);
|
||||
this.draw1d = true;
|
||||
this.draw1d = !this.draw1d;
|
||||
},
|
||||
toggleDraw2d() {
|
||||
this.setActiveSubMenu("");
|
||||
this.lastAction = "draw2d";
|
||||
this.setMainMenu(false);
|
||||
this.toggleStop();
|
||||
this.canDraw = true;
|
||||
this.draw2d = true;
|
||||
this.canDraw = !this.canDraw;
|
||||
this.draw2d = !this.draw2d;
|
||||
},
|
||||
toggleDraw2dLast() {
|
||||
this.setActiveSubMenu("");
|
||||
this.lastAction = "drawfromlast";
|
||||
this.setMainMenu(false);
|
||||
this.toggleStop();
|
||||
this.canDraw = true;
|
||||
this.draw2dLast = true;
|
||||
this.canDraw = !this.canDraw;
|
||||
this.draw2dLast = !this.draw2dLast;
|
||||
},
|
||||
toggle2dDrawFromPicture() {
|
||||
this.toggleStop();
|
||||
this.canDraw = true;
|
||||
this.draw2dpicture = true;
|
||||
this.canDraw = !this.canDraw;
|
||||
this.draw2dpicture = !this.draw2dpicture;
|
||||
},
|
||||
toggleReset() {
|
||||
this.toggleStop();
|
||||
this.reset = true;
|
||||
this.reset = !this.reset;
|
||||
},
|
||||
toggleStop() {
|
||||
this.draw1d = false;
|
||||
|
28
tests/board.test.js
Normal file
28
tests/board.test.js
Normal file
@ -0,0 +1,28 @@
|
||||
import { describe, expect, test } from "vitest";
|
||||
import {
|
||||
Board,
|
||||
create1dInitialState,
|
||||
create2dRandomGrid,
|
||||
} from "src/modules/board.js";
|
||||
|
||||
describe("Board", () => {
|
||||
const board = new Board(503, 301);
|
||||
test("create1dInitialState onecell", () => {
|
||||
const stateOne = create1dInitialState(board);
|
||||
expect(stateOne.length).toBe(board.width);
|
||||
expect(stateOne).toContain(1);
|
||||
});
|
||||
|
||||
test("create1dInitialState random", () => {
|
||||
const stateRandom = create1dInitialState(board, "random");
|
||||
expect(stateRandom.length).toBe(board.width);
|
||||
expect(stateRandom).toContain(1);
|
||||
});
|
||||
|
||||
test("create2dRandomGrid", () => {
|
||||
const board = new Board(503, 301);
|
||||
const got = create2dRandomGrid(board.width, board.height);
|
||||
expect(got.length).toBe(board.height);
|
||||
expect(got[0].length).toBe(board.width);
|
||||
});
|
||||
});
|
@ -13,4 +13,11 @@ export default defineConfig({
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
// enable jest-like global test APIs
|
||||
globals: true,
|
||||
// simulate DOM with happy-dom
|
||||
// (requires installing happy-dom as a peer dependency)
|
||||
environment: "happy-dom",
|
||||
},
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user