使用邏輯式程式設計找出兇手!
Boddy 先生死于謀殺,現有六個嫌疑犯,每個人在不同的房間,每間房間各有一件可能的兇器,但不知道嫌疑犯、房間、兇器的對應關系。請根據條件和線索,找出誰是兇手。
本系列前面的文章:
邏輯式程式設計語言極簡實作(使用C#) - 1. 邏輯式程式設計語言介紹
這是一道Prolog經典的練習題,中文翻譯版來自阮一峰的文章《Prolog 語言入門教程》。
Boddy 先生死于謀殺,現有六個嫌疑犯,每個人在不同的房間,每間房間各有一件可能的兇器,但不知道嫌疑犯、房間、兇器的對應關系。請根據下面的條件和線索,找出誰是兇手。
六個嫌疑犯是三男(George、John、Robert)三女(Barbara、Christine、Yolanda)。
六個嫌疑犯分别待在六個房間:浴室(Bathroom)、飯廳(Dining Room)、廚房(Kitchen)、起房間(Living Room)、 儲藏室(Pantry)、書房(Study)。每間房間都有一件可疑的物品,可以當作兇器:包(Bag)、火槍(Firearm)、瓦斯(Gas)、刀(Knife)、毒藥(Poison)、繩索(Rope)。
所有線索如下:
線索一:廚房裡面是一個男人,那裡的兇器不是繩索、刀子、包和火槍。
線索二:Barbara 和 Yolanda 在浴室和書房。
線索三:帶包的那個人不是 Barbara 和 George,也不在浴室和飯廳。
線索四:書房裡面是一個帶繩子的女人。
線索五:起房間裡面那件兇器,與 John 或 George 在一起。
線索六:刀子不在飯廳。
線索七:書房和食品儲藏室裡面的兇器,沒跟 Yolanda 在一起。
線索八:George 所在的那間屋子有火槍。
線索九:Boddy 先生死在食品儲藏室裡,那裡的兇器是瓦斯。
直接上代碼:
其中一些輔助函數:
<code>k.Is(a, s)</code>: <code>a</code>是集合<code>s</code>的成員。
<code>k.Noto(g1, g2, ...)</code>: <code>g1</code>、<code>g2</code>……都不成立。NMiniKanren并沒有支援“非”運算,這裡用<code>If</code>方法模拟的,僅在一定場合下成立。
<code>k.Distincto(a, b, c, ...)</code>: <code>a</code>、<code>b</code>、<code>c</code>……兩兩不相等。
完整代碼在https://github.com/sKabYY/NMiniKanren/blob/master/NMiniKaren.Tests/Crime.cs
另外,最後使用<code>k.All</code>整合所有條件時,并不是按照順序寫的。了解NMiniKanren運作原理後會知道,這是因為不同順序會影響運作速度。大體上來說,應該盡可能讓分支較少的放前面。
點選運作,等待幾十秒,輸出結果:
兇手是Christine。