Skip to content

Commit 1f84b1e

Browse files
authored
Merge pull request #30 from ut-code/Free-template
テンプレートの自由配置/Timer改善
2 parents da0b9d4 + 6a062f4 commit 1f84b1e

2 files changed

Lines changed: 115 additions & 55 deletions

File tree

src/iframe/life-game.js

Lines changed: 78 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
"use strict";
22

33
let timer = "stop";
4-
let timerId = 0;
54
let generationFigure = 0;
6-
let timerTime = 1000;
75
let isDragging = false;
86
let dragMode = false; // true: 黒にする, false: 白にする
7+
let isPlacingTemplate = false;
8+
let patternShape = [];
9+
let patternHeight = 0;
10+
let patternWidth = 0;
11+
let previewCells = [];
912

1013
//変数設定
1114
let boardSize = 20; //盤面の大きさ(20x20)
@@ -51,20 +54,49 @@ function renderBoard() {
5154
button.style.height = `${cellSize}px`;
5255
button.style.padding = "0"; //cellSizeが小さいとき、セルが横長になることを防ぐ
5356
button.style.display = "block"; //cellSizeが小さいとき、行間が空きすぎるのを防ぐ
57+
button.onclick = () => {
58+
if (isPlacingTemplate) {
59+
clearPreview();
60+
isPlacingTemplate = false;
61+
if (i + patternHeight < boardSize + 1 && j + patternWidth < boardSize + 1) {
62+
for (let r = 0; r < patternHeight; r++) {
63+
for (let c = 0; c < patternWidth; c++) {
64+
const boardRow = i + r;
65+
const boardCol = j + c;
66+
board[boardRow][boardCol] = patternShape[r][c] === 1;
67+
}
68+
}
69+
rerender();
70+
generationChange(0);
71+
stop();
72+
} else {
73+
window.parent.postMessage(
74+
{
75+
type: "Size shortage",
76+
data: {},
77+
},
78+
"*",
79+
);
80+
}
81+
}
82+
};
5483
button.onmousedown = (e) => {
5584
e.preventDefault();
56-
if (timer === "stop") {
85+
if (timer === "stop" && !isPlacingTemplate) {
5786
isDragging = true;
5887
board[i][j] = !board[i][j];
5988
dragMode = board[i][j];
6089
button.style.backgroundColor = board[i][j] ? "black" : "white";
6190
}
6291
};
6392
button.onmouseenter = () => {
64-
if (isDragging && timer === "stop" && board[i][j] !== dragMode) {
93+
if (isDragging && timer === "stop" && board[i][j] !== dragMode && !isPlacingTemplate) {
6594
board[i][j] = dragMode;
6695
button.style.backgroundColor = board[i][j] ? "black" : "white";
6796
}
97+
if (isPlacingTemplate) {
98+
drawPreview(i, j);
99+
}
68100
};
69101
td.appendChild(button);
70102
tr.appendChild(td);
@@ -73,6 +105,37 @@ function renderBoard() {
73105
}
74106
}
75107

108+
table.onmouseleave = () => {
109+
if (isPlacingTemplate) {
110+
clearPreview();
111+
}
112+
};
113+
114+
function drawPreview(row, col) {
115+
clearPreview();
116+
for (let r = 0; r < patternHeight; r++) {
117+
for (let c = 0; c < patternWidth; c++) {
118+
if (patternShape[r][c] === 1) {
119+
const boardRow = row + r;
120+
const boardCol = col + c;
121+
if (boardRow < boardSize && boardCol < boardSize) {
122+
const cell = table.rows[boardRow].cells[boardCol].firstChild;
123+
cell.style.backgroundColor = "gray";
124+
previewCells.push({ row: boardRow, col: boardCol });
125+
}
126+
}
127+
}
128+
}
129+
}
130+
131+
function clearPreview() {
132+
previewCells.forEach((cellPos) => {
133+
const cell = table.rows[cellPos.row].cells[cellPos.col].firstChild;
134+
cell.style.backgroundColor = board[cellPos.row][cellPos.col] ? "black" : "white";
135+
});
136+
previewCells = [];
137+
}
138+
76139
function rerender() {
77140
// 2回目以降の盤面生成
78141
for (let i = 0; i < boardSize; i++) {
@@ -158,30 +221,25 @@ function progressBoard() {
158221
rerender();
159222
}
160223

161-
function resetTimer() {
162-
if (timer !== "stop") {
163-
timer = "stop";
164-
clearInterval(timerId);
165-
}
166-
}
167-
168224
//イベント
169225

226+
on.progress = () => {
227+
progressBoard();
228+
};
229+
170230
on.play = () => {
171231
timer = "start";
172-
timerId = setInterval(progressBoard, timerTime);
173232
};
174233

175234
on.pause = () => {
176-
resetTimer();
235+
timer = "stop";
177236
};
178237

179238
on.board_reset = () => {
180239
//すべて白にBoardを変更
181240
board = Array.from({ length: boardSize }, () => Array.from({ length: boardSize }, () => false));
182241
renderBoard();
183242
generationChange(0);
184-
resetTimer();
185243
};
186244

187245
on.board_randomize = () => {
@@ -191,15 +249,6 @@ on.board_randomize = () => {
191249
);
192250
renderBoard();
193251
generationChange(0);
194-
resetTimer();
195-
};
196-
197-
on.timer_change = (ms) => {
198-
timerTime = ms;
199-
if (timer === "start") {
200-
clearInterval(timerId);
201-
timerId = setInterval(progressBoard, timerTime);
202-
}
203252
};
204253

205254
on.request_sync = () => {
@@ -216,11 +265,12 @@ on.request_sync = () => {
216265
console.log("generationFigure:", generationFigure, "boardSize:", boardSize);
217266
};
218267

219-
on.place_template = (newBoard) => {
220-
board = newBoard;
221-
renderBoard();
222-
generationChange(0);
223-
resetTimer();
268+
on.place_template = (template) => {
269+
patternShape = template;
270+
patternHeight = patternShape.length;
271+
patternWidth = patternShape[0].length;
272+
isPlacingTemplate = true;
273+
table.style.cursor = "crosshair";
224274
stop();
225275
};
226276

@@ -233,6 +283,5 @@ on.apply_board = (newBoard) => {
233283
board = newBoard;
234284
renderBoard();
235285
generationChange(0);
236-
resetTimer();
237286
stop();
238287
};

src/routes/+page.svelte

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,19 @@
2020
let resetModalOpen = $state(false);
2121
let bottomDrawerOpen = $state(false);
2222
23-
let intervalMs = $state(1000);
2423
let generationFigure = $state(0);
2524
let sizeValue = $state(20);
2625
26+
let timer: "running" | "stopped" = $state("stopped");
27+
let intervalMs = $state(1000);
28+
$effect(() => {
29+
if (timer === "stopped") return;
30+
const timerId = setInterval(() => {
31+
sendEvent("progress");
32+
}, intervalMs);
33+
return () => clearInterval(timerId);
34+
});
35+
2736
type SaveState =
2837
| { saving: false }
2938
| { saving: true; boardData: boolean[][]; boardName: string; boardPreview: boolean[][] };
@@ -39,15 +48,15 @@
3948
| "play"
4049
| "pause"
4150
| "state_update"
42-
| "timer_change"
4351
| "board_reset"
4452
| "board_randomize"
4553
| "place_template"
4654
| "save_board"
4755
| "apply_board"
48-
| "request_sync";
56+
| "request_sync"
57+
| "progress";
4958
50-
type IncomingEvent = "generation_change" | "sync" | "save_board";
59+
type IncomingEvent = "generation_change" | "sync" | "Size shortage" | "save_board";
5160
5261
function handleMessage(event: MessageEvent<{ type: IncomingEvent; data: unknown }>) {
5362
switch (event.data.type) {
@@ -61,6 +70,14 @@
6170
sizeValue = data.boardSize;
6271
break;
6372
}
73+
case "Size shortage": {
74+
alert(
75+
isJapanese
76+
? "盤面からはみ出してしまうため、キャンセルしました"
77+
: "This action was canceled because it would have extended beyond the board.",
78+
);
79+
break;
80+
}
6481
case "save_board": {
6582
const board = event.data.data as boolean[][];
6683
const preview = createPreview(board);
@@ -168,13 +185,8 @@
168185
onclick={() => {
169186
sendEvent("request_sync");
170187

171-
const newBoard = Array.from({ length: sizeValue }, () =>
172-
Array.from({ length: sizeValue }, () => false),
173-
);
174188
const patternData = patterns[patternName];
175189
const patternShape = patternData.shape;
176-
const patternHeight = patternShape.length;
177-
const patternWidth = patternShape[0].length;
178190

179191
if (sizeValue < (patternData.minBoardSize || 0)) {
180192
if (isJapanese) {
@@ -189,19 +201,8 @@
189201

190202
return;
191203
}
192-
// パターンがボードの中央に来るよう、パターンの左上のセルの位置(startRow, startCol)を調整
193-
const startRow = Math.floor((sizeValue - patternHeight) / 2);
194-
const startCol = Math.floor((sizeValue - patternWidth) / 2);
195-
196-
for (let r = 0; r < patternHeight; r++) {
197-
for (let c = 0; c < patternWidth; c++) {
198-
const boardRow = startRow + r;
199-
const boardCol = startCol + c;
200-
newBoard[boardRow][boardCol] = patternShape[r][c] === 1;
201-
}
202-
}
203204
bottomDrawerOpen = false;
204-
sendEvent("place_template", newBoard);
205+
sendEvent("place_template", patternShape);
205206
}}
206207
>
207208
<img
@@ -415,7 +416,6 @@
415416
class="btn btn-ghost btn-circle hover:bg-[rgb(220,220,220)]"
416417
onclick={() => {
417418
intervalMs = intervalMs * 2;
418-
sendEvent("timer_change", intervalMs);
419419
}}
420420
>
421421
<img class="size-6" src={icons.decelerate} alt="decelerate" />
@@ -425,7 +425,6 @@
425425
class="btn btn-ghost btn-circle text-black hover:bg-[rgb(220,220,220)]"
426426
onclick={() => {
427427
intervalMs = 1000;
428-
sendEvent("timer_change", intervalMs);
429428
}}
430429
>
431430
x1
@@ -435,7 +434,6 @@
435434
class="btn btn-ghost btn-circle hover:bg-[rgb(220,220,220)]"
436435
onclick={() => {
437436
intervalMs = intervalMs / 2;
438-
sendEvent("timer_change", intervalMs);
439437
}}
440438
>
441439
<img class="size-6" src={icons.accelerate} alt="accelerate" />
@@ -455,8 +453,13 @@
455453
<button
456454
class="btn btn-ghost btn-circle hover:bg-[rgb(220,220,220)] swap"
457455
onclick={() => {
458-
const eventName = isProgress ? "pause" : "play";
459-
sendEvent(eventName);
456+
if (isProgress) {
457+
timer = "stopped";
458+
sendEvent("pause");
459+
} else {
460+
timer = "running";
461+
sendEvent("play");
462+
}
460463
isProgress = !isProgress;
461464
}}
462465
>
@@ -477,6 +480,7 @@
477480
class="btn btn-ghost hover:bg-[rgb(220,220,220)] text-black"
478481
onclick={() => {
479482
isProgress = false;
483+
timer = "stopped";
480484
sendEvent("pause");
481485
sendEvent("save_board");
482486
}}
@@ -488,6 +492,7 @@
488492
class="btn btn-ghost hover:bg-[rgb(220,220,220)] text-black"
489493
onclick={() => {
490494
isProgress = false;
495+
timer = "stopped";
491496
sendEvent("pause");
492497
handleLoad();
493498
}}
@@ -499,6 +504,8 @@
499504
class="btn btn-ghost hover:bg-[rgb(220,220,220)] text-black"
500505
onclick={() => {
501506
isProgress = false;
507+
timer = "stopped";
508+
sendEvent("pause");
502509
sendEvent("board_reset");
503510
}}
504511
>
@@ -509,6 +516,8 @@
509516
class="btn btn-ghost hover:bg-[rgb(220,220,220)] text-black"
510517
onclick={() => {
511518
isProgress = false;
519+
timer = "stopped";
520+
sendEvent("pause");
512521
sendEvent("board_randomize");
513522
}}
514523
>
@@ -522,6 +531,8 @@
522531
class="btn btn-ghost hover:bg-[rgb(220,220,220)] text-black"
523532
onclick={() => {
524533
appliedCode = editingCode;
534+
isProgress = false;
535+
timer = "stopped";
525536
}}
526537
>
527538
{isJapanese ? "コードを適用" : "Apply Code"}

0 commit comments

Comments
 (0)