今取り組み中の以下の書籍で、油分け算というパズルが登場する。
- 作者: 坪崎誠司
- 出版社/メーカー: 株式会社プレスティージ
- 発売日: 2010/07/06
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
3リットル、5リットル、8リットルの容器があり、容器には目盛りがついていない。
8リットルの容器には満タンに酒が入っており、3リットルと5リットルの容器は空だ。
この状態から、5リットル容器に4リットル、8リットる容器に4リットルずつに分けたい。
【条件】目分量は禁止。つまり、一度注ぎ始めたら注ぎ元が空になるか注ぎ先が満タンになるまでストップできない。
と、ここまで説明しておいてなんだが、今回はパズルの解き方の話ではない。
試しにクラスモジュールを使って容器から容器へ注ぐ動作をエミュレートできるようにしてみたところ、メインコードが非常に人間の感覚に近いものになったので紹介したい。
まずCupという名前のクラスを用意し、以下のコードを張り付けておく。
Public 最大容量 As Integer Dim L As Integer Property Let 内容量(x As Integer) L = x End Property Property Get 内容量() As Integer 内容量 = L End Property Sub 注ぐ(注ぎ先 As Cup) If 注ぎ先 Is Me Then Exit Sub Do While 注ぎ先.内容量 < 注ぎ先.最大容量 And Me.内容量 > 0 Me.内容量 = Me.内容量 - 1 注ぎ先.内容量 = 注ぎ先.内容量 + 1 Loop End Sub
そして標準モジュールに書くコードはこちら。
Sub 手動油分け算() Dim L3 As New Cup: L3.最大容量 = 3 Dim L5 As New Cup: L5.最大容量 = 5 Dim L8 As New Cup: L8.最大容量 = 8 L8.内容量 = 8 L8.注ぐ L3 L3.注ぐ L5 L8.注ぐ L3 L3.注ぐ L5 L5.注ぐ L8 L3.注ぐ L5 L8.注ぐ L3 L3.注ぐ L5 Debug.Print "L8 "; L8.内容量 Debug.Print "L5 "; L5.内容量 Debug.Print "L3 "; L3.内容量 End Sub
…どうだろうか。
L3、L5、L8はそれぞれ、Cup型オブジェクトだ。
そして、L8.注ぐ L3という書き方は、L8からL3に注ぐという命令である。
条件である「一度注ぎ始めたら注ぎ元が空になるか注ぎ先が満タンになるまでストップできない。」という部分は、Cupクラスの内部でやってくれるので使う方は難しいことを考えなくて良い。
我ながら非常にスマートにまとまったと思う。
(もちろん、すごいのは私ではなくオブジェクト指向を生み出した先人達である。)
普段からJavaや.NETなどでオブジェクト指向に親しんでいる人からすると何をいまさらといった話かもしれないが、VBAでクラスモジュールを使ったサンプルは極めて少ないので、今後も使う機会があれば積極的に紹介していこうと思う。
追記
自分に注ぐと無限ループになることに気づき、Cupクラスのコードに以下を追加した。
If 注ぎ先 Is Me Then Exit Sub
このように、修正が局所的になるのもオブジェクト指向の良いところである。