我正在尝试编写一个谓词来分析普通的扑克牌;例如,给定一个“卡片”列表,识别玩家是否有4种; 3种;对等: 我的想法是检查类似的排名,如果没有,则删除:
这适用于fourofakind([“A”,“J”,10,“Q”,“A”,“A”,“A”])
但并非所有情景;关于这里逻辑的任何指导?
由于
答案 0 :(得分:3)
问题是你只检查手中的第一张牌是否在套装中出现了四次。你需要为所有卡片做到这一点。
我会介绍一个辅助谓词来计算你看过的牌数,然后让主谓词迭代到牌中,直到你找到一组四张牌:
four([H|T]) :- four0(H,1,T), !. % find a set of four Hs
four([_|T]) :- four(T). % else continue with remaining set
four0(_,4,_) :- !. % found four cards: stop
four0(X,I,[X|T]) :- !,I1 is I+1,four0(X,I1,T). % found another card: inc counter
four0(X,I,[_|T]) :- four0(X,I,T). % else continue
如果不是短名单,您可以通过例如记住已经检查过的卡片或删除它们来改进它。如果将列表排序为开头,它也会容易得多。
顺便说一句,您可以将原始第一个子句中的嵌套列表简化为[H,H,H,H]
,将第二个子句中的嵌套列表简化为[H1,H2|T]
。它的眼睛更容易!
答案 1 :(得分:2)
考虑好好使用内置函数:当您对列表进行排序时,所有元素都会被分组,然后检查序列是否变得容易:
fourofakind(Hand) :- % not intersted to what card is
fourofakind(Hand, _).
fourofakind(Hand, C) :-
msort(Hand, Sorted),
append([_, [C,C,C,C], _], Sorted).
谓词有2种形式,后者也提供卡片代码。请使用 msort 调用:使用sort我们会丢失重复项...
答案 2 :(得分:1)
正如chac指出并再次讨论我们在this post中进行的辩论,你可以使用append成功解析你的列表,一旦排序很容易。没有排序,你可以写:
fourofakind(Hand, X) :- append([_, [X], _, [X], _, [X], _, [X], _], Hand).
这基本上告诉prolog:我希望我的手有4次子列表[X],中间有任何东西。
或者,使用@false描述的另一个线程(DCG)his reply中非常具有图形吸引力的解决方案:
four --> ..., [X], ..., [X], ..., [X], ..., [X], ... .
... --> [] | [_], ... .
?- Xs = "bacada", phrase(four, Xs).
通过使用基本递归工作,你也可以避免使用太多的内置函数:
three_of_a_kind(Item, [Item|Tail]) :- pair(Item, Tail).
three_of_a_kind(Item, [_Item|Tail]) :- three_of_a_kind(Item, Tail).
pair(Item, [Item|Tail]) :- one(Item, Tail).
pair(Item, [_NotItem|Tail]) :- pair(Item, Tail).
one(Item, [Item|_Tail]).
one(Item, [_NotItem|Tail]) :- one(Item, Tail).
请注意,此处one/2
等同于member/2
的幼稚定义。我通过查看four_of_a_kind/1
和three_of_a_kind/1
的工作原理,让您完成添加pair/2
的任务!使用剪切也很有趣,可以删除未使用的选择点。