FreeBASIC マニュアルのトップに戻る

FreeBASIC コンウェイのライフゲーム

目次→フォーラム→FreeBASIC→補足Conways Game Of Life←オリジナル・サイト

コンウェイのライフゲーム 左にメニュー・フレームが表示されていない場合は、ここをクリックして下さい

←リンク元に戻る プログラム開発関連に戻る

ここでは Klaus Brock さんが FreeBASIC-Portal.de に投稿された「コンウェイのライフゲーム」を翻訳して紹介します。
マニュアル Conways Game of Life - Manual.pdf と、 プログラム Conways_GameOfLife.bas が翻訳対象です。
Conway_Scenes-Screensaver.bas は未翻訳です。

はじめに

「ライフゲーム」は、1970年に数学者ジョン・ホートン・コンウェイによって考案された、セル式2次元オートマトンのシステムです。

このプログラムは、ゲームオタクの人や、没入ゲームが好きな人には向かないでしょう......。
しかし、初歩的でシンプルなルールから生み出される現象を楽しむのであれば、これは間違いなく興味深いものです。
生物集団では、過疎でも過密でも個体の生存に適さない、という個体群生態学的な側面が、ゲームの背景になっています。
オートマトン(automaton)は自動機械、自動装置のことですが、セル・オートマトンは、有限個の状態(四角形などのセルで分割された空間)と、その遷移規則によって、時間経過で状態が計算されるモデルです。

「ライフゲーム」の内容と、遊ぶ上でのヒントを紹介します:

「ライフゲーム」の基本的な内容は、下記サイトに記述されています:
https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0
https://www.mirai-kougaku.jp/laboratory/pages/230120_03.php

数学的側面から、読む価値のあるサイトです:
https://www.herr-rau.de/wordpress/2009/01/life-der-zellautomat.htm
http://beltoforion.de/article.php?a=game_of_life
http://www.mathematische-basteleien.de/gameoflife.htm
https://www.jstage.jst.go.jp/article/jjsai/37/1/37_12/_pdf/-char/ja

 セルオートマトン
一次元セルラーオートマトン/二次元セルラーオートマトン/ライフゲーム
https://qiita.com/BB-KING777/items/49571dc04946a1e399dd
セルオートマトン入門
https://www.jstage.jst.go.jp/article/isciesci/63/7/63_264/_pdf/-char/ja
セルオートマトン
https://www.bunkyo.ac.jp/~hotta/lab/courses/2023/2023knw/23knw_3.pdf
セル・オートマトンを利用したゲームの開発
http://www.net.c.dendai.ac.jp/~aoshima/

 関連するゲーム
https://www.freebasic.net/forum/viewtopic.php?t=32536
 ラングトンのアリ
https://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%B3%E3%82%B0%E3%83%88%E3%83%B3%E3%81%AE%E3%82%A2%E3%83%AA

コンウェイの世界を FreeBASIC で実現します

内容
- 詳細で制御可能なプログラムバージョン "Conways_GameOfLife.exe"
- 副産物としてスクリーンセーバー "Conway_Scenes-Screensaver.scr"


プログラム "Conways_GameOfLife.exe"

1.プログラムを起動すると、実行画面にゲームの実行に必要なパラメータが表示されるので、入力します。
画面にはそれなりの説明が記述されているので、最初に参考書を読まなくても適当に入力できるでしょう。
ENTER キーを押すだけでも、設定されたデフォルト値(=標準値)で入力が進みます。

2.実行画面で ENTER キーを押すと描画画面が開きます。この描画画面にマウスやカーソルキー(線の場合)を使ってセル構成の初期状態を描画します。

3.描画画面に初期セルを描いた後、スペースキーを押すとゲーム(遷移)が開始されます。

4.描画画面で実行している状態で、S キー(Stop)を押すと中断します。中断状態でさらに C キー(Clear)を押すと、描画プログラムは終了します。


フル画面サイズではなく、小さい競技場を作る場合の、実行画面での入力例:
最小画面設定

...残りの情報については、デフォルト、つまり入力なしで選択しています。
競技場の寸法は、常に自動的にピクセル数で最適化され、全セルを収容します。

この結果、以下のような競技場になります:
競技場

...上の画面では、赤で、いわゆる R-ペントミノをスタート構成としてマークしています。
(注:初期セル設定では、移動物体であるグライダー形と、長寿型の R-ペントミノ(5つの正方形)形が有名です。)
 シャトル
https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%A3%E3%83%88%E3%83%AB_(%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0)
 グライダー銃
https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%A9%E3%82%A4%E3%83%80%E3%83%BC%E9%8A%83
 繁殖型 (ライフゲーム)
https://ja.wikipedia.org/wiki/%E7%B9%81%E6%AE%96%E5%9E%8B_(%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0)

黒丸は、競技場の中心を示すだけの目安です。
競技場の基本色は黄色です。 ゲーム中、およびゲーム終了後、白(消滅)のマスは、ゲームの進行中に「生命」が広がった場所を確認するために使うことができます。
スペースキーを押すと「ゲーム(遷移)」を開始します。 ...試してみてください!

ページの頭に戻る

スタート実行画面の特記事項と補足説明:

