From 1af9ada678003593e222a7334f07fb2bb93753bb Mon Sep 17 00:00:00 2001 From: kg0816 <211191696+kg0816@users.noreply.github.com> Date: Sat, 22 Nov 2025 00:43:44 +0900 Subject: [PATCH 1/5] feat: add colorful.js to rules --- src/lib/assets/life-game-rules/colorful.js | 335 +++++++++++++++++++++ src/lib/icons/index.ts | 1 + src/lib/icons/paint-brush.svg | 3 + src/lib/rules-explanation.ts | 16 +- src/routes/+page.svelte | 50 ++- 5 files changed, 401 insertions(+), 4 deletions(-) create mode 100644 src/lib/assets/life-game-rules/colorful.js create mode 100644 src/lib/icons/paint-brush.svg diff --git a/src/lib/assets/life-game-rules/colorful.js b/src/lib/assets/life-game-rules/colorful.js new file mode 100644 index 0000000..eefb32a --- /dev/null +++ b/src/lib/assets/life-game-rules/colorful.js @@ -0,0 +1,335 @@ +"use strict"; + +let generationFigure = 0; +let isDragging = false; +let dragColor = 0; // ドラッグ中に設定する色 +let isPlacingTemplate = false; +let patternShape = []; +let patternHeight = 0; +let patternWidth = 0; +let previewCells = []; + +//盤面の大きさ +let boardSize = 20; +const cellSize = 450 / boardSize; + +//セルの誕生/生存条件 +const birthCounts = [3]; +const survivalCounts = [2, 3]; + +// 色の定数定義 +const WHITE = 0xffffff; // 死んだセル(白) +const BLACK = 0x000000; // 生きたセル(黒) +let currentSelectedColor = BLACK; // 描かれるセルの色 + +// around: 周囲の生きたセル数 self: 自身が生きているかどうか +function isNextAlive(around, self) { + // 自身が死んでいる & 周囲が birthCounts で誕生 + if (!isAlive(self) && birthCounts.includes(around)) { + return true; + } + // 自身が生きている & 周囲が survivalCounts で生存 + if (isAlive(self) && survivalCounts.includes(around)) { + return true; + } + return false; +} + +function isAlive(self) { + return self !== WHITE ? true : false; +} + +// cellの状態に応じた色を返す関数 +function getStyle(cell) { + if (cell === WHITE) return "white"; + // 16進数を#付きの色文字列に変換 + return "#" + cell.toString(16).padStart(6, "0"); +} + +// 誕生時の色を計算 +function getBirthColor(aroundCells) { + const aliveCells = aroundCells.filter((cell) => isAlive(cell)); + + let totalR = 0; + let totalG = 0; + let totalB = 0; + + for (const cell of aliveCells) { + totalR += (cell >> 16) & 0xff; + totalG += (cell >> 8) & 0xff; + totalB += cell & 0xff; + } + + const avgR = Math.round(totalR / aliveCells.length); + const avgG = Math.round(totalG / aliveCells.length); + const avgB = Math.round(totalB / aliveCells.length); + + return (avgR << 16) | (avgG << 8) | avgB; +} + +//Boardの初期化 +let board = Array.from({ length: boardSize }, () => Array.from({ length: boardSize }, () => WHITE)); +const table = document.getElementById("game-board"); + +//盤面をBoardに従って変更する関数達(Boardを変更したら実行する) +function renderBoard() { + // bodyを中央配置に設定 + document.body.style.display = "flex"; + document.body.style.justifyContent = "center"; + document.body.style.alignItems = "center"; + document.body.style.minHeight = "100vh"; + document.body.style.margin = "0"; + document.body.style.padding = "0"; + + // 初回の盤面生成 + table.innerHTML = ""; + for (let i = 0; i < boardSize; i++) { + const tr = document.createElement("tr"); + tr.style.padding = "0"; + for (let j = 0; j < boardSize; j++) { + const td = document.createElement("td"); + td.style.padding = "0"; + const button = document.createElement("button"); + button.style.backgroundColor = getStyle(board[i][j]); //Boardの対応する値によって色を変更 + // ボードが大きいときは border をつけない + if (boardSize >= 50) { + button.style.border = "none"; + table.style.border = "1px solid black"; + } else { + button.style.border = "0.5px solid black"; + } + button.style.width = `${cellSize}px`; + button.style.height = `${cellSize}px`; + button.style.padding = "0"; + button.style.display = "block"; + button.onclick = () => { + if (isPlacingTemplate) { + clearPreview(); + isPlacingTemplate = false; + if (i + patternHeight < boardSize + 1 && j + patternWidth < boardSize + 1) { + for (let r = 0; r < patternHeight; r++) { + for (let c = 0; c < patternWidth; c++) { + const boardRow = i + r; + const boardCol = j + c; + board[boardRow][boardCol] = patternShape[r][c] ? currentSelectedColor : WHITE; + } + } + rerender(); + stop(); + } else { + window.parent.postMessage( + { + type: "Size shortage", + data: {}, + }, + "*", + ); + } + } + }; + button.onmousedown = (e) => { + e.preventDefault(); + if (!isPlacingTemplate) { + isDragging = true; + board[i][j] = board[i][j] === WHITE ? currentSelectedColor : WHITE; + dragColor = board[i][j]; + button.style.backgroundColor = getStyle(board[i][j]); + } + }; + button.onmouseenter = () => { + if (isDragging && board[i][j] !== dragColor && !isPlacingTemplate) { + board[i][j] = dragColor; + button.style.backgroundColor = getStyle(board[i][j]); + } + if (isPlacingTemplate) { + drawPreview(i, j); + } + }; + td.appendChild(button); + tr.appendChild(td); + } + table.appendChild(tr); + } +} + +table.onmouseleave = () => { + if (isPlacingTemplate) { + clearPreview(); + } +}; + +function drawPreview(row, col) { + clearPreview(); + for (let r = 0; r < patternHeight; r++) { + for (let c = 0; c < patternWidth; c++) { + if (patternShape[r][c] === 1) { + const boardRow = row + r; + const boardCol = col + c; + if (boardRow < boardSize && boardCol < boardSize) { + const cell = table.rows[boardRow].cells[boardCol].firstChild; + cell.style.backgroundColor = "gray"; + previewCells.push({ row: boardRow, col: boardCol }); + } + } + } + } +} + +function clearPreview() { + previewCells.forEach((cellPos) => { + const cell = table.rows[cellPos.row].cells[cellPos.col].firstChild; + cell.style.backgroundColor = getStyle(board[cellPos.row][cellPos.col]); + }); + previewCells = []; +} + +function rerender() { + // 2回目以降の盤面生成 + for (let i = 0; i < boardSize; i++) { + for (let j = 0; j < boardSize; j++) { + const button = table.children[i].children[j].children[0]; + + // 色の更新 + const currentCellColor = button.style.backgroundColor; + const expectedCellColor = getStyle(board[i][j]); + if (currentCellColor !== expectedCellColor) { + button.style.backgroundColor = expectedCellColor; + } + + // セルサイズの更新 + const currentCellsize = button.style.width; + const expectedCellsize = `${cellSize}px`; + if (currentCellsize !== expectedCellsize) { + button.style.width = expectedCellsize; + button.style.height = expectedCellsize; + } + } + } +} + +document.addEventListener("mouseup", () => { + isDragging = false; +}); + +renderBoard(); + +function generationChange(num) { + //現在の世代を表すgenerationFigureを変更し、文章も変更 + generationFigure = num; + window.parent.postMessage( + { + type: "generation_change", + data: generationFigure, + }, + "*", + ); +} + +function progressBoard() { + const newBoard = structuredClone(board); + for (let i = 0; i < boardSize; i++) { + for (let j = 0; j < boardSize; j++) { + //周囲のマスに生きたセルが何個あるかを計算(aroundに格納)↓ + let around = 0; + const aroundCells = []; + let tate, yoko; + if (i === 0) { + tate = [0, 1]; + } else if (i === boardSize - 1) { + tate = [0, -1]; + } else { + tate = [-1, 0, 1]; + } + if (j === 0) { + yoko = [0, 1]; + } else if (j === boardSize - 1) { + yoko = [0, -1]; + } else { + yoko = [-1, 0, 1]; + } + + for (let ii = 0; ii < tate.length; ii++) { + for (let jj = 0; jj < yoko.length; jj++) { + if (tate[ii] !== 0 || yoko[jj] !== 0) { + if (isAlive(board[i + tate[ii]][j + yoko[jj]])) { + around += 1; + aroundCells.push(board[i + tate[ii]][j + yoko[jj]]); + } + } + } + } + //↑周囲のマスに生きたセルが何個あるかを計算(aroundに格納) + + // 生死を判定 + if (isNextAlive(around, board[i][j])) { + // 生きている場合 + newBoard[i][j] = isAlive(board[i][j]) ? board[i][j] : getBirthColor(aroundCells); + } else { + // 死んでいる場合 + newBoard[i][j] = WHITE; + } + } + } + board = newBoard; + generationChange(generationFigure + 1); + rerender(); +} + +//イベント + +on.progress = () => { + progressBoard(); +}; + +on.board_reset = () => { + //すべて死んだセルにBoardを変更 + board = Array.from({ length: boardSize }, () => Array.from({ length: boardSize }, () => WHITE)); + renderBoard(); + generationChange(0); +}; + +on.board_randomize = () => { + //生きたセル死んだセルランダムにBoardを変更 + board = Array.from({ length: boardSize }, () => + Array.from({ length: boardSize }, () => { + if (Math.random() > 0.5) { + // 生きたセル:ランダムな色を生成 + const r = Math.floor(Math.random() * 256); + const g = Math.floor(Math.random() * 256); + const b = Math.floor(Math.random() * 256); + return (r << 16) | (g << 8) | b; + } else { + // 死んだセル + return WHITE; + } + }), + ); + renderBoard(); + generationChange(0); +}; + +on.get_boardsize = () => { + window.parent.postMessage({ type: "get_boardsize", data: boardSize }, "*"); +}; + +on.place_template = (template) => { + patternShape = template; + patternHeight = patternShape.length; + patternWidth = patternShape[0].length; + isPlacingTemplate = true; + table.style.cursor = "crosshair"; +}; + +on.save_board = async () => { + window.parent.postMessage({ type: "save_board", data: board }, "*"); +}; + +on.apply_board = (newBoard) => { + board = newBoard; + renderBoard(); + generationChange(0); +}; + +on.apply_color = (colorValue) => { + currentSelectedColor = colorValue; +}; diff --git a/src/lib/icons/index.ts b/src/lib/icons/index.ts index e930bc2..525e10a 100644 --- a/src/lib/icons/index.ts +++ b/src/lib/icons/index.ts @@ -10,3 +10,4 @@ export { default as reset } from "./reset.svg"; export { default as accelerate } from "./accelerate.svg"; export { default as decelerate } from "./decelerate.svg"; export { default as questionmark } from "./questionmark.svg"; +export { default as paintBrush } from "./paint-brush.svg"; diff --git a/src/lib/icons/paint-brush.svg b/src/lib/icons/paint-brush.svg new file mode 100644 index 0000000..6add0c0 --- /dev/null +++ b/src/lib/icons/paint-brush.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/lib/rules-explanation.ts b/src/lib/rules-explanation.ts index 76930f7..ce1dced 100644 --- a/src/lib/rules-explanation.ts +++ b/src/lib/rules-explanation.ts @@ -1,6 +1,7 @@ import lifespan from "$lib/assets/life-game-rules/lifespan.js?raw"; import probabilistics from "$lib/assets/life-game-rules/probabilistics.js?raw"; import wolframcode from "$lib/assets/life-game-rules/wolframcode.js?raw"; +import colorful from "$lib/assets/life-game-rules/colorful.js?raw"; export type RuleExplanation = { name: { @@ -27,8 +28,8 @@ export const rulesExplanation = { }, probabilistics: { name: { - ja: "確率システム", - en: "Probabilistic system", + ja: "確率的オートマトン", + en: "Probabilistic automaton", }, description: { ja: "生死に確率を導入できます", @@ -47,4 +48,15 @@ export const rulesExplanation = { }, code: wolframcode, }, + colorful: { + name: { + ja: "カラフル", + en: "Colorful", + }, + description: { + ja: "多彩な色付けを可能にするシステムです", + en: "A system that enables colorful coloring", + }, + code: colorful, + }, }; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 59e190a..9aeb09f 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -33,6 +33,9 @@ let generationFigure = $state(0); let sizeValue = $state(20); + let showColorPicker = $state(false); + let selectedColor = $state("#000000"); + const boardManager = new BoardManager(); const codeManager = new CodeManager(); @@ -63,7 +66,8 @@ | "save_board" | "apply_board" | "get_boardsize" - | "progress"; + | "progress" + | "apply_color"; type IncomingEvent = "generation_change" | "get_boardsize" | "Size shortage" | "save_board"; @@ -143,6 +147,14 @@ editingCode = rule.code; appliedCode = rule.code; } + + function applyColor(color: string) { + // 16進数文字列を数値に変換して送信 + const hex = color.startsWith("#") ? color.slice(1) : color; + const hexValue = parseInt(hex, 16); + sendEvent("apply_color", hexValue); + showColorPicker = false; + } + +{#if showColorPicker} +
+

