|
あきらめも肝心だ |
||||||||
Never Give Up? |
||||||||
作り上げた Hanoi で遊んでみましたか。解法は説明したものの、はじめはなかなか難しいと思います。おもわず、Give Up してしまいたくなりませんか。しかし、このプログラムには Give Up がありません。途中で終わらせるということは考えていなかったからです。 そこで、今回はゲームの途中で Give Up をするときのことを考えていきましょう。Give Up は入力をするときに g を入れてもらうことにしたいと思います。こんな感じにしてみましょう。
入力処理は Player クラスの nextStep 関数の中で行うので、ここを改造していきましょう。下に示したのは nextStep 関数の一部分ですが、Give Up の入力がされた場合の部分だけを追加しています。
入力文字列と "g" とのの比較を 9 行目で行っています。文字列の比較には == を使用せずに equals 関数を使用します。== はオブジェクトが同じかどうかを示すもので、equals 関数は String オブジェクトが保持している文字列同士を比較します。 しかし、9 行目では equals 関数を使わないで、eqaulsIgnoreCase 関数を使っています。equalsIgnoreCase も文字列の比較を行うのですが、大文字と小文字を区別しないで比較します。ですから、この場合は入力文字列が "g" でも "G" でも true になります。 Give Up の入力を受け付けることはできましたが、これをどうやって Hanoi オブジェクトに伝えればいいでしょうか。nextStep 関数の戻り値は PileMovementInfo オブジェクトなので、そのままでは Give Up の情報を Hanoi オブジェクトに伝えることはできません。考えられる方法を列挙してみましょう。
PileMovementInfo クラスは移動に関する情報をもつクラスなので、まったく意味の異なる情報をもたせるのには抵抗があります。とすると、1 か 4 の方法が残ります。今まで発生した例外を処理することはありましたが、例外を投げることはやったことがないので、1 の方法を試してみましょう。 関数が例外を投げるためには throws を使用します。たとえば SomeException を投げる関数 bar は次のようになります。
例外を投げるには throw を使用します。例外もクラスなので、実際に例外を投げる場合は 5行目で行っているように、例外のオブジェクトを作らなければなりません。 例外の使い方が分かったので、Give Up の例外を作りましょう。単純に GiveUpException という名前にしましょう。例外は Exceptio の派生クラスにします。 GiveUpException クラスのソースはこちらです GiveUpException.java
Excpetion クラスはコンストラクタが引数なしと String オブジェクトが引数の 2 種類があります。GiveUpException クラスはこのコンストラクタを定義しなおしますが、スーパークラスのコンストラクタを呼ぶだけです。 GiveUpException を投げれるようにした nextStep 関数 (部分) を次に示します。
1 行目に throws を加え、10 行目で例外を投げるようにしました。 次は GiveUpExcpeiton オブジェクトを受け取るほうの、Hanoi クラスを改造しましょう。 nextStep 関数をコールしているのは startGame 関数の中です。例外を受け取れるように try ... catch を付け加えましょう。
オレンジ色の部分が付け加えたところです。Give Up の時はメッセージを出力して、return で関数を抜け出しています。
|
ハノイの塔を解いてみる | |||||||
Give Up できるようになったのはいいのですが、なんかものたりなくないですか。せっかくだから、アプリケーションでハノイの塔を解いてみましょう。 なんか難しそうな感じがしますが、意外と簡単にできます。一番はじめに説明したように n 枚の円盤の移動には、n - 1 枚の円盤を動かせるということを利用します。こんなときは再帰という手法を用いて解くことができます。再帰というのは自分で自分を呼び出すことです。たとえば、n の階乗を計算するにはこんなふうにします。
7 行目で自分自身の関数を呼んでいますが、このとき引数は n - 1 にしています。n の階乗を計算するときには、まず n - 1 の階乗を計算して、それに n を掛ければいいのです。 ただし、自分自身を呼ぶときに無限に呼び出しては答えが戻ってこないので、どこかで再帰を止める必要があります。これを行っているのが 3 行目から 5 行目の if 文です。n が 0 の時は、0! = 1 ですから 1 を返すようにして、再帰をストップしています。 これと同じことをハノイの塔でも行えばいいわけですね。もう一度ハノイの塔の解法を思い出してみてください。
ハノイの塔を解く関数を Hanoi クラスに定義しましょう。関数の定義を下に示しました。
towers はハノイの塔、n が枚数、start が現在の塔の番号、end が目的の塔、via が経由する塔だとします。すると上述した解法は次のようにすることができます。
忘れていけないのは再帰を止める条件を入れることです。n が 1 になれば、単純に移動するだけなので、再帰をストップさせることができます。このようにしてハノイの塔をアプリケーションで解くことができます。 それではソースを見ていきましょう。
3 行目の if 文は再帰を行うかどうかを判定しています。n が 0 ならばなにもしないで return します。n が 0 以上であれば、移動を行います。5 行目で n - 1 枚を経由塔に移動させています。via と end が入れ替わっているのにご注意ください。 8 行目で n 枚目の円盤を目的の塔に移動させます。移動させたら表示しましょう (10 行目)。この後スリープしているのは、こうしないとあまりにも速く表示が変化してしまうので、ゆっくりにさせるために入れてあります。特に処理の流れには関係ないので塔を表示しなければ入れなくてもかまいません。 そして、最後に n - 1 枚を目的の塔に移動させます (17 行目)。これでおしまいです。結構、あっけないと思いませんか。
|
●作成したソースファイルとコンパイルを行ったクラスファイルはここでダウンロードできます hanoi2.zip (Jan. 2001) |
|