競技場:
- 競技場サイズ(最大物理解像度)とセルサイズ(最小2ピクセル)を自由に選択できます
- 整数個のセルに対応するためにピクセル数を自動で調整します。

画面端を超えた場合の競技場の特性 :
- トーラス(円環面) top+bottom+left+right、競技場のそれぞれの端を超えたセルは反対側に戻ってくる(デフォルト)
- トーラス(円環面)は上下のみ、左右に画面の端を超えて行き過ぎた場合はセル死滅につながる
- トーラス(円環面)は左+右のみ、上下方向で画面を超えた場合はセル死滅につながる
- トーラス(円環面)はなく、上下左右の端を超えるとセル死滅につながる
- この場合のセル死滅とは:競技場の端の外側にある細胞はすべて死んだことになります。

ルールの種類 - コンウェイの代替ワールドにも対応:
- 1 = 23/3 クラシック・コンウェイ(デフォルト)
- 2 = 1357/1357 コピーワールド(自己複製)、シンプルで魅力的。4世代毎で中断すると自己複製を楽しめます。
- 3 = l../b... 生存ルール "l "と出生ルール "b "に基づくルール世界を自由に指定できます。
- 下の画像は、ルールの種類 3の場合の入力方法の例です: l../b... に 245/3 を指定します:
生存設定

 標準のライフゲームは、周囲に3つの隣人がいれば生命が誕生し、周囲に2つか3つの隣人がいれば生き残り、それ以外の場合では死ぬ、というルールで、23/3と表します。最初の数 (2,3) は生き残るために必要な数を表し、次の数 (3) は生命の誕生に必要な数を表します。
 下の左端の図は、初期値として横に4つのオレンジ色のセルが並んで生存している例です。この図に、周囲の生きているセルの数を記入しています。3 は誕生で、1 は死亡です。すると、次の世代で中央の形に遷移します。中央の図も周囲の生きているセルの数を記入しています。3 は誕生で、5 は死亡です。すると、右端の形に遷移します。
遷移の例
 ルールで、16/6 という記述は、「1つあるいは6つの隣人がいれば生き残り、6 つの隣人がいればセルが誕生する」ことを意味します。
 バリエーションの中では、23/36 が有名です。HighLifeと呼ばれ、オリジナルのルールに加えて、6 つの隣人がいれば誕生するというルールを付け加えたものです。
 また、一般的なライフゲームでうまくいかない点を研究するために、3-4Life (34/34) などの変則ルールが多数作られています。

更なる機能:
- "n " 世代毎に途中停止できます(ルールタイプ 2 のコピーワールドでは 4 が有効)
- 移動シーケンスの追跡可能性を向上させるために、各生成後の遅延をミリ秒単位で指定できます。
(計算された標準遅延を選択することもできますが、プロセッサの性能に依存します)。
- 色選択1〜13、各世代で周期的に繰返します。

描画画面では「キー入力」で、開始(空白キー)、中断(S キー)、リセット(A キー)、終了(C キー)の操作を行えます。
キー操作の説明

セルの初期状態は、マウスを使ってフリーハンドで「描画」するか、カーソルキーを使って線を「描画」します。
 操作方法:
- マウスの左ボタンを押しながらフリーハンドで描画して、マウスの右ボタンで修正することができます。(修正されたセルは白くなります)
- 直線を描く場合は、次のようします:
1. "M "キー(着色の場合)を押した後、希望する線の開始セルをマウスの左ボタンでマークします。
2.マウスでマークしたの位置から、カーソルキー(矢印キー)を使って任意の長さの線を引くことができます。
3. カーソルキー状態で ESCape を押すと、フリーハンド・マウスモードに戻ります。

- スペースキーを押すとゲーム(遷移)を開始します。
線描画の用の "M "モード(矢印キー操作モード)からはゲーム(遷移)を開始できないので、 ESCape を押して、マウスモードに戻してから、スペースキーで遷移を開始して下さい。

ページの頭に戻る

スクリーンセーバー "Conway_Scenes-Screensaver.scr"

Conway_Scenes-Screensaver-Utf8JP.bas と Conway_Scenes-Screensaver-Utf8JP.scr は、下記でダウンロードできます。
Conway_Scenes-Screensaver-Utf8JP.zip

コンウェイ・プログラムは、固定された初期設定(つまり、描画画面に「セル着色」したもの)を想定し、遅かれ早かれ固定または振動する終了状態に至るものです。
スクリーンセーバーは、対照的に、このような開始設定の手動入力を想定していません。
スクリーンセーバーは、無限に画面表示できるように、X 世代ごとに、前述の、ペントミノ、アングル、階段、10ライン、ロングラインなど、効果的な開始図形をランダムに「ドロップ」して「再供給」します。
これはすべて、何の介入もなくランダムに起こります。 コンウェイ・ワールドの様々なパターンを楽しめます。
(初期値やパターンについてはウィキペディアを参照下さい)。

渡辺注:私は、細かいパターンを表示するように iz = Int(Rnd*10) +1 を iz = Int(Rnd*5) +1 'セルサイズ 1 〜 5 に、
また、単色だと不気味に感じるので、fanz = Int(Rnd*15) を fanz = 3 + Int(Rnd*10) として 3色以上になるように
修正してコンパイルしました。

