関数型プログラミング言語ElixirでシンプルなMiniMax実装を作成しています。多くの完全な知識のあるゲーム(三目並べ、コネクトフォー、チェッカー、チェスなど)があるため、この実装は、これらのゲームのゲームAIを作成するためのフレームワークになる可能性があります。
しかし、私が直面している問題の1つは、関数型言語でゲームの状態を適切に保存する方法です。これらのゲームは、主に次の操作が頻繁に行われる2次元ゲームボードを扱います。
- 特定のボードの場所の内容を読む
- 特定のボードの場所の内容を更新する(新しい移動の可能性を返すとき)
- 現在の場所に接続されている1つまたは複数の場所のコンテンツを考慮する(つまり、次または前の水平、垂直、または対角の場所)
- 任意の方向に接続された複数の場所のコンテンツを検討します。
- ファイル全体、ランク、対角線の内容を考慮します。
- ボードを回転またはミラーリングする(既に計算されたものと同じ結果が得られる対称性をチェックするため)。
ほとんどの関数型言語は、多要素データ構造の基本的なビルディングブロックとしてリンクリストとタプルを使用します。しかし、これらは仕事のために非常にひどく作られたようです:
- リンクされたリストには、O(n)(線形)ルックアップ時間があります。また、ボードを1回スイープして「ボードをスキャンして更新」することはできないため、リストを使用することは非常に非現実的です。
- タプルのルックアップ時間はO(1)(一定)です。ただし、ボードを固定サイズのタプルとして表すと、ランク、ファイル、対角線、または他の種類の連続する正方形を反復処理することが非常に難しくなります。また、ElixirとHaskell(どちらも知っている2つの関数型言語)には、タプルのn番目の要素を読み取るための構文がありません。これは、任意のサイズのボードで機能する動的ソリューションを作成することを不可能にします。
Elixirには組み込みのMapデータ構造(およびHaskellにはData.Map
)があり、要素へのO(log n)(対数)アクセスを許可します。現在、私はマップを使用し、x, y
キーとして位置を表すタプルを使用しています。
これは「うまくいく」が、このようにマップを乱用することは間違っていると感じますが、理由は正確にはわかりません。2次元ゲームボードを関数型プログラミング言語で格納するためのより良い方法を探しています。