+ {isJapanese + ? "色選択可能時のみ利用できます" + : "Available only when color selection is enabled"} +

+ +
+ + +
+
+{/if} From fc69daaaf571012139035e360e0f8af6896a5bc9 Mon Sep 17 00:00:00 2001 From: kg0816 <211191696+kg0816@users.noreply.github.com> Date: Sat, 22 Nov 2025 01:04:52 +0900 Subject: [PATCH 2/5] fix: add getCellColor function to display colors in board preview --- src/lib/board-preview.ts | 1 + src/lib/components/BoardModals.svelte | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/lib/board-preview.ts b/src/lib/board-preview.ts index b21dbe8..36bce95 100644 --- a/src/lib/board-preview.ts +++ b/src/lib/board-preview.ts @@ -5,6 +5,7 @@ const PREVIEW_SIZE = 20; * 20x20 に満たない場合は、中央に配置し、周囲を false (空白) で埋めます。 */ export function createBoardPreview(boardData: number[][]): number[][] { + console.log("Input board sample:", boardData[0]?.slice(0, 3)); const boardHeight = boardData.length; const boardWidth = boardData[0]?.length || 0; diff --git a/src/lib/components/BoardModals.svelte b/src/lib/components/BoardModals.svelte index 791271e..6419138 100644 --- a/src/lib/components/BoardModals.svelte +++ b/src/lib/components/BoardModals.svelte @@ -26,6 +26,21 @@ showConfirmation = false; selectedBoardId = null; } + + function getCellColor(cell: number): string { + const WHITE = 0xffffff; + + // 色対応版(0xFFFFFF形式) + if (cell === WHITE) return "white"; + if (cell === 0x000000) return "black"; + + // レガシー版(0/1形式)への互換性 + if (cell === 0) return "white"; + if (cell === 1) return "black"; + + // その他の色値 + return "#" + cell.toString(16).padStart(6, "0"); + } @@ -54,7 +69,7 @@ {#each manager.saveState.preview as row, i (i)}
{#each row as cell, j (j)} -
+
{/each}
{/each} @@ -110,7 +125,10 @@ {#each item.preview as row, i (i)}
{#each row as cell, j (j)} -
+
{/each}
{/each} @@ -179,7 +197,4 @@ width: 3px; height: 3px; } - .preview-cell.alive { - background-color: black; - } From f33795f01385b47150ce75ebb70de5c4d0f91b0f Mon Sep 17 00:00:00 2001 From: kg0816 <211191696+kg0816@users.noreply.github.com> Date: Sat, 22 Nov 2025 01:29:01 +0900 Subject: [PATCH 3/5] refactor: unify board format in legacy files --- src/iframe/life-game.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/iframe/life-game.js b/src/iframe/life-game.js index 5cea482..ff2b6fa 100644 --- a/src/iframe/life-game.js +++ b/src/iframe/life-game.js @@ -89,7 +89,6 @@ function renderBoard() { } } rerender(); - stop(); } else { window.parent.postMessage( { @@ -105,7 +104,7 @@ function renderBoard() { e.preventDefault(); if (!isPlacingTemplate) { isDragging = true; - board[i][j] = board[i][j] === 1 ? 0 : 1; + board[i][j] = board[i][j] ? 0 : 1; dragMode = board[i][j]; button.style.backgroundColor = board[i][j] ? aliveCellColor : deadCellColor; } From 30a15b764d684b4e72fc5d103099fd495d3850d6 Mon Sep 17 00:00:00 2001 From: kg0816 <211191696+kg0816@users.noreply.github.com> Date: Sat, 22 Nov 2025 02:48:15 +0900 Subject: [PATCH 4/5] feat: add isColorful flag for color mode support --- prisma/schema.prisma | 1 + src/iframe/life-game.js | 27 ++++++++++-------- src/lib/api/board.ts | 3 +- src/lib/assets/life-game-rules/colorful.js | 27 ++++++++++-------- src/lib/assets/life-game-rules/lifespan.js | 16 ++++++++++- .../assets/life-game-rules/probabilistics.js | 16 ++++++++++- src/lib/assets/life-game-rules/wolframcode.js | 16 ++++++++++- src/lib/components/BoardModals.svelte | 22 ++++++++------- src/lib/models/BoardManager.svelte.ts | 5 +++- src/routes/+page.svelte | 28 +++++++++++++++---- src/routes/api/board/+server.ts | 6 ++-- 11 files changed, 123 insertions(+), 44 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index e93858e..fe7fb04 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -22,6 +22,7 @@ model Board { name String preview Json code Json + isColorful Boolean } model Code { diff --git a/src/iframe/life-game.js b/src/iframe/life-game.js index ff2b6fa..cddd278 100644 --- a/src/iframe/life-game.js +++ b/src/iframe/life-game.js @@ -8,9 +8,10 @@ let patternShape = []; let patternHeight = 0; let patternWidth = 0; let previewCells = []; +let isColorful = false; //盤面の大きさ -let boardSize = 20; +const boardSize = 20; const cellSize = 450 / boardSize; //セルの色 @@ -168,14 +169,6 @@ function rerender() { if (currentCellColor !== expectedCellColor) { button.style.backgroundColor = expectedCellColor; } - - // セルサイズの更新 - const currentCellsize = button.style.width; - const expectedCellsize = `${cellSize}px`; - if (currentCellsize !== expectedCellsize) { - button.style.width = expectedCellsize; - button.style.height = expectedCellsize; - } } } } @@ -270,11 +263,23 @@ on.place_template = (template) => { }; on.save_board = async () => { - window.parent.postMessage({ type: "save_board", data: board }, "*"); + window.parent.postMessage( + { + type: "save_board", + data: { + board: board, + isColorful: isColorful, + }, + }, + "*", + ); }; - on.apply_board = (newBoard) => { board = newBoard; renderBoard(); generationChange(0); }; + +on.request_colorful_status = () => { + window.parent.postMessage({ type: "colorful_status", data: isColorful }, "*"); +}; diff --git a/src/lib/api/board.ts b/src/lib/api/board.ts index bbe477c..9b7fbe6 100644 --- a/src/lib/api/board.ts +++ b/src/lib/api/board.ts @@ -1,7 +1,7 @@ import { toast } from "$lib/models/ToastStore.svelte"; export async function saveBoard( - data: { board: number[][]; name: string; code: string }, + data: { board: number[][]; name: string; code: string; isColorful: boolean }, isJapanese: boolean, ) { try { @@ -67,6 +67,7 @@ export async function fetchBoardList(isJapanese: boolean): Promise { }; on.save_board = async () => { - window.parent.postMessage({ type: "save_board", data: board }, "*"); + window.parent.postMessage( + { + type: "save_board", + data: { + board: board, + isColorful: isColorful, + }, + }, + "*", + ); }; on.apply_board = (newBoard) => { @@ -333,3 +334,7 @@ on.apply_board = (newBoard) => { on.apply_color = (colorValue) => { currentSelectedColor = colorValue; }; + +on.request_colorful_status = () => { + window.parent.postMessage({ type: "colorful_status", data: isColorful }, "*"); +}; diff --git a/src/lib/assets/life-game-rules/lifespan.js b/src/lib/assets/life-game-rules/lifespan.js index 1adbad8..efb8e6e 100644 --- a/src/lib/assets/life-game-rules/lifespan.js +++ b/src/lib/assets/life-game-rules/lifespan.js @@ -9,6 +9,7 @@ let patternShape = []; let patternHeight = 0; let patternWidth = 0; let previewCells = []; +let isColorful = false; //変数設定 let boardSize = 20; //盤面の大きさ(20x20) @@ -319,7 +320,16 @@ on.place_template = (template) => { }; on.save_board = async () => { - window.parent.postMessage({ type: "save_board", data: board }, "*"); + window.parent.postMessage( + { + type: "save_board", + data: { + board: board, + isColorful: isColorful, + }, + }, + "*", + ); }; on.apply_board = (newBoard) => { @@ -328,3 +338,7 @@ on.apply_board = (newBoard) => { generationChange(0); stop(); }; + +on.request_colorful_status = () => { + window.parent.postMessage({ type: "colorful_status", data: isColorful }, "*"); +}; diff --git a/src/lib/assets/life-game-rules/probabilistics.js b/src/lib/assets/life-game-rules/probabilistics.js index 933dabb..324a1ed 100644 --- a/src/lib/assets/life-game-rules/probabilistics.js +++ b/src/lib/assets/life-game-rules/probabilistics.js @@ -9,6 +9,7 @@ let patternShape = []; let patternHeight = 0; let patternWidth = 0; let previewCells = []; +let isColorful = false; //変数設定 let boardSize = 20; //盤面の大きさ(20x20) @@ -282,7 +283,16 @@ on.place_template = (template) => { }; on.save_board = async () => { - window.parent.postMessage({ type: "save_board", data: board }, "*"); + window.parent.postMessage( + { + type: "save_board", + data: { + board: board, + isColorful: isColorful, + }, + }, + "*", + ); }; on.apply_board = (newBoard) => { @@ -291,3 +301,7 @@ on.apply_board = (newBoard) => { generationChange(0); stop(); }; + +on.request_colorful_status = () => { + window.parent.postMessage({ type: "colorful_status", data: isColorful }, "*"); +}; diff --git a/src/lib/assets/life-game-rules/wolframcode.js b/src/lib/assets/life-game-rules/wolframcode.js index 5c735e3..bdd797e 100644 --- a/src/lib/assets/life-game-rules/wolframcode.js +++ b/src/lib/assets/life-game-rules/wolframcode.js @@ -2,6 +2,7 @@ let generationFigure = 0; let currentRow = 0; +let isColorful = false; //盤面の大きさ const boardSize = 201; //奇数に設定する @@ -128,5 +129,18 @@ on.board_randomize = () => { }; on.save_board = async () => { - window.parent.postMessage({ type: "save_board", data: board }, "*"); + window.parent.postMessage( + { + type: "save_board", + data: { + board: board, + isColorful: isColorful, + }, + }, + "*", + ); +}; + +on.request_colorful_status = () => { + window.parent.postMessage({ type: "colorful_status", data: isColorful }, "*"); }; diff --git a/src/lib/components/BoardModals.svelte b/src/lib/components/BoardModals.svelte index 6419138..5f01c3f 100644 --- a/src/lib/components/BoardModals.svelte +++ b/src/lib/components/BoardModals.svelte @@ -5,10 +5,12 @@ manager, isJapanese, onSelect, + isColorful, }: { manager: BoardManager; isJapanese: boolean; onSelect: (id: number) => void; + isColorful: boolean; } = $props(); let showConfirmation = $state(false); @@ -30,16 +32,16 @@ function getCellColor(cell: number): string { const WHITE = 0xffffff; - // 色対応版(0xFFFFFF形式) - if (cell === WHITE) return "white"; - if (cell === 0x000000) return "black"; - - // レガシー版(0/1形式)への互換性 - if (cell === 0) return "white"; - if (cell === 1) return "black"; - - // その他の色値 - return "#" + cell.toString(16).padStart(6, "0"); + if (isColorful) { + // 色対応版(0xFFFFFF形式) + if (cell === WHITE) return "white"; + return "#" + cell.toString(16).padStart(6, "0"); + } else { + // レガシー版(0/1形式)への互換性 + if (cell === 0) return "white"; + if (cell === 1) return "black"; + } + return "white"; // 不明な値の場合 } diff --git a/src/lib/models/BoardManager.svelte.ts b/src/lib/models/BoardManager.svelte.ts index f608637..0e751e4 100644 --- a/src/lib/models/BoardManager.svelte.ts +++ b/src/lib/models/BoardManager.svelte.ts @@ -15,6 +15,7 @@ type SaveState = name: string; preview: number[][]; code: string; + isColorful: boolean; }; type LoadState = @@ -28,7 +29,7 @@ export class BoardManager { constructor() {} - openSaveModal(board: number[][], code: string) { + openSaveModal(board: number[][], code: string, isColorful: boolean) { const preview = createBoardPreview(board); this.saveState = { saving: true, @@ -36,6 +37,7 @@ export class BoardManager { name: "", preview: preview, code: code, + isColorful: isColorful, }; } @@ -51,6 +53,7 @@ export class BoardManager { board: this.saveState.board, name: name, code: this.saveState.code, + isColorful: this.saveState.isColorful, }, isJapanese, ); diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 9aeb09f..652ce9b 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -35,6 +35,7 @@ let showColorPicker = $state(false); let selectedColor = $state("#000000"); + let isColorful = $state(false); const boardManager = new BoardManager(); const codeManager = new CodeManager(); @@ -67,9 +68,15 @@ | "apply_board" | "get_boardsize" | "progress" - | "apply_color"; + | "apply_color" + | "request_colorful_status"; - type IncomingEvent = "generation_change" | "get_boardsize" | "Size shortage" | "save_board"; + type IncomingEvent = + | "generation_change" + | "get_boardsize" + | "Size shortage" + | "save_board" + | "colorful_status"; function handleMessage(event: MessageEvent<{ type: IncomingEvent; data: unknown }>) { switch (event.data.type) { @@ -92,7 +99,12 @@ break; } case "save_board": { - boardManager.openSaveModal(event.data.data as number[][], appliedCode as string); + const data = event.data.data as { board: number[][]; isColorful?: boolean }; + boardManager.openSaveModal(data.board, appliedCode, data.isColorful ?? false); + break; + } + case "colorful_status": { + isColorful = event.data.data as boolean; break; } default: { @@ -118,6 +130,7 @@ if (data) { editingCode = data.code; appliedCode = data.code; + isColorful = data.isColorful; sendEvent("apply_board", data.board); } } @@ -164,7 +177,11 @@
Life code
-