スクリーンセーバーは、コンウェイ プログラムの「副産物」で、初期値を「自給自足」するように拡張したものです。
背景色は常に黒で、プライマリ画面のフルスクリーンモードで表示されます。マルチスクリーンの広がりはありません!

スクリーンセーバーの表示画像例:
画像例1

画像例2


 問題?
スクリーンセーバーの再生は、通常は完全にスムーズに動作しますが、まれにカクカクすることがあります。"Conways_GameOfLife.exe "は常にスムーズかつ迅速に動作します。

 原因:
GPU(描画プロセッサー)上で計算を行うバックグラウンド・アプリケーションを使うためです。
『SETI@hoime』や『Einstein@home』など、さまざまなBOINCプロジェクトがその候補として考えられます。
スクリーンセーバーとして使うことで、BOINCプロジェクトにすべてのリソースが独占的に利用できることを知らせる...。

 解決策:
BOINC Manager の Control で "Pause GPU utilisation (GPU使用一時停止)"を有効にします。
その他の原因については、アナログ設定オプションを検索してください。

 展望
... バージョン2へ
- グライダー・キャノンなどの描画のための "スタンプボックス "と、その他の効果的なスタートフィギュア
- スクリーンセーバーもカスタマイズできるように、プログラムコールのパラメーターを有効にする。

- 質問/提案歓迎!


ページの頭に戻る

比較 "Conways_GameOfLife.exe" / "Conway_Scenes-Screensaver.scr"

一般 Conways_GameOfLife.exe Conway_Scenes-Screensaver.scr
描画画面 物理解像度を自由に選択可能、1920x1080 までテスト済み
デフォルト 幅 x 高さ - 30 ピクセル (タスクバー用に空ける)
プライマリモニターでは常にフルスクリーン表示、1920 x 1080 までテスト済み
セルサイズ 自由に選択可能/デフォルト10ピクセル/最小2x2ピクセル 1x1〜10x10ピクセルのランダム化
セル周囲のグリッド線 あり。1 ピクセルの太さで薄いグレーで表示 なし。(したがって 1x1 ピクセルのセルも良好に表示できる)
トーラス(円環面)の特性 「エッジを越える際の競技場プロパティ」ダイアログで自由に選択可能 常に上下左右で完全なトーラス(円環面)になります
ルール型(コンウェイワールド) 2 つの事前作成済み (クラシックとコピーワールド) と、もう一つは、生存と誕生のルールに基づいて自由に定義できます。 常にクラシックなコンウェイ・ワールド 23/3
"n" 世代毎の中間停止位置 有り、(コピーワールドでは 4が有効です) 無し
各世代後の遅延 自由に選択可能、計算された標準遅延を含む 常に計算された標準遅延
色数 自由に選択可能、デフォルト 1 ランダム制御 1 - 13
描画・画面で初期配置を描く はい、マウスまたは矢印キーで線 いいえ、ランダムな開始設定
終了状態に達しますか? はい、「グライダー砲」のような珍しいものを除いて、振動構造で終わることが多く、完全に「消滅」することは稀です。 いいえ、これはスクリーンセーバーであり、ランダムに「補充」されます。キーボードを押したりマウスを動かしたりすると終了します。
テクニカル

FbEdit でコンパイル 64ビットの場合、パラメータ「Windowsコンソール」、実行画面と描画画面 64ビットの場合、パラメータ「Windows GUI」、描画画面のみフルスクリーン
テスト 最大 1920x1080 最大 1920x1080
プロセッサー Celeron 4 x 1.8 Ghz から Pentium i3/i7 まで、AMD Phenom はすべて正常です。低負荷では 1 つの CPU コアのみが使用されます。 Celeron 4 x 1.8 Ghz から Pentium i3/i7 まで、AMD Phenom はすべて正常です。低負荷では 1 つの CPU コアのみが使用されます。
マルチ画面 主画面のみ 主画面のみ
インストール exeをディスクにコピーして実行します スクリーンセーバー(scr)を、Windows の System32 フォルダにコピーし、以下の手順でスクリーンセーバーとして設定します。
「コントロールパネル → 個人設定 → ロック画面 → カスタマイズ → スクリーンセーバーの変更」で、表示されるプログラム名を選択して、スクリーンセーバーとして設定します。
再コンパイルする場合は、出来上がった.exeを.scrにリネームしてください。

ページの頭に戻る

Conways_GameOfLife-JP2.bas
'========================
'コンウェイのライフゲーム
'========================

' 意味とルール : https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0
' プログラマー :   Klaus Brock                              02/2017
' コンパイル   :   Windows-Console (FbEdit)

Dim Shared As Short i,j,ib,ih,iz,il,k,l,lb,lh,m,n,ix,jx,RegelTyp,fanz,istop,lebend,LivNbrs,breit,hoch,_
                    liox,reux,lioy,reuy,Vzmillsek,Splfd,ireg
Dim Shared As Integer igen,lincolor,circolor,totcolor,lebcolor,backcolor,fndx,MousePosX,MousePosY,MouseKeyState,_
                    scrb,scrh,scrct,xstart,ystart
