From 8b8a59827c8a885492aa801e4b8d286e1ccdb08d Mon Sep 17 00:00:00 2001 From: TKHR-Shiu Date: Thu, 13 Nov 2025 17:54:58 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=E3=83=86=E3=83=B3=E3=83=97=E3=83=AC?= =?UTF-8?q?=E3=83=BC=E3=83=88=E3=81=AE=E8=87=AA=E7=94=B1=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/iframe/life-game.js | 83 +++++++++++++++++++++++++++++++++++++---- src/routes/+page.svelte | 28 +++++--------- 2 files changed, 86 insertions(+), 25 deletions(-) diff --git a/src/iframe/life-game.js b/src/iframe/life-game.js index 8ce2604..c01d11e 100644 --- a/src/iframe/life-game.js +++ b/src/iframe/life-game.js @@ -6,6 +6,11 @@ let generationFigure = 0; let timerTime = 1000; let isDragging = false; let dragMode = false; // true: 黒にする, false: 白にする +let isTemplate = false; +let patternShape = []; +let patternHeight = 0; +let patternWidth = 0; +let previewCells = []; const DEFAULT_BOARD_SIZE = 20; const DEFAULT_CELL_SIZE = 30; @@ -46,9 +51,38 @@ function renderBoard() { button.style.height = `${cellSize}px`; button.style.padding = "0"; //cellSizeが小さいとき、セルが横長になることを防ぐ button.style.display = "block"; //cellSizeが小さいとき、行間が空きすぎるのを防ぐ + button.onclick = () => { + if (isTemplate) { + clearPreview(); + isTemplate = 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; + if (patternShape[r][c] === 1) { + board[boardRow][boardCol] = true; + } + } + } + renderBoard(); + generationChange(0); + resetTimer(); + stop(); + } else { + window.parent.postMessage( + { + type: "Size shortage", + data: {}, + }, + "*", + ); + } + } + }; button.onmousedown = (e) => { e.preventDefault(); - if (timer === "stop") { + if (timer === "stop" && !isTemplate) { isDragging = true; board[i][j] = !board[i][j]; dragMode = board[i][j]; @@ -56,10 +90,13 @@ function renderBoard() { } }; button.onmouseenter = () => { - if (isDragging && timer === "stop" && board[i][j] !== dragMode) { + if (isDragging && timer === "stop" && board[i][j] !== dragMode && !isTemplate) { board[i][j] = dragMode; button.style.backgroundColor = board[i][j] ? "black" : "white"; } + if (isTemplate) { + drawPreview(i, j); + } }; td.appendChild(button); tr.appendChild(td); @@ -68,6 +105,37 @@ function renderBoard() { } } +table.onmouseleave = () => { + if (isTemplate) { + 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 = board[cellPos.row][cellPos.col] ? "black" : "white"; + }); + previewCells = []; +} + document.addEventListener("mouseup", () => { isDragging = false; }); @@ -196,11 +264,12 @@ on.request_sync = () => { console.log("generationFigure:", generationFigure, "boardSize:", boardSize); }; -on.place_template = (newBoard) => { - board = newBoard; - renderBoard(); - generationChange(0); - resetTimer(); +on.place_template = (template) => { + patternShape = template; + patternHeight = patternShape.length; + patternWidth = patternShape[0].length; + isTemplate = true; + table.style.cursor = "crosshair"; stop(); }; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index f2ec61f..0cd28f2 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -46,7 +46,7 @@ // unused events | "board_resize"; - type IncomingEvent = "generation_change" | "sync" | "save_board"; + type IncomingEvent = "generation_change" | "sync" | "Size shortage" | "save_board"; function handleMessage(event: MessageEvent<{ type: IncomingEvent; data: unknown }>) { switch (event.data.type) { @@ -60,6 +60,14 @@ sizeValue = data.boardSize; break; } + case "Size shortage": { + alert( + isJapanese + ? "盤面からはみ出してしまうため、キャンセルしました" + : "This action was canceled because it would have extended beyond the board.", + ); + break; + } case "save_board": { saveState = { saving: true, boardData: event.data.data as boolean[][], boardName: "" }; break; @@ -164,13 +172,8 @@ onclick={() => { sendEvent("request_sync"); - const newBoard = Array.from({ length: sizeValue }, () => - Array.from({ length: sizeValue }, () => false), - ); const patternData = patterns[patternName]; const patternShape = patternData.shape; - const patternHeight = patternShape.length; - const patternWidth = patternShape[0].length; if (sizeValue < (patternData.minBoardSize || 0)) { if (isJapanese) { @@ -185,19 +188,8 @@ return; } - // パターンがボードの中央に来るよう、パターンの左上のセルの位置(startRow, startCol)を調整 - const startRow = Math.floor((sizeValue - patternHeight) / 2); - const startCol = Math.floor((sizeValue - patternWidth) / 2); - - for (let r = 0; r < patternHeight; r++) { - for (let c = 0; c < patternWidth; c++) { - const boardRow = startRow + r; - const boardCol = startCol + c; - newBoard[boardRow][boardCol] = patternShape[r][c] === 1; - } - } bottomDrawerOpen = false; - sendEvent("place_template", newBoard); + sendEvent("place_template", patternShape); }} > Date: Thu, 13 Nov 2025 21:49:25 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E5=A4=89=E6=95=B0=E5=90=8D=E5=A4=89?= =?UTF-8?q?=E6=9B=B4=E3=81=AA=E3=81=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/iframe/life-game.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/iframe/life-game.js b/src/iframe/life-game.js index c01d11e..c324141 100644 --- a/src/iframe/life-game.js +++ b/src/iframe/life-game.js @@ -6,7 +6,7 @@ let generationFigure = 0; let timerTime = 1000; let isDragging = false; let dragMode = false; // true: 黒にする, false: 白にする -let isTemplate = false; +let isPlacingTemplate = false; let patternShape = []; let patternHeight = 0; let patternWidth = 0; @@ -52,17 +52,15 @@ function renderBoard() { button.style.padding = "0"; //cellSizeが小さいとき、セルが横長になることを防ぐ button.style.display = "block"; //cellSizeが小さいとき、行間が空きすぎるのを防ぐ button.onclick = () => { - if (isTemplate) { + if (isPlacingTemplate) { clearPreview(); - isTemplate = false; + 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; - if (patternShape[r][c] === 1) { - board[boardRow][boardCol] = true; - } + board[boardRow][boardCol] = patternShape[r][c] === 1; } } renderBoard(); @@ -82,7 +80,7 @@ function renderBoard() { }; button.onmousedown = (e) => { e.preventDefault(); - if (timer === "stop" && !isTemplate) { + if (timer === "stop" && !isPlacingTemplate) { isDragging = true; board[i][j] = !board[i][j]; dragMode = board[i][j]; @@ -90,11 +88,11 @@ function renderBoard() { } }; button.onmouseenter = () => { - if (isDragging && timer === "stop" && board[i][j] !== dragMode && !isTemplate) { + if (isDragging && timer === "stop" && board[i][j] !== dragMode && !isPlacingTemplate) { board[i][j] = dragMode; button.style.backgroundColor = board[i][j] ? "black" : "white"; } - if (isTemplate) { + if (isPlacingTemplate) { drawPreview(i, j); } }; @@ -106,7 +104,7 @@ function renderBoard() { } table.onmouseleave = () => { - if (isTemplate) { + if (isPlacingTemplate) { clearPreview(); } }; @@ -268,7 +266,7 @@ on.place_template = (template) => { patternShape = template; patternHeight = patternShape.length; patternWidth = patternShape[0].length; - isTemplate = true; + isPlacingTemplate = true; table.style.cursor = "crosshair"; stop(); }; From 3c8048f14528fb088b7f2db84e8ea7eb38eac776 Mon Sep 17 00:00:00 2001 From: TKHR-Shiu Date: Thu, 13 Nov 2025 22:07:51 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=E3=82=B3=E3=83=B3=E3=83=95=E3=83=AA?= =?UTF-8?q?=E3=82=AF=E3=83=88=E3=81=AE=E8=A7=A3=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/iframe/life-game.js | 55 ++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/src/iframe/life-game.js b/src/iframe/life-game.js index c324141..ef47d94 100644 --- a/src/iframe/life-game.js +++ b/src/iframe/life-game.js @@ -12,12 +12,9 @@ let patternHeight = 0; let patternWidth = 0; let previewCells = []; -const DEFAULT_BOARD_SIZE = 20; -const DEFAULT_CELL_SIZE = 30; - //変数設定 -let boardSize = 20; -let cellSize = 30; +let boardSize = 20; //盤面の大きさ(20x20) +const cellSize = 600 / boardSize; //セルの大きさ(px) // around: 周囲の生きたセル数 self: 自身が生きているかどうか function isNextAlive(around, self) { @@ -32,11 +29,19 @@ function isNextAlive(around, self) { return false; } +// cellの状態に応じた色を返す関数 +function getStyle(cell) { + // cellがtrueなら黒、falseなら白を返す + return cell ? "black" : "white"; +} + //Boardの初期化 let board = Array.from({ length: boardSize }, () => Array.from({ length: boardSize }, () => false)); const table = document.getElementById("game-board"); + +//盤面をBoardに従って変更する関数達(Boardを変更したら実行する) function renderBoard() { - //盤面をBoardに従って変更する関数(Boardを変更したら必ず実行する) + // 初回の盤面生成 table.innerHTML = ""; for (let i = 0; i < boardSize; i++) { const tr = document.createElement("tr"); @@ -63,7 +68,7 @@ function renderBoard() { board[boardRow][boardCol] = patternShape[r][c] === 1; } } - renderBoard(); + rerender(); generationChange(0); resetTimer(); stop(); @@ -134,6 +139,30 @@ function clearPreview() { 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; }); @@ -192,7 +221,7 @@ function progressBoard() { } board = newBoard; generationChange(generationFigure + 1); - renderBoard(); + rerender(); } function resetTimer() { @@ -213,15 +242,6 @@ on.pause = () => { resetTimer(); }; -on.board_resize = (newSize) => { - boardSize = newSize; - cellSize = Math.floor(DEFAULT_CELL_SIZE * (DEFAULT_BOARD_SIZE / newSize)); - board = Array.from({ length: boardSize }, () => Array.from({ length: boardSize }, () => false)); - renderBoard(); - generationChange(0); - resetTimer(); -}; - on.board_reset = () => { //すべて白にBoardを変更 board = Array.from({ length: boardSize }, () => Array.from({ length: boardSize }, () => false)); @@ -276,6 +296,7 @@ on.save_board = async () => { }; on.apply_board = (newBoard) => { + boardSize = newBoard.length; board = newBoard; renderBoard(); generationChange(0);