最近出现的代码挑战之一要求我解决最少量的输入材料,我可以使用这些材料来应用一组给定的反应并获得 1 个单位的输出材料。
例如,给定
10 ORE => 10 A
1 ORE => 1 B
7 A, 1 B => 1 C
7 A, 1 C => 1 D
7 A, 1 D => 1 E
7 A, 1 E => 1 FUEL
我们总共需要 31 块矿石来制造 1 种燃料(1 块用来生产单位 B,然后 30 块用来制造必需的 28 A)。
今年,我一直在努力拓展我的编程语言视野,所以我已经完成了 SML/NJ 的大部分挑战。这个似乎——<em>似乎——很适合 Prolog,考虑到我对它的了解很少:逻辑编程、约束求解等。
在一些帮助下,我能够整理出一个工作版本,并且我抽出时间阅读了一些关于 CHR 编程的教程。我想我基本上明白,下面,我们说如果我们知道 10 个a(1)
项目(这些被称为什么?证明?),那么我们可以将其替换为ore(10)
- 将扩展为 10 个单独的ore(1)
调用。
%prolog
:- module(ore, [ fuel/1 ]).
:- use_module(library(chr)).
:- use_module(library(clpfd)).
% constraint names
% ore and fuel are guaranteed
:- chr_constraint
ore/1,
a/1,
b/1,
c/1,
d/1,
e/1,
fuel/1.
% problem constraints
a(1),a(1),a(1),a(1),a(1),a(1),a(1),a(1),a(1),a(1) <=> ore(10).
b(1) <=> ore(1).
c(1) <=> a(7), b(1).
d(1) <=> a(7), c(1).
e(1) <=> a(7), d(1).
fuel(1) <=> a(7), e(1).
% decompositions (one per element???)
a(X) <=> X #> 1, Y #= X-1 | a(Y), a(1).
b(X) <=> X #> 1, Y #= X-1 | b(Y), b(1).
c(X) <=> X #> 1, Y #= X-1 | a(Y), a(1).
d(X) <=> X #> 1, Y #= X-1 | d(Y), d(1).
e(X) <=> X #> 1, Y #= X-1 | e(Y), e(1).
ore(X) <=> X#> 1, Y #= X-1 | ore(Y), ore(1).
% aggregation (for convenience)
% always present
:- chr_constraint ore_add/1, total_ore/1.
total_ore(A), total_ore(Total) <=> NewTotal #= A + Total, total_ore(NewTotal).
ore(1) <=> total_ore(1).
不过,如果能够编写以下内容,那就太好了:
a(10) <=> ore(10)
并以某种方式告诉 prolog,如果我“知道”,例如,a(8)
我仍然可以替换它ore(10)
(因为我需要 10 矿石来制造那些 8a,而有些只是浪费了)。
我认为如果我能做到这一点,我可以把这个输出
?- fuel(1).
ore:a(1),
ore:a(1),
ore:a(1),
ore:a(1),
ore:a(1),
ore:a(1),
ore:a(1),
ore:a(1),
ore:total_ore(21).
进入
?- fuel(1).
ore:total_ore(31).
如果我手动添加,ore:a(2)
到燃料查询中,我会得到正确的总矿石。
总结一下,
- 我如何表达我不能部分运行反应,但我可以运行反应以获得比我需要的更多的约束?换句话说,如果我需要
a(8)
,就足以知道我需要a(10)
吗?我认为,这也将允许我用类似的语言a(10) <=> ore(10)
而不是荒谬的语言来编写原始问题陈述a(1),a(1)...
。还是会? - 这会解决我的“搜索”问题,这样
fuel(1)
会给我ore:total_ore(31)
吗?
更新:我花了一些时间玩(1)来获得
%prolog
:- module(ore, [ fuel/1 ]).
:- use_module(library(chr)).
:- use_module(library(clpfd)).
% constraint names
% ore and fuel are guaranteed
:- chr_constraint
ore/1,
a/1,
b/1,
c/1,
d/1,
e/1,
fuel/1.
% problem constraints
a(X) <=> X #>= 1, X #=< 10 | ore(10).
b(1) <=> ore(1).
c(1) <=> a(7), b(1).
d(1) <=> a(7), c(1).
e(1) <=> a(7), d(1).
fuel(1) <=> a(7), e(1).
% decompositions (one per element???)
b(X) <=> X #> 1, Y #= X-1 | b(Y), b(1).
c(X) <=> X #> 1, Y #= X-1 | a(Y), a(1).
d(X) <=> X #> 1, Y #= X-1 | d(Y), d(1).
e(X) <=> X #> 1, Y #= X-1 | e(Y), e(1).
ore(X) <=> X#> 1, Y #= X-1 | ore(Y), ore(1).
% aggregation (for convenience)
% always present
:- chr_constraint ore_add/1, total_ore/1.
total_ore(A), total_ore(Total) <=> NewTotal #= A + Total, total_ore(NewTotal).
ore(1) <=> total_ore(1).
这total_ore(41)
为我的查询产生了。我相信“剩菜”正在转化为矿石,在这种情况下,这不是我想要的(尽管它当然是指定的)。s现在a
被删除得太早了——也就是说,这是正确的,但不是最小的。如何更喜欢整体反应?嗯……