扑克手在Prolog

时间:2011-12-13 00:20:47

标签: prolog dcg

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

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

但并非所有情景;关于这里逻辑的任何指导?

由于

3 个答案:

答案 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/1three_of_a_kind/1的工作原理,让您完成添加pair/2的任务!使用剪切也很有趣,可以删除未使用的选择点。