これはMisskey Advent Calendar 2020の3日目の記事です!!
概要
AiScriptでライフゲームを作ってpagesで走らせたらめちゃくちゃ重かった!
はじめに
僕はライフゲームが大好きで、小一時間はずっと眺めることができます。
ライフゲームとは、偉い数学者が考えた遊びで、票の格子を生物に見立てて、環境によってその格子が死んだり生まれたりするというようなゲームです
本物を見たい方はここを見てください
kawaii
それぞれの格子に隣接する生きている格子の数によって
-
誕生
死んでいるセルに隣接する生きたセルがちょうど3つあれば、次の世代が誕生する。 -
生存
生きているセルに隣接する生きたセルが2つか3つならば、次の世代でも生存する。 -
過疎
生きているセルに隣接する生きたセルが1つ以下ならば、過疎により死滅する。 -
過密
生きているセルに隣接する生きたセルが4つ以上ならば、過密により死滅する。
みたいなルールにのっとて世代が進んでいきます。
この記事は細かいこと知らなくても雰囲気で楽しめる記事となっておりますが、詳細が気になる人はwikipediaをご覧ください!
そこまで実装がむずかしくないためプログラムの入門なんかにも使われたりすることがあるらしいです。
なので今回は、AiScriptで実装してみることにしました!!
目次
ライフゲームについて
このライフゲーム、見ていて面白いだけではなく、これで論理上、時間はかかるものの一般的なプログラミング言語と同等の計算能力(チューリング完全性)を持っています!!(なので、これで時計とか電卓とか作ったりできます!)
さらに、マス目を移動して行ったり、増殖したりと、いろんな面白いパターンが作ることができて、その中でも僕がすきなものをいくつか紹介します!
パルサー
こいつは振動子と呼ばれるタイプのパターンで**一定の動きを繰り返します!**振動子の中でもパルサーはx軸,y軸対象のきれいな動きをするのでお気に入りです!
グライダー
ライフゲームといえばこいつというぐらい有名な移動物体です!こいつは見てわかる通りクネクネしながら移動して行きます。
ごちゃごちゃしたライフゲームの中でも移動していて目立つのですぐに見つけられると思います!
AiScriptで実装した
それでそれをpagesに移植したのがこちらです!
15x15マスの中でランダムに生きた格子が生成され、生き死にを繰り返します。
AiScriptはやっぱり癖が強くて、書くのが大変でした!スペース一つで構文エラーになるのでもうちょっと柔軟になったら使いやすいと思いました!
それで、この実装だとむちゃくちゃ重いです!
やりようによってはもっと軽くできるとは思うのですが、AiScriptに慣れてなかったので、できるだけコーディングで迷わないようにと気を使った結果この重さに!
こんな書き方もあるよ~など、知ってる方!ぜひ助言をお願いします!
一応コードも載せておきます!
ここまで見ていただきありがとうございました~!
#FIELD_WIDTH = 15
#FIELD_HEIGHT = 15
$field <- []
~ #column (FIELD_HEIGHT+2) {
~ #row (FIELD_WIDTH+2) {
? ((((row=1)|(column=1))|((row=(FIELD_HEIGHT+2))|(column=(FIELD_WIDTH+2))))=no) {
Arr:push(field Math:rnd(0 1))
} . {
Arr:push(field 0)
}
}
}
@isAlive(field index){
#count = (((field[((index-(FIELD_WIDTH+2))-1)]+field[(index-(FIELD_WIDTH+2))])+(field[((index-(FIELD_WIDTH+2))+1)]
+field[(index-1)]))+((field[(index+1)]
+field[((index+(FIELD_WIDTH+2))-1)])+(field[(index+(FIELD_WIDTH+2))]+field[((index+(FIELD_WIDTH+2))+1)])))
? ((field[index]=1)&(count=2)) {
<< 1
} .? (count=3) {
<< 1
} . {
<< 0
}
}
@do(field){
$_field <- []
~ ((FIELD_HEIGHT + 2) * (FIELD_WIDTH + 2)) {
Arr:push(_field 0)
}
~ #column (FIELD_HEIGHT+2) {
? (((column=1)|(column=(FIELD_HEIGHT+2)))=no) {
~ #row (FIELD_WIDTH+2) {
? (((row=1)|(row=(FIELD_WIDTH+2)))=no) {
_field[(((FIELD_WIDTH+2)*(column-1))+row)] <- isAlive(field (((FIELD_WIDTH+2)*(column-1))+row))
}
}
}
}
<< _field
}
@display(field){
$row_str <- ""
~ #column (FIELD_HEIGHT+2) {
~ #row (FIELD_WIDTH+2) {
? ((((row=1)|(column=1))|((row=(FIELD_HEIGHT+2))|(column=(FIELD_WIDTH+2))))=no) {
? (field[(((column-1)*(FIELD_HEIGHT+2))+row)]=1) {
row_str <- `{row_str} 0`
} . {
row_str <- `{row_str} .`
}
} . {
row_str <- `{row_str} *`
}
}
<: row_str
row_str <- ""
}
}
@start(){
Async:interval(50, @(){
field <- do(field)
<: ""
<: ""
display(field)
})
}
display(field)
start()