ゼロからはじめるPython 第126回 ブラウザで動くPython「PyScript」でライフゲームを作ってみよう

2025年4月9日(水)15時57分 マイナビニュース


PyScriptを使うと、ブラウザ上で手軽にPythonを実行できる。JavaScriptを使わなくても、大抵のことがPythonだけで実現できる。図形の描画ができるのでゲームも開発できる。ライフゲームを実装してみて、使い方を確認してみよう。
○PyScriptとは何だろう?
PyScriptとは、Pythonをブラウザ上で直接実行できるようにしたフレームワークだ。HTMLにと記述するだけで、Pythonをブラウザで動かすことができる。
本連載の110回目(https://news.mynavi.jp/techplus/article/zeropython-110/)でも、簡単にPyScriptについて紹介したが、その後も順調にバージョンアップを重ねている。仕組み的には、PythonをWebAssemblyとして実行する「Pyodide」をベースにして開発されている。そのため、初回実行時にはPythonランタイム(WebAssembly)の読み込みに少し時間がかかる。
PyScriptについての詳しいドキュメント(英語)は、こちら(https://docs.pyscript.net/2025.3.1/)から確認できる。
○PyScriptでライフゲームを作ろう
ライフゲームとは、二次元のグリッドで生物(セル)の生死を表現するものだ。本連載の9回目(https://news.mynavi.jp/techplus/article/zeropython-9/)でも紹介したが、その時は、Tkinterを利用したため、プログラムを実行するには、ローカルPCにPythonをインストールする必要があった。PyScriptを使って作り直すことで、ブラウザ上で使えるようになる。
ライフゲームと名前が付いているものの、基本的にプレイヤーは操作することなく、セルの生死を観察するシミュレーションだ。詳しいルールは以前の連載を確認してみて欲しい。
簡単に紹介すると、「生物は過疎でも過密でも生きてはいけない」という基本的なルールに基づいたシミュレーションを行う。具体的には、生物の周囲(8方向)を調べて、何匹の生きたセルがあるかによって、次の世代の生死が決定する。
- 生きているセルが3つ → 次世代に生物が誕生
- 生きているセルが2つか3つ → 次の世代に生物は継続して生存
- 生きているセルが1つ以下(過疎状態) → 次の世代に死滅
- 生きているセルが4つ以上(過密状態) → 次の世代に死滅
○PyScriptのプログラムを作ってみよう
今回、PyScriptを用いてライフゲームを作ると100行ほどになった。100行と言えど、ちょっと長いので、パーツごとに分けて紹介しよう。
プログラム全体をこちらのGist(https://gist.github.com/kujirahand/3f1acb7d148f4f9b4ac998f92b048a79)にアップロードした。全体を確認する場合はそちらで確認して欲しい。
プログラムを実行するには、まず、Gistからソースコードをコピーしてテキストエディタなどに貼り付けて、「lifegame.html」というファイル名で保存しよう。そして、このファイルをブラウザにドラッグ&ドロップしよう。「開始する」ボタンを押すと、ライフゲームが始まる。
○PyScriptフレームワークの読み込み
それでは、少しずつプログラムを確認してみよう。
PyScriptでは、HTMLの中にPythonのプログラムを記述する。それで、PyScriptのバージョン「2025.3.1」を利用する場合には、次のようなHTMLを記述する。これは、PyScriptのマニュアルに載っているひな形(https://docs.pyscript.net/2025.3.1/beginning-pyscript/)を微修正したものだ。
なお、 の内側にPythonのプログラムを書くことになっている。
○ライフゲームを描画するキャンバスや開始ボタンなどを用意
HTMLでライフゲームのような描画が必要なアプリケーションを作るには、HTMLにタグを用意する必要がある。そこで、…の間にを挿入して「game」というidを割り振ろう。また、ライフゲームを開始するボタンと初期化するボタンを用意し、それぞれに、「start-btn」と「reset-btn」というidを割り振ろう。
ライフゲーム
▶️ 開始する
🔄 初期化
○Pythonのプログラムで描画を行うには?
PyScriptのプログラムで、キャンバスに描画するためには、まず、下記の(*1)でjsパッケージのdocumentオブジェクトを利用する宣言を記述する。続いて、(*2)でdocument.getElementByIdメソッドを利用して、HTMLでid属性を割り振ったオブジェクトを取得する。ここでは、gameというidを割り振ったキャンバスオブジェクトを取得する。なお、キャンバスに描画するためには、getContext("2d")というメソッドを呼び出し、描画用のコンテキストを取得する必要がある。
○キャンバスに生物を描画しよう
次に、セルの初期化とグリッドを描画する処理を確認してみよう。以下の(*3)の部分では二次元リストのグリッドを初期化する。グリッドの値が1のとき生物がいる、0のとき生物がいないという状態を表す。(*4)の関数draw_gridでは、上記(*2)で取得した描画用のコンテキストを利用して、実際にキャンバスを描画する。ctx.clearRectメソッドで、画面を初期化する。(*5)以下の部分で生物を描画する。円を特定の色で描画するには、このように、beginPathメソッドを呼び出し、arcメソッドで描画し、fillメソッドで塗りつぶし、closePathメソッドでパスを閉じるという手順を踏む。
# グリッドを初期化 --- (*3)
def create_grid():
global grid
grid = [[random.choice([0, 0, 1]) for _ in range(cols)] for _ in range(rows)]
# グリッドを描画する --- (*4)
def draw_grid():
ctx.clearRect(0, 0, canvas.width, canvas.height)
for y in range(rows):
for x in range(cols):
# 値が1の時生物を描画する ---- (*5)
if grid[y][x] == 1:
ctx.beginPath()
ctx.arc(
x * cell_size + cell_size / 2,
y * cell_size + cell_size / 2,
cell_size / 2,
0,
2 * math.pi
)
ctx.fillStyle = "red"
ctx.fill()
ctx.closePath()
○ライフゲームの世代を進める
次に、ライフゲームで世代を進める処理(*6)を確認しよう。以下の処理は、二次元リストの変数gridを更新する処理だ。左上から右下に向かって、セルを一つずつ確認して、次世代の生物の状態を変更する。
# グリッドの世代を進める --- (*6)
def update_grid():
global grid
new_grid = [[0 for _ in range(cols)] for _ in range(rows)]
for y in range(rows):
for x in range(cols):
neighbors = sum(
grid[(y + dy) % rows][(x + dx) % cols]
for dy in [-1, 0, 1]
for dx in [-1, 0, 1]
if not (dy == 0 and dx == 0)
)
if grid[y][x] == 1 and neighbors in [2, 3]:
new_grid[y][x] = 1
elif grid[y][x] == 0 and neighbors == 3:
new_grid[y][x] = 1
grid = new_grid
draw_grid()
.

マイナビニュース

「ブラウザ」をもっと詳しく

「ブラウザ」のニュース

「ブラウザ」のニュース

トピックス

x
BIGLOBE
トップへ