2017.04.11
第3回 コーディング面接の問題にチャレンジ!(その2)
前回は、実際にコードを書く問題を紹介しました。今回もコードを書く問題を紹介しますが、前回とは少し違ったタイプのものを紹介します。書籍『世界で闘うプログラミング力を鍛える本 ~コーディング面接189問とその解法』の問題7.8より出題です。
早速はじめよう
前回のように"紙"と"ペン"を用意してください。
紙とペンだけでオセロのゲームを実装するなんて無理だろうと思ってしまいそうですが、『オブジェクト指向で』とあるところがポイントです。オセロのゲームが題材になっていますが、問題の記述をよく見ると斜め方向から挟んだ場合の記述がありませんし、ルールについてはかなりあいまいです。ここでは、オセロゲームそのものよりも設計に対する考え方を問う問題と捉えることが重要です。
ゲーム内容の確認
まずは簡単な例からはじめましょう。オセロのゲームを次のように進めていったとします。
1. オセロ板の中央に白と黒の石を2つずつ置いて初期状態にする。黒が左上と右下になるように置いておく。
2. 黒の石を上から6、左から4の位置に置き、間にある白い石(上から5、左から4)を裏返し黒にする。
3. 白の石を上から4、左から3の位置に置き、間にある黒い石(上から4、左から4)を裏返し白にする。
この操作を終えると、オセロ板は次のようになります。
設計を考える
中心的なオブジェクトはおそらくゲーム、オセロ板、石(黒と白)、プレイヤーになるでしょう。これらをオブジェクト指向設計で的確に表現するにはどのようにすればよいでしょうか?
黒と白の石は別のクラスにすべきか?
1つヒントを見てみると、次のように書かれています。
まず最初に石の抽象クラスから派生した、黒い石と白い石のクラスがほしいと考えたくなるかもしれません。しかし、それはおそらく良い考えではありません。どの石も裏表の回転を頻繁に行いますから、本質的に同じオブジェクトを何度も消したり作ったりするというのは賢明ではなさそうです。単なる石のクラス(Piece)を作って、現在の色を表すフラグを持たせるだけでよいでしょう。
ゲームのクラスと別にオセロ板のクラスを作る必要があるか?
厳密に言えば、ゲームのクラス(Game)とオセロ板のクラス(Board)の両方を持つ必要はないでしょう。2つのオブジェクトを分離していれば、Boardクラスのロジック(石の配置など)とGameクラスのロジック(経過ターン数やゲームの流れなど)を分離することができます。しかし、これにはプログラムに追加のレイヤーが加わってしまうという欠点があります。Boardのメソッドを呼びたいだけであっても、Gameのメソッドを呼び出す必要が出てくるでしょう。今回の解法ではGameクラスとBoardクラスは別にしていますが、これについては面接官と議論しておきましょう。
スコアはどのクラスで保持するのか?
黒と白それぞれの石の数を何らかの形で記録しておくべきなのは間違いありません。どのクラスでこのようなスコア情報を保持しておくべきでしょうか? GameクラスかBoardクラスに保持する、あるいはPieceクラスに静的メソッドを使って保持するなど議論の余地はたくさんありますが、論理的にはオセロ板クラスに属する情報だと考えられるので、今回はBoardクラスでスコア情報を扱う実装にしました。PieceクラスやBoardクラスからcolorChangedとcolorAddedというメソッドを呼び出してスコア情報を更新するようにしています。
Gameクラスはシングルトンパターンで実装すべきか?
シングルトンパターンを用いてGameクラスを実装すれば、わざわざGameオブジェクトへの参照を渡さなくても、Gameクラスのメソッドをどこからでも簡単に呼び出すことができる利点があります。
しかし、シングルトンパターンで実装すると、Gameクラスのインスタンスを一度しか生成できなくなりますが、そのように仮定してもよいでしょうか? この点は面接官と議論すべきでしょう。設計の一例は次の通りです。
Boardクラスは石そのものの管理をします。ゲームのプレイ自体は扱わずに、Gameクラスに処理を任せています。
前述のとおり、石は単純に黒と白の値をとるColor型の変数を持たせたPieceクラスで実装しています。
プレイヤーを扱うクラスPlayerにはごく限られた情報だけを持たせています。得点情報すら持っていませんが、得点を得るメソッドはあります。Player.getScore()メソッドはGameオブジェクトから得点情報を得るようにしています。
実際に動くコード
今回書いたコードをよく見てみると、ところどころで{...}のように具体的な記述が省略されています。面接の限られた時間だけで完全に実装することは無理でしょうから、このように時間や各スペースを節約することも必要になります。
とはいえ、面接準備の段階では動くコードが手元にあった方が便利です。
この問題の解答コードは https://github.com/careercup/CtCI-6th-Edition/tree/master/Java/Ch%2007.%20Object-Oriented%20Design/Q7_08_Othello にありますので、気になった方はアクセスしてみてください。