Dim Shared As String steuer,Taste,Pfeil
Dim Shared As BOOLEAN cnt

'RegelTyp 3 : 生きるための隣人の数 :
Dim Shared As Short ueberleb (1 To 8) = { -1,-1,-1,-1,-1,-1,-1,-1 }
'RegelTyp 3 : 誕生時の隣人の数 :
Dim Shared As Short neugebor (1 To 8) = { -1,-1,-1,-1,-1,-1,-1,-1 }

  lincolor  = 7
  circolor  = 0
  totcolor  = 15
  lebcolor  = 4   ' 最初の割り当て、その後、循環的に
  backcolor = 14  ' 競技場の初期背景
Dim Shared As Integer farbe (1 To 13)  'fndxの色
  Farbe(1)  =  4
  Farbe(2)  =  1
  Farbe(3)  =  2
  Farbe(4)  =  3
  Farbe(5)  =  5
  Farbe(6)  =  6
  Farbe(7)  =  8
  Farbe(8)  =  9
  Farbe(9)  =  10
  Farbe(10) =  11
  Farbe(11) =  12
  Farbe(12) =  13
  Farbe(13) =  10 '14 は背景色

Declare Sub StartWerteSetzen()
Declare Sub GitterLinienZeichnen()
Declare Sub BelebteZellenInit()
Declare Sub MainLoop()

Declare Sub CountLivingNeigbors()

' ... die Conway-"Welten" :
Declare Sub KlassischConway()
Declare Sub KopierWelt()
Declare Sub FreiDefWelt()

' ---

Declare Sub ZellGeburtInit()
Declare Sub ZellGeburt()
Declare Sub ZellTod()
Declare Sub ZellPos()
Declare Sub StopKey()
Declare Sub Ausgestorben()
Declare Sub ShowArray()

'------------------- メイン・プログラム -----------------------------------------------------

Cls

Randomize

StartWerteSetzen

'内部作業配列の望ましい寸法(lh*lb)が判明した :
'numW = 現在のフィールド / numFolg = 次世代のフラグ
Dim Shared As BOOLEAN numW    (1 To lh, 1 To lb)
Dim Shared As BOOLEAN numFolg (1 To lh, 1 To lb)

Do
  GitterLinienZeichnen
  BelebteZellenInit
  igen   = 1     '  生成 = ゲートのすべての論理フィールドを1回通過する
  MainLoop
Loop


'-------------------  レベル1のサブは以下の通り  -----------------------------------------------------

Sub StartWerteSetzen

