2016-04-25 105 views
1

我正在製作一個簡單的紙牌遊戲,其中涉及在特定羣組中放置卡片。我想寫一個謂詞,試圖找出一組卡片是否可以安排到有效的組中。Prolog卡牌遊戲:有效套牌

有效組中的卡牌必須專門用於:(1)同一套牌的 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)現在使用剩餘的卡,嘗試使用我的卡連接謂詞將它們分配給這些組所需的規則

+0

不是很清楚你希望你的謂語工作。它是否具有卡片的第一個參數,並且作爲組的第二個參數? – 2016-04-25 16:44:19

+0

'S1 = S2,連續號碼(S1,S2)'很奇怪。如果S1和S2相等,則它們不能連續。你的意思是'連續數字(N1,N2)'? –

+0

是的,這是正確的托馬斯,我的意思是說我打電話給卡號的謂詞來檢查它們。 – John

回答

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(..., ...)]], []]. 

我用橋邏輯更合適的表示:卡(套裝,價值)

編輯

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運行,用HTML渲染被Qt處理:

enter image description here