小舟に乗って川を渡る #(人 狼 羊 菜) たち
Smalltalker's Salon Mailing List (SML) の 青木 淳さんの投稿より。
小舟に乗って川を渡ろうとしている人がいる。この人は狼と羊と菜を持っている。しかし、川を渡るための小舟には、一回に持って渡れるものがたった一つという制限がある。狼を持って渡ろうとすると、渡っている間に羊が菜を食べてしまう。菜を持って渡ろうとすると、渡っている間に狼が羊を食べてしまう。すべてのものを安全に対岸に渡すためのダイナミックモデル (状態遷移図) を作成せよ。
ここで、部分集合とその補集合について、その可否の判断の結果を出力するスクリプトを Squeak の Smalltalk で書いてみました。さっそく、ファウラーの「コレクションクロージャメソッド」にからめて作ったメモを活用。w 可否の判断には #noneSatisfy: を、組み合わせには #combinations:atATimeDo: を使ってみます。
| 構成 無効 可否出力 補集合 可否 | 構成 := #(人 狼 羊 菜). 無効 := #((狼 羊) (羊 菜) (狼 羊 菜)). World findATranscript: nil. 可否出力 := [: 集合 | 補集合 := 構成 reject: [: 要素 | 集合 includes: 要素]. 可否 := {集合. 補集合} noneSatisfy: [: 各々 | 無効 includes: 各々]. Transcript cr; show: 集合 printString. Transcript show: ' - '; show: 補集合 printString. Transcript show: ' -> '; show: 可否 printString]. 可否出力 value: #(). (1 to: 構成 size) do: [: nn | 構成 combinations: nn atATimeDo: [: 組み合わせ | 可否出力 value: 組み合わせ]]
なお、#combinations:atATimeDo: は第一引数に 0(抽出なし)を想定していないようなので、出力作業をブロックにして括りだし、ループの外で別途、空集合時の出力を得ました。
このスクリプトを do it したときの、トランスクリプト(Smalltalk システムの標準出力もどき)への出力はこんなかんじ。
#() - #(#人 #狼 #羊 #菜) -> true #(#人) - #(#狼 #羊 #菜) -> false #(#狼) - #(#人 #羊 #菜) -> true #(#羊) - #(#人 #狼 #菜) -> true #(#菜) - #(#人 #狼 #羊) -> true #(#人 #狼) - #(#羊 #菜) -> false #(#人 #羊) - #(#狼 #菜) -> true #(#人 #菜) - #(#狼 #羊) -> false #(#狼 #羊) - #(#人 #菜) -> false #(#狼 #菜) - #(#人 #羊) -> true #(#羊 #菜) - #(#人 #狼) -> false #(#人 #狼 #羊) - #(#菜) -> true #(#人 #狼 #菜) - #(#羊) -> true #(#人 #羊 #菜) - #(#狼) -> true #(#狼 #羊 #菜) - #(#人) -> false #(#人 #狼 #羊 #菜) - #() -> true
Nihongo7、および、日本語用リソースを追加した Squeak 3.8 で動作します。