227 lines
6.7 KiB
JavaScript
227 lines
6.7 KiB
JavaScript
import $ from 'jquery';
|
||
import { Msg } from 'blockly/core';
|
||
import {
|
||
PageBase,
|
||
HTMLTemplate,
|
||
StatusBarsManager,
|
||
Workspace
|
||
} from 'mixly';
|
||
import '../language/loader';
|
||
import STATUS_BAR_GAME_TEMPLATE from '../templates/html/statusbar-game.html';
|
||
|
||
|
||
export default class StatusBarGame extends PageBase {
|
||
static {
|
||
HTMLTemplate.add(
|
||
'html/statusbar/statusbar-game.html',
|
||
new HTMLTemplate(STATUS_BAR_GAME_TEMPLATE)
|
||
);
|
||
|
||
this.init = function () {
|
||
StatusBarsManager.typesRegistry.register(['game'], StatusBarGame);
|
||
const mainWorkspace = Workspace.getMain();
|
||
const statusBarsManager = mainWorkspace.getStatusBarsManager();
|
||
statusBarsManager.add({
|
||
type: 'game',
|
||
id: 'game',
|
||
name: Msg.PYTHON_PYODIDE_GAME,
|
||
title: Msg.PYTHON_PYODIDE_GAME
|
||
});
|
||
statusBarsManager.changeTo('output');
|
||
return statusBarsManager.get('game');
|
||
}
|
||
}
|
||
|
||
#$startBtn_ = null;
|
||
#$pauseBtn_ = null;
|
||
#$randomBtn_ = null;
|
||
#$resetBtn_ = null;
|
||
#$generation_ = null;
|
||
#$grid_ = null;
|
||
#GRID_SIZE_ = 10;
|
||
#SPEED_ = 500;
|
||
#grid_ = [];
|
||
#isRunning_ = false;
|
||
#generation_ = 0;
|
||
#intervalId_ = null;
|
||
|
||
constructor() {
|
||
super();
|
||
const $content = $(HTMLTemplate.get('html/statusbar/statusbar-game.html').render({
|
||
epoch: Msg.PYTHON_PYODIDE_GAME_EPOCH,
|
||
start: Msg.PYTHON_PYODIDE_GAME_START,
|
||
pause: Msg.PYTHON_PYODIDE_GAME_PAUSE,
|
||
random: Msg.PYTHON_PYODIDE_GAME_RANDOM,
|
||
reset: Msg.PYTHON_PYODIDE_GAME_RESET
|
||
}));
|
||
this.setContent($content);
|
||
this.#$startBtn_ = $content.find('.start-btn');
|
||
this.#$pauseBtn_ = $content.find('.pause-btn');
|
||
this.#$randomBtn_ = $content.find('.random-btn');
|
||
this.#$resetBtn_ = $content.find('.reset-btn');
|
||
this.#$generation_ = $content.find('.generation');
|
||
this.#$grid_ = $content.find('.grid');
|
||
this.#addEventListeners_();
|
||
}
|
||
|
||
#addEventListeners_() {
|
||
this.#$startBtn_.click(() => this.startGame());
|
||
this.#$pauseBtn_.click(() => this.pauseGame());
|
||
this.#$randomBtn_.click(() => this.randomInitialize());
|
||
this.#$resetBtn_.click(() => this.resetGame());
|
||
}
|
||
|
||
// 初始化网格
|
||
initializeGrid() {
|
||
this.#$grid_.empty();
|
||
this.#grid_ = [];
|
||
|
||
for (let i = 0; i < this.#GRID_SIZE_; i++) {
|
||
this.#grid_[i] = [];
|
||
for (let j = 0; j < this.#GRID_SIZE_; j++) {
|
||
this.#grid_[i][j] = 0; // 0表示死亡,1表示存活
|
||
|
||
const cell = document.createElement('div');
|
||
cell.className = 'cell';
|
||
cell.dataset.row = i;
|
||
cell.dataset.col = j;
|
||
|
||
cell.addEventListener('click', () => this.toggleCell(i, j));
|
||
|
||
this.#$grid_.append(cell);
|
||
}
|
||
}
|
||
this.updateGridDisplay();
|
||
}
|
||
|
||
// 切换细胞状态
|
||
toggleCell(row, col) {
|
||
if (!this.#isRunning_) {
|
||
this.#grid_[row][col] = this.#grid_[row][col] === 0 ? 1 : 0;
|
||
this.updateGridDisplay();
|
||
}
|
||
}
|
||
|
||
// 更新网格显示
|
||
updateGridDisplay() {
|
||
const $cells = this.#$grid_.children('.cell');
|
||
for (let i = 0; i < $cells.length; i++) {
|
||
const cell = $cells[i];
|
||
const row = parseInt(cell.dataset.row);
|
||
const col = parseInt(cell.dataset.col);
|
||
if (this.#grid_[row][col] === 1) {
|
||
cell.classList.add('alive');
|
||
} else {
|
||
cell.classList.remove('alive');
|
||
}
|
||
}
|
||
}
|
||
|
||
// 计算下一代
|
||
nextGeneration() {
|
||
const newGrid = [];
|
||
|
||
for (let i = 0; i < this.#GRID_SIZE_; i++) {
|
||
newGrid[i] = [];
|
||
for (let j = 0; j < this.#GRID_SIZE_; j++) {
|
||
const neighbors = this.countNeighbors(i, j);
|
||
|
||
if (this.#grid_[i][j] === 1) {
|
||
// 存活细胞:周围有2-3个存活细胞则继续存活
|
||
newGrid[i][j] = (neighbors === 2 || neighbors === 3) ? 1 : 0;
|
||
} else {
|
||
// 死亡细胞:周围有3个存活细胞则复活
|
||
newGrid[i][j] = neighbors === 3 ? 1 : 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
this.#grid_ = newGrid;
|
||
this.#generation_++;
|
||
this.#$generation_.text(this.#generation_);
|
||
this.updateGridDisplay();
|
||
}
|
||
|
||
// 计算周围存活细胞数量
|
||
countNeighbors(row, col) {
|
||
let count = 0;
|
||
for (let i = -1; i <= 1; i++) {
|
||
for (let j = -1; j <= 1; j++) {
|
||
if (i === 0 && j === 0) continue; // 跳过自身
|
||
|
||
const newRow = row + i;
|
||
const newCol = col + j;
|
||
|
||
// 检查边界
|
||
if (newRow >= 0 && newRow < this.#GRID_SIZE_ && newCol >= 0 && newCol < this.#GRID_SIZE_) {
|
||
count += this.#grid_[newRow][newCol];
|
||
}
|
||
}
|
||
}
|
||
return count;
|
||
}
|
||
|
||
// 开始游戏
|
||
startGame() {
|
||
if (!this.#isRunning_) {
|
||
this.#isRunning_ = true;
|
||
this.#generation_ = 0;
|
||
this.#$generation_.text(this.#generation_);
|
||
this.#intervalId_ = setInterval(() => this.nextGeneration(), this.#SPEED_);
|
||
this.updateButtons();
|
||
}
|
||
}
|
||
|
||
// 暂停游戏
|
||
pauseGame() {
|
||
if (this.#isRunning_) {
|
||
this.#isRunning_ = false;
|
||
clearInterval(this.#intervalId_);
|
||
this.updateButtons();
|
||
}
|
||
}
|
||
|
||
// 随机初始化网格
|
||
randomInitialize() {
|
||
if (!this.#isRunning_) {
|
||
for (let i = 0; i < this.#GRID_SIZE_; i++) {
|
||
for (let j = 0; j < this.#GRID_SIZE_; j++) {
|
||
// 25%的概率生成存活细胞
|
||
this.#grid_[i][j] = Math.random() < 0.25 ? 1 : 0;
|
||
}
|
||
}
|
||
this.updateGridDisplay();
|
||
}
|
||
}
|
||
|
||
// 重置游戏
|
||
resetGame() {
|
||
this.#isRunning_ = false;
|
||
clearInterval(this.#intervalId_);
|
||
this.#generation_ = 0;
|
||
this.#$generation_.text(this.#generation_);
|
||
this.initializeGrid();
|
||
this.updateButtons();
|
||
}
|
||
|
||
// 更新按钮状态
|
||
updateButtons() {
|
||
this.#$startBtn_.attr('disabled', this.#isRunning_);
|
||
this.#$pauseBtn_.attr('disabled', !this.#isRunning_);
|
||
this.#$randomBtn_.attr('disabled', this.#isRunning_);
|
||
this.#$resetBtn_.attr('disabled', false);
|
||
}
|
||
|
||
init() {
|
||
super.init();
|
||
this.hideCloseBtn();
|
||
this.initializeGrid();
|
||
this.updateButtons();
|
||
}
|
||
|
||
onMounted() { }
|
||
|
||
onUnmounted() { }
|
||
|
||
resize() { }
|
||
} |