feat(board): python_pyodide板卡状态栏添加新tab 生命游戏

This commit is contained in:
王立帮
2025-10-14 10:58:32 +08:00
parent b7d76c763e
commit be97f0d712
6 changed files with 354 additions and 0 deletions

View File

@@ -15,6 +15,7 @@ import { KernelLoader } from '@basthon/kernel-loader';
import StatusBarImage from './statusbar-image';
import StatusBarFileSystem from './statusbar-filesystem';
import StatusBarTool from './statusbar-tool';
import StatusBarGame from './statusbar-game';
import TeachableMachineApp from './teachableMachine/App.vue';
import LOADER_TEMPLATE from '../templates/html/loader.html';
@@ -63,6 +64,7 @@ export default class PythonShell {
this.statusBarTool = StatusBarTool.init();
const teachableMachineApp = createApp(TeachableMachineApp);
teachableMachineApp.mount(this.statusBarTool.getContent()[0]);
this.statusBarGame = StatusBarGame.init();
this.pythonShell = new PythonShell();
this.pyodide = window.pyodide;
this.interruptBuffer = new Uint8Array(new ArrayBuffer(1));

View File

@@ -0,0 +1,227 @@
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() { }
}