bigsleepの日記

 | 

2015-05-10

リバーシのオンラインゲームを作った (3)

17:06

並行処理

(1) でリバーシロジック部分をFreeモナドで作りました。

CUI上で激弱なAIと対戦する場合の実装がこれです。

https://github.com/bigsleep/reversi/blob/master/Cui.hs

run :: Free Reversi a -> IO a

こういう型の実行用の関数を実装しています。

foldFreeという関数が使えるので、多分 Reversi a -> IO a を実装するのでもいいと思います。

http://hackage.haskell.org/package/free-4.11/docs/Control-Monad-Free.html#v:foldFree



オンラインで対戦させる場合は並行処理でこれを実行することになります。

サーバーの実装によってはリクエストごとや通信ごとに別プロセスだったりするかもしれませんが

warpを使った場合には同じプロセス内で別スレッド

それぞれのリクエスト時の処理が実行されると思います。

なのでMVarやTVarなどスレッド間で共有される変数を使って実装しました。

それとゲーム進行用のworkerのようなスレッドを使ってます。

これはそのほうが自分にはわかりやすく実装しやすかったんですが

workerとか無しでゲームを進行させることもできると思います。



オンライン化した方の実装はこれです。

https://github.com/bigsleep/reversi-online/blob/master/Game.hs

run :: Mode -> TVar GameContext -> Free Reversi ReversiResult -> IO ReversiResult

Modeは二人で対戦するかAIと対戦するかの設定です。

入出力はGameContextという共有変数を使ってやり取りするような感じになっています。

a が ReversiResult になってるのはタイムアウトした時にそこで終わりにするため

だったと思います。


タイムアウトの処理は入力用のMVarを用意して

threadDelayしてtryPutMVarで塞ぐスレッドを用意するような感じにしました。

タイムアウト用の関数がbaseにもあるのでこれ使ったほうがいいのかもしれません。

http://hackage.haskell.org/package/base-4.8.0.0/docs/System-Timeout.html#v:timeout



ゲーム進行用のworkerの実装はこれです。

https://github.com/bigsleep/reversi-online/blob/master/Worker.hs



workerなどを作らない場合は Free Reversi ReversiResult を共有変数に入れて

手番ごとに更新するような感じになるのかなと思います。


あと状態をメモリ上に持つと途中でサーバー再起動したりすると消えてしまって困るような気もします。

redisとかにも保存して、再起動した時に復元するとかできるといいのかもしれません。

トラックバック - http://d.hatena.ne.jp/bigsleep/20150510/1431245180
 | 
Connection: close