Width 100,70
  Print ""
  Print "   -------------------------   ■"
  Print "   コンウェイのライフゲーム      ■"
  Print "   ------------------------- ■■■"
  Print ""
  Print "意味とルール : https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0"
  Print "プログラマー           : Klaus Brock                                02/2017"
  Print ""

  '物理的な画面解像度 :
  ScreenInfo scrb,scrh,scrct
  Print "画面の解像度:b * h * 色深度 : " ;scrb;" * ";scrh;" * ";scrct

  '物理的な画面の幅と高さ、セルのサイズを設定します(すべてピクセル数)。
  Print ""
  Input "描画画面の幅(デフォルトは b/1.5)ピクセル単位             : "; ib
  If ib = 0 Or ib > scrb Then
    ib  = scrb/1.5
  EndIf
  Input "描画画面の高さ(デフォルトは h/1.5 - 30)ピクセル単位      : "; ih
  If ih = 0 Or ih > scrh Then
    ih  = scrh/1.5 - 30  'タスクバーのスペースを確保
  EndIf
  Input "セルの高さ(ピクセル単位)(デフォルト 10 / 最小 2)   : "; iz
  If iz = 0 Then
    iz  = 10
  EndIf
  If iz < 2  Then
    iz  = 2
  EndIf

  '論理画面 サイズ (垂直方向と水平方向のセルの数) を決定します。
  '物理画面 サイズを可能な限り最大に調整します。セルの数は整数です。
  'そのため、物理的な画面 サイズの指定について心配する必要はありません。
  Print ""
  Print "競技場のサイズはセル数(ピクセル数)の整数に調整されます :"
  ib = ib - ib Mod (iz+1) 'math. Remainder
  Print "描画画面の幅をピクセル単位で調整 = "; ib
  ih = ih - ih Mod (iz+1) 'math. Remainder
  Print "描画画面の高さをピクセル単位で調整 = "; ih

  'これにより、論理ゲームゲートのサイズは lb x lh セルとなり、
  '競技場には常に整数個のフィールドが存在することが保証されます :
  Print "結果として得られる競技場のサイズ(セル) :"
  lb = ib \ (iz+1) 'math. Floor
  Print "  log. 競技場の幅(セル単位) = 列 = "; lb
  lh = ih \ (iz+1) 'math. Floor
  Print "  log. 技場の高さ(セル単位) = 行  = "; lh

  '描画画面から飛び出したときの競技場の特性 :
  Print ""
  Print "画面端を越える場合の競技場の特性 : "
  Print "-------------------------------------------------- "
  Print "- 円環面上/下 + 左/右 (デフォルト)"
  Print "  - 左側から出たセルは右側から戻ってくる"
  Print "  - 上に出たセルは下から戻ってくる"
  Print "                            ...逆も同様 (デフォルト)  --> 1"
  Print "- 円環面なし、競技場外"
  Print "                 すべてのセルは死んだとみなされる     --> 2"
  Print "- 円環面は上/下のみ(左/右=セル死)                  --> 3"
  Print "- 円環面は左/右のみ(上/下=セル死)                  --> 4"
  Input "競技場の特性を選択してください  : "; Splfd
  If Splfd = 0 Then
     Splfd = 1
  ElseIf Splfd > 4 Then
     Splfd = 1
  Else
  EndIf

  ' クエリルールの種類 / 生存/誕生のルール番号
  Print ""
  Print "ルールの種類 : "
  Print "------------ "
  Print "  23/3   コンウェイ・クラシック(デフォルト)--> RegelTyp 1"
  Print "  1357/1357  コピーワールド                  --> RegelTyp 2"
  Print "  l../b...   自由に定義します                --> RegelTyp 3"
  Input "ルールの種類を選択してください。  : "; RegelTyp
  If RegelTyp= 0 Then
     RegelTyp = 1
  ElseIf RegelTyp= 3 Then
  	  Print
  	  Print "  ライフゲームのルールの略語: (Wikipedia) "
  	  Print "  まず、セルが生き残る場合の近傍の数の数字を(昇順で)指定して、"
  	  Print "  次に、セルが誕生する場合の数字をスラッシュで区切って並べます。"
     Input "  生存条件の数を、最大8桁の 0 〜8( カンマ区切り)を入力してください : "_
        ,ueberleb(1),ueberleb(2),ueberleb(3),ueberleb(4),ueberleb(5),ueberleb(6)_
        ,ueberleb(7),ueberleb(8)
     Input "  誕生条件の数を、最大 8桁の 0 〜8( カンマ区切り)を入力してください : "_
        ,neugebor(1),neugebor(2),neugebor(3),neugebor(4),neugebor(5),neugebor(6)_
        ,neugebor(7),neugebor(8)
     For ireg = 2 To 8
     	 If ueberleb(ireg) = 0 Then
     	 	 ueberleb(ireg) = -1
     	 EndIf
     	 If neugebor(ireg) = 0 Then
     	 	 neugebor(ireg) = -1
     	 EndIf
     Next
     Print "  選択されたコンウェイルールの世界 : ";
       For ireg = 1 To 8
       	If ueberleb(ireg) > -1 Then
       		Print ueberleb(ireg);
       	EndIf
       Next ireg
       Print " /";
       For ireg = 1 To 8
       	If neugebor(ireg) > -1 Then
       		Print neugebor(ireg);
       	EndIf
       Next ireg
       Print ""
  ElseIf RegelTyp> 3 Then
     RegelTyp = 1
  Else
  EndIf

    '何世代ごとの停止す条件。0の場合は無限に実行
  Print ""
  Print "途中停止: コピーワールド(ルール タイプ 2)では 4 の倍数を推奨します "
  Print "--------------"
  Input "  何世代ごとに途中停止しますか? ( なしの場合は ENTER ): "; istop
  'If istop = "" Then
  '  istop  = 0
  'EndIf

  ' 各世代終了後の遅延 :
  Print ""
  Print "各生成後の遅延(視認性向上のため):"
  Print "----------------------------------"
  Print "  遅延なし             デフォルト   :  0"
  Print "  標準遅延(セル数に応じて) 推奨   :  1"
  Print "  遅延表示(ミリ秒単位).           : nnn"
  Input "遅延を選択してください  : "; Vzmillsek
  If Vzmillsek = 1 Then
     Vzmillsek = ((1921-lb) * (1001-lh)) / 30000
     Print "ミリ秒単位の標準遅延: ";Vzmillsek
  EndIf

  ' 色番号 :
  Print ""
  Input "色数を入力してください 1 - 13 ( Default 1 ) : "; fanz
  If fanz= 0 Then
     fanz= 1
  ElseIf fanz>13 Then
    fanz=13
  Else
  EndIf

  ' ... to do :
  Print ""
  Print "これで絵が描けます :"
  Print "--------------------------"
  Print "- 描画画面で、初期状態で生きているセルを、マウスで左クリックしてマークします。"
  Print "- 誤って入力しセルは、マウスの右クリックで修正できます。"
  Print "- 線の描画 :  M キーを押してキー操作に切り替えます。マウス左クリックで線の起点をマークします。"
  Print "  矢印キーを使って線を描画できます。マウスで描画するモードに戻すには ESCape キーを押します。"
  Print "- 起動・中断・終了 - 空白キーを押すと、描画画面を表示します。"
  Print "                   - S キー(Stop)で描画表示を停止します。何かキー入力すると表示再開します。"
  Print "                   - Stop 状態で A キーを押すと、現在のゲームをキャンセルし、描画をリセットします"
  Print "                   - Stop 状態で C キーを押すと、プログラムは終了します。"
  Print "                   - つまり、描画プログラムの終了は、S キーを押した後 C キーを押します。"
  Print ""
  Print "  ===> 何かキーを押すと描画画面を開始します !"
  Sleep

