Prolog纸牌游戏:有效套装

时间:2016-04-25 15:54:34

标签: list prolog

我正在制作一个简单的纸牌游戏,其中包括在特定群组中将牌放在桌子上。我想写一个谓词,试图找出一组卡片是否可以安排到有效的组中。

有效群组中的卡片必须完全符合以下条件: a)同一套装,连续数字(心1,2,3)或 b)不同的西装和相同的号码(1颗心,1颗钻石和1支球杆) 允许的最小组是三个。

第一步是定义卡片的内容,明显的方法是以谓词形式定义它们:

%hearts:
card(1,h).
card(2,h).
% etc.....

%diamonds:
card(1,d).
card(2,d).
%etc...

以及俱乐部和黑桃等等。

其次,我定义了一系列谓词来指定规则。卡如何连接,以及如何测试有效组。例如,我已经定义了以下内容来检查两张卡是否有效且具有相同的套装和相同的数字:

card_will_connect((N1,S1),(N2,S2)):-
    %firstly check that the cards exist:
    card(N1,S1),
    card(N2,S2),
    %same_suit
    S1=S2,
        consecutive_number(S1,S2).

我还编写了一些谓词,这些谓词通过一组卡片来查看它们之间的连接是否有效。

问题是,如果我有一组随机的卡片 - 如何在没有详尽搜索的情况下尝试以有效的方式对它们进行分组?

我的想法是: a)找出任何一个卡在该组内是否具有零可能的连接。如果失败了,就不要继续 b)找出任何卡只有1个有效连接,将它们移动到组 c)现在使用剩余的卡,尝试使用我的卡连接谓词将它们分配给这些组以满足所需的规则

1 个答案:

答案 0 :(得分:2)

我会对序列进行排序,并使用像findall / 3和append / 2这样的内置函数。然后验证谓词更容易编写:

% build a bridge deck
bridge_deck(Cs) :-
    findall(card(S,V), (member(S,[♥,♦,♣,♠]),between(1,13,V)), Cs).

% shuffle
bridge_hands([S,W,N,E]) :-
    bridge_deck(Cs),
%setrand(rand(1,2,3)), % get a known random set, to ease debugging
    random_permutation(Cs, RCs),
    maplist([H]>>length(H,13), [S,W,N,E]),
    append([S,W,N,E], RCs).

% behaves like a bridge player :)
hands_sorted(Sorted) :-
    bridge_hands(Hands),
    maplist(sort, Hands, Sorted).

group_hand(Hand, Groups) :-
    findall([A,B,C|D],
      (append([_,[A,B,C|D],_],Hand), 'same suit and consecutive numbers'([B,C|D],A)), Groups).

'same suit and consecutive numbers'([card(S,Y)|R], card(S,X)) :-
    succ(X,Y),
    'same suit and consecutive numbers'(R, card(S,Y)).
'same suit and consecutive numbers'([], _).

?- hands_sorted(Ps), maplist(group_hand, Ps, Gs), maplist(writeln, Gs).
Ps = [[card('♠', 1), card('♠', 4), card('♠', 5), card('♠', 11), card('♣', 2), card('♣', 4), card('♣', 10), card(..., ...)|...], [card('♠', 2), card('♠', 6), card('♠', 9), card('♠', 12), ...
Gs = [[], [], [[card('♥', 10), card('♥', 11), card('♥', 12)], [card('♥', 10), card('♥', 11), card('♥', 12), card(..., ...)], [card('♥', 11), card('♥', 12), card(..., ...)]], []].

我使用了更合适的桥接逻辑表示:card(Suit,Value)

修改

SWI-Prolog有一个很好的结构化输出设施。此代码段以可读形状布局桥接表:

:- use_module(library(http/html_write)).

bridge_cards :-
    hands_sorted(Hands),
    layout_table(Hands).

layout_table([S,W,N,E]) :-
    phrase(html([\css,
     table([
        tr([\empty,     \layout_hand(N),    \empty]),
        tr([\layout_hand(W),    \empty,     \layout_hand(E)]),
        tr([\empty,     \layout_hand(S),    \empty])
    ])]), Tokens),
    with_output_to(atom(X), print_html(Tokens)),
    win_html_write(X).

css --> html(style(type='text/css',
    ['.size{background-color:lightgrey;}'
    ,'.player{color:blue;}'
    ,'.value{text-align:right;background-color:lightgreen}'
    ])).

empty --> html(td([class=size],[])).

layout_hand(Cards) -->
    {findall(S-Vs, (
        member(S, [♣,♦,♥,♠]),
        findall(V, member(card(S,V),Cards), Vs)
    ), SuitesValues)},
    html(td([class=player], table(\layout_suits(SuitesValues)))).

layout_suits([]) --> [].
layout_suits([Suit-Values|SVs]) -->
    html(tr([td(Suit), \layout_values(Values)])),
    layout_suits(SVs).

layout_values([]) --> [].
layout_values([V|Vs]) --> html(td([class=value], \layout_value(V))), layout_values(Vs).

layout_value(V) --> {nth1(V,['A',2,3,4,5,6,7,8,9,'T','J','Q','K'],C)}, html(C).

我认为在HTML中获取输出特别方便,因为它允许尝试最小化,稍后 - 如果需要 - 将代码移植到SWI-Prolog HTTP服务器,以便在野外运行。

swipl-win运行的示例,由Qt处理HTML呈现:

enter image description here