Question

I'm trying to learn Prolog. This are my first steps with this language. As exercise I want to write program which can recognize some poker hands (Straight flush, Four of a kind, Full house etc.).

I'm looking for good card representation in Prolog. I need to have possibility to check if one card is bigger than other, if cards are suited and so one.

I have started with code:

rank(2).
rank(3).
rank(4).
rank(5).
rank(6).
rank(7).
rank(8).
rank(9).
rank(t).
rank(j).
rank(q).
rank(k).
rank(a).

value(2, 2).
value(3, 3).
value(4, 4).
value(5, 5).
value(6, 6).
value(7, 7).
value(8, 8).
value(9, 9).
value(t, 10).
value(j, 11).
value(q, 12).
value(k, 13).
value(a, 14).
%value(a, 1).

suite(d).
suite(h).
suite(c).
suite(s).

rank_bigger(X, Y) :-
               value(X, A),
               value(Y, B),
               A > B.

That give mi possibility to check if rank A is bigger than for example J.

But I'm not sure how to represent single card. This representation should contains rank of card and also suit. There is also some issue with Ace because Ace have rank 14 but it can be also 1 in straight.

So my question is how to represents cards if I want to make rules like:

isStraight(C1, C2, C3, C4, C5) :- 
                                  [...]

or

isStraightFlush(C1, C2, C3, C4, C5) :- 
                                       [...]

I'm sure that this is kind of simple question if you know language, but it is not so easy to 'switch' thinking from languages like C or python. :-)

Was it helpful?

Solution

You could represent cards as terms with the form Rank-Suite.

In order to check if the cards come from the same suite define a predicate:

same_suit(_-S, _-S).

You can use this predicate to check if you have a flush:

?- Cards = [1-d, 2-d, 3-d, 4-d, 5-d], maplist(same_suit(_-S), Cards).
Cards = [1-d, 2-d, 3-d, 4-d, 5-d],
S = d.

In order to detect if you have a pair, two pairs, three of a kind, full house, or four of a kind you can just count the number of pairs in the hand and then map the result to the name of the hand.

% Count the number of pairs in the given list of cards.
count_pairs([], 0).

count_pairs([R-_ | Cs], Pairs) :-
    count_rank(R, Cs, RankCount),
    count_pairs(Cs, Pairs0),
    Pairs is RankCount + Pairs0.


% Count the number of cards with the given rank
count_rank(R, Cs, RankCount) :-
    count_rank(R, Cs, 0, RankCount).


count_rank(_, [], RankCount, RankCount) :- !.

count_rank(R, [R-_ | Cs], RankCount0, RankCount) :-
    !,
    RankCount1 is RankCount0 + 1,
    count_rank(R, Cs, RankCount1, RankCount).

count_rank(R, [_ | Cs], RankCount0, RankCount) :-
    count_rank(R, Cs, RankCount0, RankCount).


% Map the number of pairs to the name of the hand
pairs_hand(1, one_pair).
pairs_hand(2, two_pair).
pairs_hand(3, three_of_a_kind).
pairs_hand(4, full_house).
%pairs_hand(5, 'NOT POSSIBLE').
pairs_hand(6, four_of_a_kind).

Usage examples:

?- count_pairs([q-c, q-d, q-s, j-s, q-h], PairsCount), pairs_hand(PairsCount, Hand).
PairsCount = 6,
Hand = four_of_a_kind.

?- count_pairs([j-c, q-d, q-s, j-s, q-h], PairsCount), pairs_hand(PairsCount, Hand).
PairsCount = 4,
Hand = full_house.

?- count_pairs([j-c, q-d, q-s, j-s, 7-h], PairsCount), pairs_hand(PairsCount, Hand).
PairsCount = 2,
Hand = two_pair.

OTHER TIPS

You can use unicode and SWI to make pretty programs...

:- op(200, xf, ♥).
:- op(200, xf, ♦).
:- op(200, xf, ♣).
:- op(200, xf, ♠).
:- op(200, xf, ♡).
:- op(200, xf, ♢).
:- op(200, xf, ♧).
:- op(200, xf, ♤).

main :- print([2♠,3♦,'K'♥,10♠,3♣]),
        isFlush(2♠,3♦,'K'♥,10♠,3♣).

isFlush(♥(_),♥(_),♥(_),♥(_),♥(_)).
isFlush(♦(_),♦(_),♦(_),♦(_),♦(_)).
isFlush(♣(_),♣(_),♣(_),♣(_),♣(_)).
isFlush(♠(_),♠(_),♠(_),♠(_),♠(_)).

Use a list of pairs, card(rank, suite) for the hand. Define predicates to count the number of times each rank is repeated in a hand, sort inversely by count, and you have poker in [4,1], full in [3,2], trio in [3|_], etc. A little more work with sorting and counting will reveal flushes and straights. Instead of numerical values, use relationships higher(a,b) and equal(a,b) that apply to both ranks and to hands (and to suits, if that rule applies).

Because there are only five cards in a hand, you can get away with enumerating the possibilities instead of sorting... your choice.

Note: I removed the code samples because they contained too many syntax and logic errors.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top