2011年11月13日日曜日

論理パズル で Prolog のウォーミングアップ

テストケース(開発者が作る、いわゆる DeveloperTest のテストケースじゃなくて、開発はやらないテスト部隊が使うテストケース)を作るための小道具として Prolog を使うと便利かもと思って、自宅の環境に SWI-Prolog を用意してみた。

Fedora の「ソフトウェアの追加/削除」でリストアップされてたので、選択して適用するだけでインストールできた。

本当は、与えられた条件にしたがって、縦に要因、横にテストケースを並べた直交表もどきの表を生成するような仕組みを作りたいんだけど、その前にウォーミングアップしてみる。

手元にある論理パズル集の中から簡単なものを選んで、Prolog で解いてみる事にする。

お題は以下のようなもの。

  • とあるミスコンで、好美、恵美、明美、麻美、宏美が予選通過した
  • なかよし4人組が以下のように優勝者を予想した
    • まゆみ:好美と恵美ではないだろう
    • 大貴:恵美か明美だろう
    • 崇臣:好美か麻美だろう
    • やす美:好美と麻美ではないだろう
  • 予想が的中した人数は2名だった。
優勝したのはだれか?

あまり Prolog に詳しいわけではないけど、素朴に書くと以下のようになるのではないだろうか。
% 出場者
contestant(akemi). 
contestant(asami). 
contestant(hiromi). 
contestant(emi). 
contestant(yoshimi).

% 誰が誰の優勝を予想しているか
expect(mayumi, akemi). expect(mayumi, asami). expect(mayumi, hiromi).
expect(daiki, akemi). expect(daiki, emi).
expect(takaomi, yoshimi). expect(takaomi, asami).
expect(yasumi, emi). expect(yasumi, akemi). expect(yasumi, asami).

% 結局、優勝者は2名の予想者に予想された出場者だった
winner(Contestant):- expectors(Contestant, 2).

% 優勝者と予想者数の関係
expectors(Contestant, Count):-
  contestant(Contestant),  
  countExpectators(Contestant, [mayumi, daiki, takaomi, yasumi], Count).

% 優勝者を予想した人を数える
countExpectators(_, [], 0 ).
countExpectators(Contestant, [Expector|OtherExpectors], Count) :-
  expect(Expector, Contestant), 
  countExpectators(Contestant, OtherExpectors, Count2),
  Count is Count2 + 1.
countExpectators(Contestant, [Expector|OtherExpectors], Count) :-
  not(expect(Expector, Contestant)),
  countExpectators(Contestant, OtherExpectors, Count).
これを SWI-Prolog に読ませて、以下のようにすると答えが出る。
?- winner(Winner).
Winner = emi .
ちなみに明美の優勝を予想した人数は、上で定義した述語 expectors 使って、以下のように求められる。
?- expectors(akemi, Count).
Count = 3 .
逆に、同じ expectors を使って、3名が優勝を予想した出場者を求めることもできる。これがPrologの面白いところでもある。
?- expectors(W, 3).
W = akemi ;
W = asami ;
false.

====

ソフトウェアのテストケースを作ろうとすると、あるテスト対象の振る舞いに影響を与える条件群について、すべての条件を掛け合わせると現実的でないテストケース数になったりする

なので、少ないテストケース数でなるべく各条件を網羅できるように工夫する事になるんだけど、その辺りの作業がちょっとしたパズルみたいになってくる事がある。

で、せっかくプログラミングを生業としているのだから、プログラムでなんとかしようかって発想になるんだけど、手続き型言語を使うと、やりたい事とコード上の表現がいまいち直截性に欠けていたりする。

あまり流行ってはいなけど、こういう時は Prolog が割と使えそうな気がしないでもない。

0 件のコメント:

コメントを投稿