逻辑式编程语言极简实现(使用C#) - 2. 一道逻辑题:谁是凶手
本系列前面的文章:
这是一道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 先生死在食品储藏室里,那里的凶器是煤气。
NMiniKanren解题
直接上代码:
var George = "George";
var John = "John";
var Rebert = "Rebert";
var Barbara = "Barbara";
var Christine = "Christine";
var Yolanda = "Yolanda";
var res = KRunner.Run(10, (k, q) =>
{
// 男人集合
var manNames = new string[] { George, John, Rebert };
var man = k.List(manNames);
// 女人集合
var womanNames = new string[] { Barbara, Christine, Yolanda };
var woman = k.List(womanNames);
// 所有人集合
var person = k.List(manNames.Concat(womanNames).ToArray());
// 每个场所所在的人
var bathroom = k.Fresh();
var dining = k.Fresh();
var kitchen = k.Fresh();
var livingroom = k.Fresh();
var pantry = k.Fresh();
var study = k.Fresh();
// 物品持有者
var bag = k.Fresh();
var firearm = k.Fresh();
var gas = k.Fresh();
var knife = k.Fresh();
var poison = k.Fresh();
var rope = k.Fresh();
// 不同的人在不同的房间
var locationConst = k.Distincto(bathroom, dining, kitchen, livingroom, pantry, study);
// 不同的人持有的物品不同
var weaponConst = k.Distincto(bag, firearm, gas, knife, poison, rope);
// 变量X表示凶手
var X = k.Fresh();
// 线索
// 厨房里面是一个男人,那里的凶器不是绳索、刀子、包和火枪。
var clue1 = k.All(
k.Is(kitchen, man),
k.Noto(k.Eq(kitchen, rope), k.Eq(kitchen, knife), k.Eq(kitchen, bag), k.Eq(kitchen, firearm)));
// Barbara 和 Yolanda 在浴室和书房。
var clue2 = k.Any(
k.All(k.Eq(bathroom, Barbara), k.Eq(study, Yolanda)),
k.All(k.Eq(bathroom, Yolanda), k.Eq(study, Barbara)));
// 带包的那个人不是 Barbara 和 George,也不在浴室和饭厅。
var clue3 = k.Noto(
k.Eq(bag, Barbara), k.Eq(bag, George),
k.Eq(bag, bathroom), k.Eq(bag, dining));
// 书房里面是一个带绳子的女人。
var clue4 = k.All(k.Is(rope, woman), k.Eq(rope, study));
// 起居室里面那件凶器,与 John 或 George 在一起。
var clue5 = k.Any(k.Eq(livingroom, John), k.Eq(livingroom, George));
// 刀子不在饭厅。
var clue6 = k.Noto(k.Eq(knife, dining));
// 书房和食品储藏室里面的凶器,没跟 Yolanda 在一起。
var clue7 = k.Noto(k.Eq(study, Yolanda), k.Eq(pantry, Yolanda));
// George 所在的那间屋子有火枪。
var clue8 = k.Eq(firearm, George);
// Boddy 先生死在食品储藏室里,那里的凶器是煤气。
var clue9 = k.All(k.Eq(X, pantry), k.Eq(X, gas));
// 集合所有条件
return k.All(
k.Is(X, person),
k.Is(bathroom, person),
k.Is(dining, person),
k.Is(kitchen, person),
clue5,
k.Is(livingroom, person),
k.Is(pantry, person),
k.Is(study, person),
clue2,
locationConst,
k.Is(bag, person),
k.Is(firearm, person),
clue8,
k.Is(gas, person),
k.Is(knife, person),
k.Is(poison, person),
k.Is(rope, person),
weaponConst,
clue1,
clue3,
clue4,
clue6,
clue7,
clue9,
k.Eq(q, k.List(
bathroom, dining, kitchen, livingroom, pantry, study,
bag, firearm, gas, knife, poison, rope,
X)));
});
Console.WriteLine("(bathroom dining kitchen livingroom pantry study bag firearm gas knife poison rope X)");
KRunner.PrintResult(res);
其中一些辅助函数:
k.Is(a, s)
: a
是集合s
的成员。
k.Noto(g1, g2, ...)
: g1
、g2
……都不成立。NMiniKanren并没有支持“非”运算,这里用If
方法模拟的,仅在一定场合下成立。
k.Distincto(a, b, c, ...)
: a
、b
、c
……两两不相等。
完整代码在https://github.com/sKabYY/NMiniKanren/blob/master/NMiniKaren.Tests/Crime.cs
另外,最后使用k.All
整合所有条件时,并不是按照顺序写的。了解NMiniKanren运行原理后会知道,这是因为不同顺序会影响运行速度。大体上来说,应该尽可能让分支较少的放前面。
点击运行,等待几十秒,输出结果:
(bathroom dining kitchen livingroom pantry study bag firearm gas knife poison rope X)
[(Yolanda George Rebert John Christine Barbara John George Christine Yolanda Rebert Barbara Christine)]
凶手是Christine。
逻辑式编程语言极简实现(使用C#) - 2. 一道逻辑题:谁是凶手的更多相关文章
- 逻辑式编程语言极简实现(使用C#) - 3. 运行原理
本系列前面的文章: 逻辑式编程语言极简实现(使用C#) - 1. 逻辑式编程语言介绍 逻辑式编程语言极简实现(使用C#) - 2. 一道逻辑题:谁是凶手 第二天,好为人师的老明继续开讲他的私人课堂. ...
- 逻辑式编程语言极简实现(使用C#) - 4. 代码实现(完结)
本文是本系列的完结篇.本系列前面的文章: 逻辑式编程语言极简实现(使用C#) - 1. 逻辑式编程语言介绍 逻辑式编程语言极简实现(使用C#) - 2. 一道逻辑题:谁是凶手 逻辑式编程语言极简实现( ...
- 逻辑式编程语言极简实现(使用C#) - 1. 逻辑式编程语言介绍
相信很多朋友对于逻辑式编程语言,都有一种最熟悉的陌生人的感觉.一方面,平时在书籍.在资讯网站,偶尔能看到一些吹嘘逻辑式编程的话语.但另一方面,也没见过周围有人真正用到它(除了SQL). 遥记当时看&l ...
- Python 极简教程(十二)逻辑控制语句 if else
计算机软件之所以能够对不同的情况进行不同的处理,就是我们在编码的时候,通过逻辑控制语句,告诉软件在不同的情况下应该做什么处理. 比如我们在登录的时候,那么当你输入正确的账号密码和错误的账号密码,完全是 ...
- Atitit.编程语言的主要的种类and趋势 逻辑式语言..函数式语言...命令式语言
Atitit.编程语言的主要的种类and趋势 逻辑式语言..函数式语言...命令式语言 1. 编程语言的主要的种类 逻辑式语言..函数式语言...命令式语言 1 2. 逻辑式语言,,不必考虑实现过程而 ...
- 原生JS轮播-各种效果的极简实现
寒假持续摸鱼中~此为老早以前博客的重写,当时还是分开写的,这里汇总重写,正好复习一遍~ 春招我来了! 所有有意思的,一股脑先扔进收藏,然后再也不看哈哈,真是糟糕. 今日事,今日毕,说起来容易. 当时竟 ...
- HTML5 极简的JS函数
页面初始化 mui框架将很多功能配置都集中在mui.init方法中,要使用某项功能,只需要在mui.init方法中完成对应参数配置即可,目前支持在mui.init方法中配置的功能包括:创建子页面.关闭 ...
- 【股票盯盘软件】01_程序员炒股之开发一款极简风格的股票盯盘软件StockDog_V1.0.0.1
1.前言 话说最近一段时间受疫情的影响,股市各种妖魔横行.本人作为一个入股市不满三年的小韭菜,就有幸见证了好几次历史,也是满心惊喜,就权当是接受资本市场的再教育了吧. 小韭菜的炒股方法其实很简单,这两 ...
- 极简 Node.js 入门 - 4.2 初识 stream
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
随机推荐
- Spring Boot笔记(五) SpringBoot 集成Lombok 插件
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 为了减少代码量,为当前项目添加 lombok 来优雅编码 Lombok 插件安装: a . 添加依赖: ...
- Shell脚本 (一) 概述、解析器、脚本入门
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 一. Shell 脚本概述 1. Shell 的 含义: Shell 是一个用C语言编写的程序,它是用户 ...
- 第六届蓝桥杯JavaC组省赛真题
解题代码部分来自网友,如果有不对的地方,欢迎各位大佬评论 题目1.隔行变色 隔行变色 Excel表的格子很多,为了避免把某行的数据和相邻行混淆,可以采用隔行变色的样式. 小明设计的样式为:第1行蓝色, ...
- Java实现第八届蓝桥杯包子凑数
包子凑数 题目描述 小明几乎每天早晨都会在一家包子铺吃早餐.他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子.每种蒸笼都有非常多笼,可以认为是无限笼. 每当有顾客想买X个包子,卖包子的大叔 ...
- java解决poi导出excel文字水印,导出excel不可操作问题
首先需求是用户提出导出excel数据需使用水印备注其用途: 其实就是在导出excel的同时带有自定义文字水印的导出. 那么我们首先想到的肯定是以一个什么样的思路去解决该问题,首先查找poi导出exce ...
- “进大厂大半年,每个月都想走!”大公司 VS 小公司到底该如何选择?
前言 江湖风云不断,有人吐槽阿里996,也有人吐槽华为狼性文化,这不,就看到有腾讯员工吐槽“进腾讯大半年,每个月都想走!” “和我一样,进去一周就想走”.“我都陷入自我怀疑了,以为自己适应不了大公司” ...
- 多态的C语言实现版本
#ifndef _51_2_H #define _51_2_H typedef void Demo; typedef void Derived; Demo* Demo_create(int i,int ...
- WDCP配置ThinkPHP5伪静态隐藏index.php,出现“”解决重定向次数过”问题
站点域名的配置:xxx.com.conf server { listen 80; root /www/web/xxx_com/public_html; server_name xxx.com; ind ...
- linux下解决vim打开文件乱码现象
用VIM打开一个文件进行编辑时最下面的任务栏出现中文乱码,严重影响编写代码. 因为VIM默认的语言支持不行, 修改~/.vimrc 文件或/etc/vimrc 文件,添加一下代码: set encod ...
- 【 哈希和哈希表】Three Friends【进制哈希】
Three Friends 传送门:链接 (UPC)或 链接(大视野) 题目描述 Three friends like to play the following game. The first f ...