End Sub


Sub GitterLinienZeichnen

  'ゲームゲート/ライトグレーの線をlhとlb に応じて描画します。グリッド線自体には1ピクセル追加します。
  ScreenRes ib, ih, 8    ' 画面モード 巾 x 高さ 8bpp
  ScreenControl 100,0,0  ' 画面位置 SET_WINDOW_POS 左上
  Color lincolor,backcolor
  Cls
  WindowTitle "コンウェイのライフゲーム /RegTyp=" & RegelTyp & " 世代=" & igen & " (開始:Space、 停止:S、終了:C)"
  ' erst die waagerechten :
  For i=0 To ih Step iz+1
    Line(1,i)-(ib,i),lincolor
  Next i
  ' jetzt die senkrechten :
  For i=0 To ib Step iz+1
    Line(i,1)-(i,ih),lincolor
  Next i
  'Mittelpunktsmarkierung :
  Circle(ib/2,ih/2),iz,circolor

End Sub


Sub BelebteZellenInit

  '内部数字配列をホームポジションへ、これが現在の作業フィールドです :
  For i=1 To lh            'log. Hoehe   (Zeilen)
    For j=1 To lb          'log. Breite  (Spalten)V
      numW(i,j) = FALSE
    Next j
  Next i
  'マウスで最初に生存させるセルを設定する :
  Do
    '描画画面内のマウス座標を決定する :
    GetMouse (MousePosX, MousePosY, , MouseKeyState)    'Mausstatus abfragen
    breit=MousePosX
    hoch =MousePosY
    '線画(m)または終了(スペース)が要求されましたか?
    Taste=InKey
    If Taste = "m" Or Taste = Chr(27) Then 'これらの 2 つの値で矢印操作
       Pfeil = Taste
    EndIf
    'マウス座標から内部数値配列の対応するインデックス i,j を計算する:
    i = hoch  \ (iz+1) +1
    j = breit \ (iz+1) +1
    '内部配列とゲート内のセルを誕生させる、マウスの左ボタン :
    If MouseKeyState And 1 Then
    	numW(i,j) = TRUE
      ZellGeburtInit()
      'カーソルキー(矢印キー)を使って、
      '今入力したセルから始まる線の描画を要求しましたか ? :
      If Pfeil = "m" Then ' m キーは、カーソルキーでは絵を描き始める
        Do
        	 Pfeil = InKey
      	 If Pfeil = Chr(255,72) Then 'nach oben
             i = i - 1
          EndIf
          If Pfeil = Chr(255,75) Then 'nach links
             j = j - 1
          EndIf
          If Pfeil = Chr(255,77) Then 'nach rechts
             j = j + 1
          EndIf
          If Pfeil = Chr(255,80) Then 'nach unten
             i = i + 1
          EndIf
          If Pfeil <> " " Then 'カーソルキーが使われたので、この方向に線を引く
         	numW(i,j) = TRUE
            ZellGeburtInit()
          EndIf
        Loop Until Pfeil = Chr(27) 'ESCape  絵を残すために :
      EndIf
    EndIf
    '誤って生存化されたセルを修正するには、マウスの右ボタン :
    If MouseKeyState And 2 Then
    	numW(i,j) = FALSE
    	ZellTod()
    EndIf
  'スペースキーを押すとマークを終了:
  Loop Until Taste = " "

End Sub


Sub MainLoop

  ' ... そしてここからが本当の始まりです !!!
  '      ------------------------------------
  '
  'マウスで塗りつぶされた競技場の1 回限りの転送 :
  For i=1 To lh            'log. Hoehe   (Zeilen)
   For j=1 To lb          'log. Breite  (Spalten)V
     numFolg(i,j) = numW(i,j)    '最新の状態にする(0=死亡、1誕生の順)
   Next j
  Next i
  '
  Do             '  望ましい無限ループ (s.LOOP)
    ' --- 現在の世代の始まり :  ---
    WindowTitle "コンウェイのライフゲーム /RegTyp=" & RegelTyp & " 世代=" & igen & " (開始:Space、 停止:S、終了:C)"
    lebend = 0          ' この世代以降に「すべて絶滅」したかどうかの検出
    For i=1 To lh
      For j=1 To lb
        CountLivingNeigbors()
        If RegelTyp=1 Then
          KlassischConway()
        ElseIf RegelTyp=2 Then
          KopierWelt()
        ElseIf RegelTyp=3 Then
          FreiDefWelt()
        Else
          'ルールタイプが間違っています。ここでは発生しません
        EndIf
        ' ********** ここでは他のルールの世界も可能です !!!!!!!!!!!!!
        If numW(i,j) = TRUE Then
          lebend = lebend + 1    '世代ごとに現在生きているセルを数える
        EndIf
      Next j
    Next i
    '
    ' --- 現在の世代の終わり :  ---
    '誕生/死亡の内部数字配列を処理します。
    'つまり、現在の数値配列を更新して画像を描画します :
    fndx = (igen Mod fanz) +1  'math. Remainder
    If fndx>13 Then
    	fndx=13
    EndIf
    For i=1 To lh              'log. Hoehe   (Zeilen)
      For j=1 To lb            'log. Breite  (Spalten)
        If numW(i,j) Xor numFolg(i,j) = TRUE Then   '3=以下変更なし。 (0=死亡 1誕生の連続)
          numW(i,j) = numFolg(i,j)
          If numW(i,j) = FALSE Then
            ZellTod()
          EndIf
          If numW(i,j) = TRUE Then
            ZellGeburt()    '塗りつぶされた長方形の色は世代に応じて生じる
          EndIf
        EndIf
      Next j
    Next i
    ' 遅延 :
    Sleep Vzmillsek
    ' ユーザーの停止は「s」経由で要求されたか?
    StopKey()
    ' ... それともすべて絶滅したのでしょうか? これでプログラムは終了です!
    Ausgestorben()
    '途中停止をリクエストしましたか? (4 は「コピーワールド」で役立ちます)
    If istop > 0 Then
    	If igen Mod istop = 0 Then
        Sleep
      EndIf
    EndIf
    igen = igen+1
    Steuer = InKey
    If Steuer = "c" Or Steuer = "C" Then
    	End
    EndIf
  Loop Until ( Steuer = "a" Or Steuer = "A" )  ' A = Abbruch ご破算

