2

我正在尝试编写一个谓词来分析常见的扑克手;例如,给定一个“卡片”列表,确定玩家是否有 4 个同类;3种;对等:我的想法是检查相似的排名,如果没有则删除:

这适用于四种([“A”,“J”,10,“Q”,“A”,“A”,“A”])

但不是所有情况;这里的逻辑有什么指导吗?

谢谢

4

3 回答 3

4

问题是你只检查手中的第一张牌是否在该组中出现了四次。您需要对所有卡执行此操作。

我将引入一个辅助谓词来计算您看到的牌张数,并让主谓词遍历手中的牌,直到找到一组四张牌:

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]。对眼睛更轻松!

于 2011-12-13T07:19:06.083 回答
3

考虑充分利用内置函数:当您对列表进行排序时,所有元素都会被分组,然后检查序列变得容易:

fourofakind(Hand) :-  % not intersted to what card is
 fourofakind(Hand, _).

fourofakind(Hand, C) :-
 msort(Hand, Sorted),
 append([_, [C,C,C,C], _], Sorted).

谓词有2种形式,后者还提供卡号。请使用msort调用:使用排序我们会丢失重复项...

于 2011-12-13T09:21:49.753 回答
2

正如 chac 指出的那样,为了再次引起我们在这篇文章中的辩论,您可以使用 append 成功地解析您的列表,一旦排序很容易。没有排序,你可以写:

fourofakind(Hand, X) :- append([_, [X], _, [X], _, [X], _, [X], _], Hand).

这基本上告诉序言:我希望我的手有 4 倍的子列表 [X],中间有任何东西。

或者,在他对另一个线程(DCGs)的回复中使用@false描述为一个非常吸引人的解决方案:

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/1pair/2工作!使用 cut 来删除未使用的选择点也会很有趣。

于 2011-12-13T09:53:55.163 回答