8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

正月休みに作ったゲームフレームワーク

Last updated at Posted at 2015-01-04

モジュール化の練習に。

年末にゲームを作った。
http://amo12937.github.io/minmax_web/

年末時点では、2014年内に公開することを優先させたため、モジュールとしてはうまく分離できなかった(目指してはいたが…)
年始の4日で、テストとリファクタリングを行い、いくつかの機能をモジュールとして bower に公開したのでここにそれを記しておく。

クラス図

スクリーンショット 2015-01-04 21.40.38.png

1回のゲームは、次の3つのオブジェクト間のメッセージパッシングによって進行する:

  • amo.module.game.game.Game
    • ゲームの進行役
    • ゲームの開始を受けて、適切なプレイヤーに play メッセージを送ることでゲームを進行させる(後述のシーケンス図参照)。
  • amo.module.game.player.Player
    • プレイヤー
    • 一つの戦略(player.strategy)に従って、1回の play を行う。
  • amo.minmax.module.board.Board
    • ゲーム盤
    • 盤面、スコア、現在のターン、選択可能な手の一覧など、ゲーム固有の要素を保持する。

ゲームのシーケンス図

1回のゲームの進行はこんな感じ。
スクリーンショット 2015-01-04 21.55.21.png

各種モジュール

angular.amo.module.game.game

game.GameFsm

game の進行をステートマシンで表現している。game の状態はとてもシンプルで、初期状態 INIT、プレイ中 PLAYING、正常終了 DONE、異常終了 STOPPED の4種類しかない。

スクリーンショット 2015-01-04 22.13.15.png

game.Game

GameFsm 自体を直接使うことはなく、Game が内部で使用している。使う側は、Game をインスタンス化し、start メッセージを呼ぶことで状態を遷移させていく。

method input output description
start - - ゲームを開始する際に呼び出す。このメソッドは一度だけ呼べば良い。
pause - - このメソッドが呼び出されると、次に resume が呼ばれるまでゲームを中断できる。ゲーム中断中も play は続行されるが、次の player へは処理は渡らず、delegate.notifyFinishedPlaying は呼ばれない。
resume - - 中断中に呼び出されると、ゲームが再開される。play が終了していた場合は delegate.notifyFinishedPlaying が呼び出され、次の player へ処理が渡る。
paused - boolean 中断中の場合に true を返す
stop - - ゲームを中止する。

game.Player

(これは、実際には JavaScript のコードとしては現れない。JavaScript にインターフェースを書く仕組みが無いため。)
game.Player は、Game から player への要求インターフェースである。必要なメソッドは以下のとおり

method required input output description
play o - finished 1回の play を要求し、その play によってゲームが終了したかどうかを返す。output は boolean でも良いが、ユーザーの入力を待ったりするために、promise を返してもよい。

game.delegate

Gameplayer のことを知らないので、次に誰が play するかを外部に問い合わせる。

method required input output description
getNextPlayer o - game.Player 次に play する player を返す

他にも、ゲームの進行にあわせて notify 系のメッセージを投げるが、多いので省略。

angular.amo.module.game.player

https://github.com/amo12937/angular.amo.module.game.player
プレイヤー自体は何もせず、単に戦略 player.strategy に従って、play を行う。

player.strategy.Man

Man は、人間の入力に従う戦略である。現在の盤面をもとにユーザーが手を入力し、それを持って 1度の play とする。

player.strategy.Com.AlphaBeta

Com.AlphaBeta は、アルファベータ法に基づくコンピュータの戦略である。アルファベータ法はミニマックスを改良したもので、ゲーム木の中の探索する必要のない枝を切って、効率化している。

コンピュータの手の選択がゲーム盤に依存していないのは、ゲーム盤が次のようにうまく抽象化されているからである。

player.Board

player.Board インターフェースは、プレイヤーがゲーム盤に求める要求インターフェースで、次のメソッドが必要である:

method description
current.turn() 現在の手番を表す値を返す
current.value(turn) 手番を受け取り、現在の評価値を返す
current.getSelectableList() 現在選択可能な手の一覧を返す
select(x) 手を表す値を受け取り、その手を受理したかどうかを返す
undo() 盤面の状態を一つ前に戻す
isFinished() ゲームが終了したかどうかを返す
  • 「手」x は、選択可能な一覧を順に select していくので、具体的には何なのかを問わない。それは Object であっても、Array であっても、数値や文字列であっても良い。
  • 「手番」turn は単に current.value を得るために使われるため、これも具体的に何なのかを問わない。
  • current.value は、数値を返す必要がある。(本当は順序が定義されたものであれば何でも良いがとしたかったが、内部で -InfinityInfinity と比較している。)

amo.minmax.module.board

minmax のゲーム盤 を表す。
このゲームにおいて、

  • turn: 現在の手番
    • 先手、または後手が交互に返される
  • value: ある手番の評価値
    • 自分のスコアから相手のスコアを引いた差である
    • この値を大きくすることがゲームの目的である
  • selectableList: 選択可能な手の一覧
    • 初手においては全てのパネル
    • 以降の後手は縦1列
    • 先手は横1列
    • ただし、一度選ばれたパネルは省く
  • isFinished: 終了条件
    • 選択可能な手が無くなった

となる。amo.minmax.module.board.Board で実装されている。

おしまい:次の一手

仕事では時間やコストの折り合いもあってあまりモジュールに分けての開発というのをやれていなかったが、今回は完全に自分の趣味での開発だったので、やりたいように出来た。まだテストとリファクタリングとモジュール化が徹底できていないので、継続してやっていきたい。

  • テスト
  • リファクタリング
  • モジュール化
  • 横展開
    • board を差し替えれば、「二人零和有限確定完全情報ゲーム」系を作ることができるので、オセロや、もう少し簡単な「Kalah」というのを作ってみたい。
8
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?