End Sub


'-------------------  レベル2のサブが続きます ---------------------------------------------------

Sub CountLivingNeigbors
  'ここでは、対象となるセルの生きている隣接セルがカウントされる。 ( 3 x 3 )
  ' 「トーラス」とは :
  '隣の駒が範囲外、つまりゲーム ゲートの端に直接位置している場合は、
  '反対側の端の行/列が使用されます。
  'これにより、競技場が無限であるかのような振る舞いになります...
  LivNbrs = 0
  For k=i-1 To i+1
    For l=j-1 To j+1
    	 ' 競技場の端を越えてカウントできる(Splfd 1の標準)
    	 cnt=TRUE
       ' プレイフィールドの端を超えない通常のケース(範囲外) :
       m=k
       n=l
       ' 範囲外 / 左、右、上、下を超える = 4 つのケースを扱う :
       ' ------------------------------------------------------------------------------
       'ケース 1: TORUS 左/右 と 上/下 (このような表面は現実には有りえないが)
       If Splfd = 1 Then
         If k<1 Then  'Zeile
           m=lh
         EndIf
         If k>lh Then
           m=1
         EndIf
         If l<1 Then  'Spalte
           n=lb
         EndIf
         If l>lb Then
           n=1
         EndIf
       'Fall 2 : kein TORUS, Randueberschreitung = ZellTod
       ElseIf Splfd = 2 Then
         If k<1 Then  'Zeile
           m=1
           cnt=FALSE
         EndIf
         If k>lh Then
           m=lh
           cnt=FALSE
         EndIf
         If l<1 Then  'Spalte
           n=1
           cnt=FALSE
         EndIf
         If l>lb Then
           n=lb
           cnt=FALSE
         EndIf
       'Fall 3 : TORUS NUR oben/unten  ( links/rechts=ZellTod )
       ElseIf Splfd = 3 Then
         If k<1 Then  'Zeile
           m=lh
         EndIf
         If k>lh Then
           m=1
         EndIf
         If l<1 Then  'Spalte
           n=1
           cnt=FALSE
         EndIf
         If l>lb Then
           n=lb
           cnt=FALSE
         EndIf
       'Fall 4 : TORUS NUR links/rechts ( oben/unten =ZellTod )
       ElseIf Splfd = 4 Then
         If k<1 Then  'Zeile
           m=1
           cnt=FALSE
         EndIf
         If k>lh Then
           m=lh
           cnt=FALSE
         EndIf
         If l<1 Then  'Spalte
           n=lb
         EndIf
         If l>lb Then
           n=1
         EndIf
       Else ' nicht moeglich
       EndIf
       ' 生きている隣接セルを数える :
       If cnt = TRUE  And  numW(m,n) = TRUE Then
         LivNbrs = LivNbrs + 1
       EndIf
    Next l
  Next k
  If numW(i,j) = TRUE Then
    LivNbrs=LivNbrs-1 'セル自体が生きている場合はカウントされない !
  EndIf
End Sub


Sub KlassischConway
  'コンウェイのクラシック・ルール :
  '-----------------------------------
  ' 死亡、しかし、生きた 3人の隣人がいる :
  If numW(i,j) = FALSE And LivNbrs = 3 Then
    numFolg(i,j) = TRUE    ' 誕生を順番に記録します。
  EndIf
  ' 生存、しかし、隣人は2人未満 :
  If numW(i,j) = TRUE And LivNbrs < 2 Then  '孤独による死亡
    numFolg(i,j) = FALSE   ' シーケンス内の死亡に注意。
  EndIf
  ' 生存、しかし、3人以上の隣人が生きている :
  If numW(i,j) = TRUE And LivNbrs > 3 Then  '人口過剰による死亡
    numFolg(i,j) = FALSE   ' シーケンス内の死亡に注意。
  EndIf
  ' 2人か3人の隣人と一緒に暮らす場合に限って、生き残ることができます。
End Sub


