はじめ
突然ですが私はマンカラというボードゲームが好きです。アフリカを起源とする(諸説ある)種まきのようなゲームで、より多くの石を取ったほうが勝ちという最古級のアブストラクトゲームです。最近では任天堂の「世界のアソビ大全」で収録されているのでご存知の方も多いと思います。
このゲームはいわゆる二人零和有限確定完全情報ゲームで、ランダム要素がなく完全に相手の手を読むゲームです。さらに、盤面の情報はそれぞれの穴の中にある石の数だけで、ルールも(比較的)簡単です。新しい言語で遊ぶときの練習台としてちょうどいいと考え、Elmで実装してみることにしました。
まとめ
マンカラにも色々あるのですが、今回は、マンカラの中でも日本で有名なカラハを作ってみました。
(「アソビ大全」で遊べるルールです。)
成果物はこのEllieで遊ぶことができます。
カラハのルールおさらい
- 6個 * 2列の穴に石が4つずつあり、両端にゴールとなる空の穴があります(向かって右手側の穴が自分のゴールです)。
- 自分側の穴の1つから石をとり、隣の穴に1個ずつ反時計回りに播きます。
- 播いた石の最後の1つが自分のゴールに入ると、もう一回手番を行えます。
- 播いた石の最後の1つが自陣の空の穴に入り、かつ向かいの(相手側の)穴に石があれば、それと自陣側の石(最後に播いたもの)を自分のゴールに移します。
- これを繰り返して、播けるものがなくなったら、その時点で自陣にある石の数が多いほうが勝ちです。
やったこと
マンカラ盤のModelをつくる
ざっくりとやりたいこととしては、
- マンカラをあそびたい
- ターン表示
- 終わったらどちらが勝ったか表示
を考えていたので、下のようなModelにしてみました。
type Player --プレイヤーを示す
= Myself
| Opposite
type PlayStatus --ゲームの進行状況を示す
= End Player
| Draw
| Playing
type alias Stage =
{ turn : Player --現在の手番
, field : List Int --各穴に入っている石の数
, lastSown : Maybe Int --最後に石を播いた穴のIndex
, remainStone : Int --これから播く石の残数
, status : PlayStatus --ゲームの進行状況
}
type alias Model =
Stage
fieldは下のように、0番目と7番目のindexがゴールの穴であるようなList Intを用意します。
[0, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4]
マンカラのゴールの穴は本来いろいろな機能があり、本当は別にしてやるべきだと思うのですが、カラハはゴールにも石を播くというルール上、こうすると楽でした。
lastSownとremainStoneは、ルール3. 4. を処理するために準備しました。
石を播く
石を播く処理は
prepareSowing : Int -> Stage -> Stage
progressSowing : Stage -> Stage
の2つの関数を用意しました。prepareSowingで指定した穴にある石を取り出してremainStoneに格納し、progressSowingで1つずつ播いていきます。石を取り出す穴の位置が確定すれば、播いた後の盤面も決まるので、こんなまだるっこしいことはしなくていいのですが、テストプレイしていると盤面が一気に変わって見にくかったのでこういう処理にしています。updateで画面更新をする際に、
progressSowing model, Task.perform (always (Spread position)) (Process.sleep 100)
として播いているときにちょっと時間を置いたりして1つずつ播いているように見せています。
画面を作る
elm-uiに興味があったので、せっかくだし使ってみました。パズルのようにcolumnやrowを組み合わせて作れるので、慣れれば面白い感じです。
めちゃ長くなったので詳細は割愛しますが、ゴールの要素はviewPointCell、それぞれの穴の要素はviewCell、といったかんじで部品ごとにつくっていって、だんだんまとめていくと書いていてわかりやすい感じでした。
ただ、センタリングのやり方(centerX, centerYなど)は意図通りに設定するのはかなり難儀しました。たぶん設定の重複とかいろいろあるはず……。
本当はやりたかったこと
- 石の情報を数字じゃなくて石を画像でわかりやすく表示したかった(svgとか)
- 全体的に極めてダサいのでなんとかしたかった
- 他のルールにも対応できる汎用性のある設計にしたかった
この辺は今後どうにかしたいですが、一区切りとするためにQiitaに供養することにしました。