Prolog 选择与特定数字相加的数字(带扭曲)
我想在Prolog的帮助下,解开冒险游戏《不成文故事集2》中的一个谜语,进一步加深我对这门语言的了解 从9个数字中找出3个加起来就是41 你必须选择一个数字三次。每次选择都来自9个数字中的3个固定的不同分组。组的顺序是固定的。这些选项与一个减号或加号操作数组合,该操作数不是数字本身的符号,而是告诉它将如何与下一个数字(扭曲)进行代数链接 要从中选择的示例组:Prolog 选择与特定数字相加的数字(带扭曲),prolog,Prolog,我想在Prolog的帮助下,解开冒险游戏《不成文故事集2》中的一个谜语,进一步加深我对这门语言的了解 从9个数字中找出3个加起来就是41 你必须选择一个数字三次。每次选择都来自9个数字中的3个固定的不同分组。组的顺序是固定的。这些选项与一个减号或加号操作数组合,该操作数不是数字本身的符号,而是告诉它将如何与下一个数字(扭曲)进行代数链接 要从中选择的示例组: (65+) (17 -) (37+) (50-) (23 -) (27+) (33) (47) (45) 正确的解决办法是 (65+)
(65+) (23-) (47) = 41
i.e. 65 + 23 - 47 = 41
我下面的程序只找到以下不正确的解决方案
(17-)(23+)(47)=41
(17-)(23-)(47)=-53
这是不正确的,因为在分组中,只有(23-)可用,而不是(23+)
问题是运算符应用不正确。
所以我尝试通过让嵌套调用返回符号来修复它
addX(X,Y,S) :- X is S - Y.
e(X,S,R,SI,SO) :- ( (addX( X,65,S),R=65,SO= 1) ; (addX( X,17,S),R = 17,SO= -1) ; (addX( X,37,S),R = 37,SO= 1) ),X=0.
d(X,S,R,SI,SO) :- (addX( X,SI*50,S),R=50,SO= -1) ; (addX( X,SI*23,S),R = 23,SO= -1) ; (addX( X,SI*27,S),R = 27,SO= 1).
c(X,S,R,SI,SO) :- (addX( X,SI*33,S),R=33,SO= 1) ; (addX( X,SI*47,S),R = 47,SO= 1) ; (addX( X,SI*45,S),R = 45,SO= 1).
solve(Sum,Res3,Res4,Res5) :- e(Xe,Xd,Res5,1,SO5),d(Xd,Xc,Res4,SO5,SO4),c(Xc,Sum,Res3,SO4,SO3).
不幸的是,这会导致以下运行时错误:
?- solve(41,X1,X2,X3).
ERROR: is/2: Arguments are not sufficiently instantiated
感谢您的帮助 我会采取不同的方法。首先,我会选择一种更易于操作的数据表示形式。编号与操作的每个配对:
[(65,(+),(17,(-),(37,(+)])]
[(50,(-),(23,(-),(27,(+)])]
[33,47,45]
(N,(op))
。这个术语可以让我们很容易地选择数字和运算符。在Prolog中,由于语法原因,运算符周围需要额外的括号。您还可以选择一种形式,例如,[[65,+],[17,-],[37,+]
或[t(65,+),t(17,-),t(37,+)]
然后,为了查询问题,我选择将这组信息作为上述列表的列表传递。查询如下所示:
solve(41, [[(65,(+)),(17,(-)),(37,(+))],[(50,(-)),(23,(-)),(27,(+))],[(33),(47),(45)]], Result).
我可以选择将上述3个列表作为单独的参数传递,但是如果您想更改列表的数量,列表的列表更具可伸缩性。对于结果
,我希望看到的是从上述三个列表中依次选择一个项目的列表,因此该列表的评估值为41
然后,解决方案将遍历列表列表的每个元素,从每个元素中选择一个成员,评估该选择的结果,并将该结果与sum参数进行比较(在本例中,41
)
运行此查询:
| ?- solve(41, [[(65,(+)),(17,(-)),(37,(+))],[(50,(-)),(23,(-)),(27,(+))],[(33),(47),(45)]], R).
R = [(65,(+)),(23,(-)),47] ? ;
no
通过对第一个参数使用变量,可以看到可能的结果组合:
| ?- solve(S, [[(65,(+)),(17,(-)),(37,(+))],[(50,(-)),(23,(-)),(27,(+))],[(33),(47),(45)]], R).
R = [(65,(+)),(50,(-)),33]
S = 82 ? ;
R = [(65,(+)),(50,(-)),47]
S = 68 ? ;
R = [(65,(+)),(50,(-)),45]
S = 70 ? ;
...
此解决方案很容易扩展,只需改变上面1、2和3中的列表即可。您可以有两个或多个列表,也可以有不同长度的列表。
如果我可以窃取aBathologists
maplist
idea,这个解决方案的一个变体是:
solve(Sum, Choices, Results) :-
maplist(member, Results, Choices),
evaluate(Results, Sum).
evaluate([(N1,Op1), (N2,Op2)|Ops], Sum) :-
Term =.. [Op1, N1, N2], % form a term with first two
S is Term, % Evaluate the Term
evaluate([(S,Op2)|Ops], Sum). % Evaluate the remaining terms
evaluate([(N1,Op),N2], Sum) :- % Evaluate last term
Term =.. [Op, N1, N2], % Form a term
Sum is Term. % Check final sum
我会采取不同的方法。首先,我会选择一种更易于操作的数据表示形式。编号与操作的每个配对:
[(65,(+),(17,(-),(37,(+)])]
[(50,(-),(23,(-),(27,(+)])]
[33,47,45]
(N,(op))
。这个术语可以让我们很容易地选择数字和运算符。在Prolog中,由于语法原因,运算符周围需要额外的括号。您还可以选择一种形式,例如,[[65,+],[17,-],[37,+]
或[t(65,+),t(17,-),t(37,+)]
然后,为了查询问题,我选择将这组信息作为上述列表的列表传递。查询如下所示:
solve(41, [[(65,(+)),(17,(-)),(37,(+))],[(50,(-)),(23,(-)),(27,(+))],[(33),(47),(45)]], Result).
我可以选择将上述3个列表作为单独的参数传递,但是如果您想更改列表的数量,列表的列表更具可伸缩性。对于结果
,我希望看到的是从上述三个列表中依次选择一个项目的列表,因此该列表的评估值为41
然后,解决方案将遍历列表列表的每个元素,从每个元素中选择一个成员,评估该选择的结果,并将该结果与sum参数进行比较(在本例中,41
)
运行此查询:
| ?- solve(41, [[(65,(+)),(17,(-)),(37,(+))],[(50,(-)),(23,(-)),(27,(+))],[(33),(47),(45)]], R).
R = [(65,(+)),(23,(-)),47] ? ;
no
通过对第一个参数使用变量,可以看到可能的结果组合:
| ?- solve(S, [[(65,(+)),(17,(-)),(37,(+))],[(50,(-)),(23,(-)),(27,(+))],[(33),(47),(45)]], R).
R = [(65,(+)),(50,(-)),33]
S = 82 ? ;
R = [(65,(+)),(50,(-)),47]
S = 68 ? ;
R = [(65,(+)),(50,(-)),45]
S = 70 ? ;
...
此解决方案很容易扩展,只需改变上面1、2和3中的列表即可。您可以有两个或多个列表,也可以有不同长度的列表。
如果我可以窃取aBathologists
maplist
idea,这个解决方案的一个变体是:
solve(Sum, Choices, Results) :-
maplist(member, Results, Choices),
evaluate(Results, Sum).
evaluate([(N1,Op1), (N2,Op2)|Ops], Sum) :-
Term =.. [Op1, N1, N2], % form a term with first two
S is Term, % Evaluate the Term
evaluate([(S,Op2)|Ops], Sum). % Evaluate the remaining terms
evaluate([(N1,Op),N2], Sum) :- % Evaluate last term
Term =.. [Op, N1, N2], % Form a term
Sum is Term. % Check final sum
一个“声明性”的解决方案(或者是一个丑陋的黑客?)
:- op(100, xf, +).
:- op(100, xf, -).
test(X,Y,Z) :-
member(X, [65 +, 17 -, 37 +]),
member(Y, [50 -, 23 -, 27 +]),
member(Z, [33 , 47 , 45 ]),
combine(X, Y, Z, E), 41 is E.
combine(X -, Y -, Z, X - Y - Z).
combine(X -, Y +, Z, X - Y + Z).
combine(X +, Y -, Z, X + Y - Z).
combine(X +, Y +, Z, X + Y + Z).
一个更通用的解决方案出人意料地困难,尽管时间更短
test(X,Y,Z) :-
member(X, [65 +, 17 -, 37 +]),
member(Y, [50 -, 23 -, 27 +]),
member(Z, [33 , 47 , 45 ]),
eval([X, Y, Z], E), 41 is E.
%combine(X, Y, Z, E), 41 is E.
eval([H|T], E) :- H =.. [Op,N], eval(Op,N,T,E).
eval(Op,X,[H|T], E) :-
H =.. [Op1,M], Q =.. [Op,X,M], eval(Op1,Q,T,E)
; E =.. [Op,X,H].
一个“声明性”的解决方案(或者是一个丑陋的黑客?)
:- op(100, xf, +).
:- op(100, xf, -).
test(X,Y,Z) :-
member(X, [65 +, 17 -, 37 +]),
member(Y, [50 -, 23 -, 27 +]),
member(Z, [33 , 47 , 45 ]),
combine(X, Y, Z, E), 41 is E.
combine(X -, Y -, Z, X - Y - Z).
combine(X -, Y +, Z, X - Y + Z).
combine(X +, Y -, Z, X + Y - Z).
combine(X +, Y +, Z, X + Y + Z).
一个更通用的解决方案出人意料地困难,尽管时间更短
test(X,Y,Z) :-
member(X, [65 +, 17 -, 37 +]),
member(Y, [50 -, 23 -, 27 +]),
member(Z, [33 , 47 , 45 ]),
eval([X, Y, Z], E), 41 is E.
%combine(X, Y, Z, E), 41 is E.
eval([H|T], E) :- H =.. [Op,N], eval(Op,N,T,E).
eval(Op,X,[H|T], E) :-
H =.. [Op1,M], Q =.. [Op,X,M], eval(Op1,Q,T,E)
; E =.. [Op,X,H].
既然@capelical的解决方案并没有被证明是一个丑陋的黑客,而他的和@潜伏者的都足够优雅和有用,我想我可以冒昧地用一个真正丑陋的黑客来回答 这肯定不是解决问题的好办法。但它确实有效
puzzle(P) :-
P = [
['65 +', '17 -', '37 +'],
['50 -', '23 -', '27 +'],
['33', '47', '45']
].
puzzle_solution(Puzzle, Sum, Expr) :-
maplist(member, Ps, Puzzle),
atomic_list_concat(Ps, ' ', ExprAtom),
term_to_atom(Expr, ExprAtom),
Sum is Expr.
既然@capelical的解决方案并没有被证明是一个丑陋的黑客,而他的和@潜伏者的都足够优雅和有用,我想我可以冒昧地用一个真正丑陋的黑客来回答 这肯定不是解决问题的好办法。但它确实有效
puzzle(P) :-
P = [
['65 +', '17 -', '37 +'],
['50 -', '23 -', '27 +'],
['33', '47', '45']
].
puzzle_solution(Puzzle, Sum, Expr) :-
maplist(member, Ps, Puzzle),
atomic_list_concat(Ps, ' ', ExprAtom),
term_to_atom(Expr, ExprAtom),
Sum is Expr.
如果从第三组中选择一个数字,该数字不能为负数(第三组中没有符号)?第三组中没有附加运算符,因为运算符不是该数字的符号,但说明以下数字将如何以代数方式与其关联,并且示例中没有第四组。不幸的是,我的代码中的组数是硬编码的,我希望我能够