Sub KopierWelt
  ' コピーワールド(生きている隣人の数を2で割ったもの) :
  '-----------------------------------
  If LivNbrs Mod 2 = 0 Then 'math. Remainder
    numFolg(i,j) = FALSE    ' 死亡 Vormerken Absterben bei 0,2,4,6,8 leb.Nachbarn in Folgegen.
  Else
    numFolg(i,j) = TRUE     ' 誕生 Vormerken Geburt bei 1,3,5,7 leb.Nachbarn  in Folgegen.
  EndIf
End Sub


Sub FreiDefWelt
  '生存ルール l と誕生ルール b に基づいて自由に定義できる世界 llll/bbbb  :
  '-------------------------------------------------------------------------------------
  '注: 入力されていない値は入力後に -1 に設定されます (0 はなくなります) !
  '
  ' Start-Annahme :
  numFolg(i,j) = FALSE  ' シーケンス内の死亡に注意してください。
  ' ueberlebend ? :
  If numW(i,j) = TRUE Then
    For ireg = 1 To 8
      If LivNbrs = ueberleb(ireg)  Then
        numFolg(i,j) = TRUE   ' 誕生を順番に記録します。
        Continue For
      EndIf
    Next ireg
  EndIf
  ' Geburt ? :
  If numW(i,j) = FALSE Then
    For ireg = 1 To 8
      If LivNbrs = neugebor(ireg)  Then
        numFolg(i,j) = TRUE   ' 誕生を順番に記録します。
        Continue For
      EndIf
    Next ireg
  EndIf
End Sub


Sub ZellGeburtInit
  '以前は死んでいたセルが生き返る(数値配列とゲート内)
  liox = (j-1)*(iz+1) + 1   ' +1 ist die Gitternetzlinie
  lioy = (i-1)*(iz+1) + 1   ' +1 ist die Gitternetzlinie
  reux = liox + (iz-1)
  reuy = lioy + (iz-1)
  Line(liox,lioy)-(reux,reuy),lebcolor,BF  '塗りつぶされた長方形の色 生きている INIT
End Sub


Sub ZellTod
  ZellPos()
  Line(liox,lioy)-(reux,reuy),totcolor,BF  '塗りつぶされた矩形の色 デッドINIT
End Sub


Sub ZellGeburt
  '以前は死んでいたセルが生き返る(数値配列とゲート内)
  ZellPos()
  Line(liox,lioy)-(reux,reuy),Farbe(fndx),BF  '塗りつぶされた長方形の色 生きている INIT
End Sub


Sub ZellPos
  liox = (j-1)*(iz+1) + 1   ' +1 はグリッド線
  lioy = (i-1)*(iz+1) + 1   ' +1 はグリッド線
  reux = liox + (iz-1)
  reuy = lioy + (iz-1)
End Sub


Sub StopKey
  ' Stop game
  If InKey = "s" Or InKey = "S" Then
  	 WindowTitle "CONWAYs Sp... /RegTyp=" & RegelTyp & " 世代=" & igen & " Stop ! ( C = 終了 / A = 再描画 )"
  	 Sleep
  EndIf
End Sub


Sub Ausgestorben
  ' ... すべて絶滅 :
  If lebend = 0 Then
  	 WindowTitle "コンウェイのライフゲーム /RegTyp=" & RegelTyp & " 世代=" & igen & " すべて絶滅 !"
    Sleep
    i = i / 0
  EndIf
End Sub


Sub ShowArray
  ' テスト目的のみ 完全な数値配列の出力
  For ix=1 To lh
    For jx=1 To lb
      If numW(ix,jx)= TRUE Then
        Print "1"
      Else
        Print "0"
      EndIf
    Next jx
    Print ""
  Next ix
End Sub

ページの頭に戻る

参照:
有名なルール Life Family Cellular Automata
https://github.com/craiglp/agon-life

A. コンウェイの生涯 - 混沌 - 23/3
B. 2x2 - 混沌 - 125/36
C. 34 生命 - 爆発 - 34/34
D. アメーバ - 混沌 - 1358/357
E. 同化 - 安定 - 4567/345
F. 凝固 - 爆発 - 235678/378
G. コーラル - 爆発 - 45678/3
H. 昼と夜 - 安定 - 34678/3678
I. ディアメーバ - 混沌 - 5678/35678
J. フレーク - 拡大 - 012345678/3
K. ナール - 爆発 - 1/1
L. HighLife - 混沌 - 23/36
M. Long Life - 安定 - 5/345
N. Maze - 爆発 - 12345/3
O. Mazectric - 爆発 - 1234/3
P. 移動 - 安定 - 245/368
Q. 擬似生命 - 混沌 - 238/357
R. Replicator - 爆発 - 1357/1357
S. Stains - 安定 - 235678/3678
T. WalledCities - 安定 - 2345/45678

他の作者の FreeBASIC プログラム・バージョン:
https://freebasic.net/forum/viewtopic.php?t=29177
ページの頭に戻る
補足 に戻る
←リンク元に戻る プログラム開発関連に戻る
ページ歴史:2017-06-30
日本語翻訳:WATANABE Makoto、原文著作者:Klaus Brock

ホームページのトップに戻る

表示-非営利-継承