#はじめに
Scala独学で学んで1ヶ月くらい経ったので、実践ということで、ソケット通信を使ったオセロゲームを作って見ました。以下、学んだ点などつらつらまとめています。実装期間は、2週間程度です。(Scala単体の学習は除く)
[ソースコード]https://github.com/yuto226/Oselo
#What is Scala
Scalaは、Javaの親戚みたいなもんという認識です。
Scalaでできることは基本的にJavaでも出来ます。
Javaと最も違うと感じたところは、とにかくコード量が少ない、ガチガチのオブジェクト指向ではなく関数型のプログラミングも出来るというところでしょうか。
traitという機能が便利そうですが、今回キャパオーバーで使うに至れなかったので、今後改良したいと思います。
#環境
Mac OS X Sierra 10.12.6
InteliJ IDEA
Scala 2.12.7
jdk-9
*環境構築的な話は省きます。
#何を作ったか
最近、技術怠けしていたのでとにかく手を動かすという意味を込めてゲームでも作ろうかなと思いオセロを作りました。ついでに、ネットワーク処理関係の復習も兼ねてソケット通信も実装しています。
Scala を使ったのは、今後仕事でJavaを使う可能性が高かったので、何かないかと調べていたら近しいものがでてきたので、興味本位で手を出しました。
そんなモチベーションでやったのでScalaの良さ100%活かした実装までは至っていないかと思います。(とにかく動くことを目標にしてました)
ただ、Scala自体は結構使っていて書きやすく面白かったので、今後がっつり勉強していこうかと思います。
##簡単な設計(流れ)
ソケット通信ということで、クライアントサーバー形式です。
サーバー側がオセロの黒を担当し、クライアントが接続してきて白です。
ソケットを通して、どこに駒を置いたかの座標をメッセージでやりとりして、ゲームを進めていきます。
設計段階でGUI描画処理がきっと面倒なことになりそうだと思っていましたが、やはり後々面倒臭かったです(笑)
#実装
ソケット通信のプログラミング自体が久々だったので、ソケットをつないでメッセージのやりとりをするのが第一関門でした。さらに今回は、ゲームなのでGUIのための画面描画処理が入ります。スレッド一つでプログラムを走らせていると、どうしても限界がくるのでマルチスレッドを導入しました。サブのスレッドで、メッセージ受信を無限ループで待たせて、勝利判定や、画面描画は本スレッドでやらせる感じです。
こういういつ来るかわからないI/O処理を無限待ちさせるときは、マルチスレッド必須ですね。(初め、本スレッドで無限待ちさせていて当然ですが全く処理が進まなくなりました。。)
override def run(): Unit ={
createServer
receiveMsg
}
receiveMsg関数が無限待ち担当です。createServer関数は、初期設定でBufferedReaderなどを初期化しています。
JavaのThreadクラスを継承させて、本スレッドからstartメソッドで呼び出します。
基本的にこれをクライアントとサーバーで同じように待たせて、順番制御、勝利判定、メッセージ送信などを交互にやっていけばゲームとして成り立ちます。
画面描画自体は、scalafx(javafx)でやったのですが、scalafxはScene Builderというツールを使ってGUIでGUIの設計ができます。(X CodeでiPhoneアプリの画面作る時のような)
swingにはそういったものが無く、UIコードとデータ処理コードが入り混じった実装になってしまうそうなので、scalafx(javafx)の利点かなとは思います。
##ブロッキング・ノンブロッキング
最終的には、実装途中で、マルチスレッドにすれば、メッセージ受信やら画面描画は解決できる!と分かったのですが、調べて迷走している途中でブロッキング・ノンブロッキングという言葉も出てきて結構迷いました。(大学の講義で言葉を聞いた記憶はあった)
結論から言うと、ブロッキング・ノンブロッキングを考えるのは、サーバーに対してクライアントが複数アクセスする恐れがあるときは、ノンブロッキングを使った方が良い。とのことです。(違ったら教えてください・・)
コンピューターリソース的な観点から、複数来るクライアントに対して、いちいちスレッド・プロセスを割り当てていたら枯渇するのは目に見えているので、「監視」する処理を入れておいて、新規接続なら繋いで、メッセージが飛んできたら処理をして、といった風に実装するのが理想なようですね。ここら辺も落ち着いたらまた勉強しようかと思います。
#学びとまとめ
以下箇条書きでまとめます。
・無限待ちのI/O処理は、マルチスレッドを使う。
・マルチスレッドにおいて、画面描画処理をサブのスレッドで行う場合は、注意が必要。
・今回のように1対1の通信は、ブロッキング処理で大丈夫。複数クライアントが来るときは、ノンブロッキングで監視する処理を入れる。
・オセロの反転アルゴリズムめっちゃ大変。(ここのクラスのコード500行超えました。)
・Scala使い増えたらいいな。
マルチスレッドで画面描画を行う際のコードは、迷いそうなので残しておきます。
Platform#runLaterに対象関数を渡すことで解決しました。
Platform.runLater(() -> hogehoge())
今後、Scala勉強していきたいと思ったので、コード読んでくださった方は、ここはこうした方がいいよ!っていうのをコメントいただけると勉強の糧となります。宜しくお願いします。