diff --git a/src/components/CanvasBoard.vue b/src/components/CanvasBoard.vue index f7ce42f..c2f3373 100644 --- a/src/components/CanvasBoard.vue +++ b/src/components/CanvasBoard.vue @@ -1,7 +1,13 @@ + diff --git a/src/components/MenuRow.vue b/src/components/MenuRow.vue index 743bfe7..83732e4 100644 --- a/src/components/MenuRow.vue +++ b/src/components/MenuRow.vue @@ -30,7 +30,11 @@ window.removeEventListener("click", this.onWindowClick); }, methods: { - ...mapActions(globalStore, ["setActiveSubMenu", "toggleMainMenu"]), + ...mapActions(globalStore, [ + "setActiveSubMenu", + "toggleMainMenu", + "setMainMenu", + ]), onKeyDown: function (event) { // escape if (event.keyCode == 27) { diff --git a/src/modules/automata.js b/src/modules/automata.js index 8ed51a5..ac4df56 100644 --- a/src/modules/automata.js +++ b/src/modules/automata.js @@ -91,6 +91,39 @@ function conwayRules(cell, neighbors) { return cell; } +// variation on the game of life's rules, +// where the "three live neighbors" rule is ignored +function threebornRules(cell, neighbors) { + // loneliness rule + if (cell === 1 && neighbors < 2) return 0; + // overpopulation rule + if (cell === 1 && neighbors > 3) return 0; + // born when three live neighbors rule + return cell; +} + +// variation on the game of life's rules, +// where the loneliness rule is ignored +function lonelinessRules(cell, neighbors) { + // overpopulation rule + if (cell === 1 && neighbors > 3) return 0; + // born when three live neighbors rule + if (cell === 0 && neighbors === 3) return 1; + // the cell remains the same if none apply + return cell; +} + +// variation on the game of life's rules, +// where the overpopulation rule is ignored +function overpopulationRules(cell, neighbors) { + // loneliness rule + if (cell === 1 && neighbors < 2) return 0; + // born when three live neighbors rule + if (cell === 0 && neighbors === 3) return 1; + // the cell remains the same if none apply + return cell; +} + // get the next evolution of a 2D CA initial state // Rules : Moore neighborhood function evolve2d(board, rulesFn) { @@ -148,6 +181,9 @@ export { createBoard, create1dStateOneCell, conwayRules, + overpopulationRules, + lonelinessRules, + threebornRules, evolve1d, evolve2d, }; diff --git a/src/modules/picture.js b/src/modules/picture.js new file mode 100644 index 0000000..9a91b67 --- /dev/null +++ b/src/modules/picture.js @@ -0,0 +1,39 @@ +// https://stackoverflow.com/questions/4492385/convert-simple-array-into-two-dimensional-array-matrix +// convert a 1D array into a 2D matrix +export function toMatrix(array, width) { + return array.reduce( + (rows, key, index) => + (index % width == 0 + ? rows.push([key]) + : rows[rows.length - 1].push(key)) && rows, + [] + ); +} + +// convert an image into a black and white image +export function picToBlackAndWhite(pixels, width, height) { + return pixels.reduce((acc, pixel, index) => { + if (index % 4 == 0) { + const count = pixels[index] + pixels[index + 1] + pixels[index + 2]; + const colour = count >= 255 ? 255 : 1; + acc.data[index] = colour; + acc.data[index + 1] = colour; + acc.data[index + 2] = colour; + acc.data[index + 3] = 255; + } + return acc; + }, new ImageData(width, height)); +} + +// convert an ImageData into a 2D array of boolean (0, 1) values +export function picToBoard(pixels, width, height) { + const flat = pixels.reduce((acc, pixel, index) => { + if (index % 4 == 0) { + const count = pixels[index] + pixels[index + 1] + pixels[index + 2]; + const value = count >= 255 ? 1 : 0; + acc.push(value); + } + return acc; + }, []); + return toMatrix(flat, Math.max(width, height)); +} diff --git a/src/modules/preset.js b/src/modules/preset.js index 0eee491..922aab0 100644 --- a/src/modules/preset.js +++ b/src/modules/preset.js @@ -92,4 +92,30 @@ const initialStates = [ }, ]; -export { presetRuleset, initialStates }; +const preset2dRules = [ + { + id: "conway", + name: "Conway's Game of Life", + description: "The most popular 2d automata", + }, + { + id: "overpopulation", + name: "Overpopulation variation", + description: + "Variation on Conway's Game of Life *without* the overpopulation rule", + }, + { + id: "loneliness", + name: "Loneliness variation", + description: + "Variation on Conway's Game of Life *without* the loneliness rule", + }, + { + id: "threeborn", + name: "Three lives variation", + description: + "Variation on Conway's Game of Life *without* the 'three live neighbors' rule", + }, +]; + +export { presetRuleset, initialStates, preset2dRules }; diff --git a/src/stores/index.js b/src/stores/index.js index 5b40b41..cd81b56 100644 --- a/src/stores/index.js +++ b/src/stores/index.js @@ -16,6 +16,11 @@ export const globalStore = defineStore("globalStore", { "000": 1, }, }, + selected2dRules: { + id: "conway", + name: "Conway's Game of Life", + description: "The most popular 2d automata", + }, cellProperties: { size: 3, liveColor: "#000000", @@ -32,8 +37,10 @@ export const globalStore = defineStore("globalStore", { draw1d: false, draw2d: false, draw2dLast: false, + draw2dpicture: false, reset: false, canDraw: true, + picture: null, mainMenu: false, activeSubMenu: "", }; @@ -66,6 +73,11 @@ export const globalStore = defineStore("globalStore", { this.canDraw = true; this.draw2dLast = true; }, + toggle2dDrawFromPicture() { + this.toggleStop(); + this.canDraw = true; + this.draw2dpicture = true; + }, toggleReset() { this.toggleStop(); this.reset = true; @@ -74,6 +86,7 @@ export const globalStore = defineStore("globalStore", { this.draw1d = false; this.draw2d = false; this.draw2dLast = false; + this.draw2dpicture = false; this.canDraw = false; }, setActiveSubMenu(data) {