ConwayのGame of Lifeを実装する機能プログラミングの方法は何ですか[非公開]


12

私は最近、ConwayのGame of LifeをJavascript(実際はcoffeescriptですが同じこと)で実装しました。javascriptは関数型言語として使用できるので、私はその範囲の終わりにとどまろうとしていました。結果に満足できませんでした。私はかなり優れたオブジェクト指向プログラマーであり、私の解決策は同じ古いものを叩きました。長い質問は短い:それを行う(擬似コード)機能スタイルは何ですか?

これが私の試みの擬似コードです。

class Node
  update: (board) ->
    get number_of_alive_neighbors from board
    get this_is_alive from board
    if this_is_alive and number_of_alive_neighbors < 2 then die
    if this_is_alive and number_of_alive_neighbors > 3 then die
    if not this_is_alive and number_of_alive_neighbors == 3 then alive

class NodeLocations
  at: (x, y) -> return node value at x,y
  of: (node) -> return x,y of node

class Board
  getNeighbors: (node) -> 
   use node_locations to check 8 neighbors 
   around node and return count

nodes = for 1..100 new Node
state = new NodeState(nodes)
locations = new NodeLocations(nodes)
board = new Board(locations, state)

executeRound:
  state = clone state
  accumulated_changes = for n in nodes n.update(board)
  apply accumulated_changes to state
  board = new Board(locations, state)

3
Oded

@Odedそれは私の頭の上に憂鬱です。私は基本的な概念を認識していますが、ほんのわずかです
ジョージマウアー

頭の上の...専門言語の達人ができることの例としてそれを投稿しました。それを私たちすべてのインスピレーションと呼んでください:)
Oded

@GeorgeMauer「実際のCoffeeScriptが、同じことが、」これは悲しい日です
レイノス

回答:


11

さて、いくつかのアイデア。私はFPの専門家ではありませんが、...

Boardゲームの状態を表すタイプが必要であることはかなり明らかです。実装の基礎は、evolve型の関数でなければなりませんevolve :: Board -> Board。つまりBoard、ゲームのルールをに適用することからを生成しBoardます。

どのように実装すればよいevolveですか?A BoardはおそらくCellsのnxm行列でなければなりません。a とその隣接s が次の反復で状態を計算するcellEvolve型の関数を実装できます。cellEvolve :: Cell -> [Cell] -> CellCellCellCell

また、からsの近傍getCellNeighborsを抽出する関数を実装する必要があります。このメソッドのシグネチャが完全にはわかりません。あなたは実装方法に応じて、そしてあなたは、インスタンスのために持っている可能性があり、取締役会および2点の座標(与えられたインデックスの位置に使用されるタイプになります)、(ボード内のすべてのセルが持っていないあなたの隣人の可変長リストを与えます同じ数の隣人-コーナーには3人の隣人、国境5、その他8人がいます。CellBoardCellBoardgetCellNeighbors :: Board -> CoordElem -> CoordElem -> [Cell]CoordElemBoard

evolveこれ組み合わせて実施することが可能cellEvolvegetCellNeighborsボード内のすべてのセルのために、もう一度正確な実装は、実装方法に依存しますBoardCell、それは現在のボードのすべてのセルのために、彼らの隣人を取得し、計算するためにそれらを使用する」のようなものでなければなりません「新しいボードの対応するセル」これは、「ボードのセル機能のマップ」を使用して、ボード全体にこれらの機能を汎用的に適用することで可能になります。

他の考え:

  • ゲームのルールをエンコードcellEvolveする型GameRulesをパラメーターとして受け取るように、実際に実装する必要があります。(State,[(State,NumberOfNeighbors)],State)特定の状態と各状態の隣人の数を示すタプルのリストがあります。 。cellEvolveの署名はcellEvolve :: GameRules -> Cell -> [Cell] -> Cell

  • これは論理的にあなたをevolve :: Board -> Board変化させるように連れていくevolve :: GameRules -> Board -> Boardので、evolve異なるものを変えずに使うGameRulesことができますが、さらにステップを進めてcellEvolve代わりにプラグイン可能にすることができますGameRules

  • getCellNeighborsあなたと遊ぶことは、ボードのエッジ、3Dボードなどの周りを包むことができるトポロジevolveについて一般的にすることもBoardできますgetCellNeighbors


9

Lifeの関数型プログラミングバージョンを作成している場合は、Gosperのアルゴリズムについて学ぶ必要があります。関数型プログラミングのアイデアを使用して、一辺が数兆平方インチのボードで毎秒数世代を達成します。それは不可能に思えますが、完全に可能です。私は、C#で、一辺が2 ^ 64の正方形のボードを簡単に処理できる小さな実装を用意しています。

秘Theは、時間と空間の両方でLifeボードの大規模な自己相似性を活用することです。ボードの大きなセクションの将来の状態をメモすることで、一度に巨大なセクションを迅速に進めることができます。

私は長年にわたって初心者向けのGosperのアルゴリズムの紹介をブログに書くつもりでしたが、時間がありませんでした。そのようになったら、ここにリンクを投稿します。

超幾何和を計算するためのゴスパーのアルゴリズムではなく、生命の計算のためのゴスパーのアルゴリズムを検索することに注意してください。


面白そうに見えますが、まだそのリンクを待っています...;)
jk。

3

偶然、今日のHaskell講義でこの問題を取り上げました。初めて見ましたが、与えられたソースコードへのリンクは次のとおりです。

http://pastebin.com/K3DCyKj3


それが何をするのか、そして尋ねられた質問に答えるのになぜそれをお勧めするのか、さらに説明していただけますか?Stack Exchange では「リンクのみの回答」は歓迎されません
-gnat

3

インスピレーションを得るために、RosettaCodeの実装を確認することをお勧めします。

たとえば、機能的なHaskellバージョンとOCamlバージョンがあり、前のボードに機能を適用することで毎ターン新しいボードを作成しますが、グラフィカルなOCamlバージョンは2つのアレイを使用し、速度のために交互に更新します。

実装のいくつかは、ボード更新関数を、近隣をカウントする関数に分解し、ライフルールを適用し、ボード上で反復します。これらは、機能設計の基礎となる有用なコンポーネントのようです。ボードのみを変更して、他のすべてを純粋な機能として維持してください。


1

Clojureの純粋に機能的な短いバージョンを以下に示します。すべての功績は、彼のブログ投稿でこれを公開したクリストフ・グランドにあります:Conway's Game of Life

(defn neighbours [[x y]]
  (for [dx [-1 0 1] 
        dy (if (zero? dx) [-1 1] [-1 0 1])]
    [(+ dx x) (+ dy y)]))

(defn step [cells]
  (set (for [[loc n] (frequencies (mapcat neighbours cells))
             :when (or (= n 3) (and (= n 2) (cells loc)))]
         loc)))

その後、「ステップ」機能をセルのセットに繰り返し適用することにより、ゲームをプレイできます。例:

(step #{[1 0] [1 1] [1 2]})
=> #{[2 1] [1 1] [0 1]}

賢さは(mapcatの隣接セル)部分です。これは、アクティブセルごとに8つの隣接セルのリストを作成し、それらをすべて連結します。次に、このリストに各セルが表示される回数を(周波数....)でカウントし、最後に正しい周波数カウントを持つセルを次の世代までカウントします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.