Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 111 additions & 23 deletions src/iframe/life-game.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ let generationFigure = 0;
let timerTime = 1000;
let isDragging = false;
let dragMode = false; // true: 黒にする, false: 白にする

const DEFAULT_BOARD_SIZE = 20;
const DEFAULT_CELL_SIZE = 30;
let isPlacingTemplate = false;
let patternShape = [];
let patternHeight = 0;
let patternWidth = 0;
let previewCells = [];

//変数設定
let boardSize = 20;
let cellSize = 30;
let boardSize = 20; //盤面の大きさ(20x20)
const cellSize = 600 / boardSize; //セルの大きさ(px)

// around: 周囲の生きたセル数 self: 自身が生きているかどうか
function isNextAlive(around, self) {
Expand All @@ -27,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");
Expand All @@ -46,20 +56,50 @@ function renderBoard() {
button.style.height = `${cellSize}px`;
button.style.padding = "0"; //cellSizeが小さいとき、セルが横長になることを防ぐ
button.style.display = "block"; //cellSizeが小さいとき、行間が空きすぎるのを防ぐ
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] === 1;
}
}
rerender();
generationChange(0);
resetTimer();
stop();
} else {
window.parent.postMessage(
{
type: "Size shortage",
data: {},
},
"*",
);
}
}
};
button.onmousedown = (e) => {
e.preventDefault();
if (timer === "stop") {
if (timer === "stop" && !isPlacingTemplate) {
isDragging = true;
board[i][j] = !board[i][j];
dragMode = board[i][j];
button.style.backgroundColor = board[i][j] ? "black" : "white";
}
};
button.onmouseenter = () => {
if (isDragging && timer === "stop" && board[i][j] !== dragMode) {
if (isDragging && timer === "stop" && board[i][j] !== dragMode && !isPlacingTemplate) {
board[i][j] = dragMode;
button.style.backgroundColor = board[i][j] ? "black" : "white";
}
if (isPlacingTemplate) {
drawPreview(i, j);
}
};
td.appendChild(button);
tr.appendChild(td);
Expand All @@ -68,6 +108,61 @@ function renderBoard() {
}
}

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 = board[cellPos.row][cellPos.col] ? "black" : "white";
});
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;
});
Expand Down Expand Up @@ -126,7 +221,7 @@ function progressBoard() {
}
board = newBoard;
generationChange(generationFigure + 1);
renderBoard();
rerender();
}

function resetTimer() {
Expand All @@ -147,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));
Expand Down Expand Up @@ -196,11 +282,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;
isPlacingTemplate = true;
table.style.cursor = "crosshair";
stop();
};

Expand All @@ -209,6 +296,7 @@ on.save_board = async () => {
};

on.apply_board = (newBoard) => {
boardSize = newBoard.length;
board = newBoard;
renderBoard();
generationChange(0);
Expand Down
28 changes: 10 additions & 18 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}}
>
<img
Expand Down