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. :-)
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(♠(_),♠(_),♠(_),♠(_),♠(_)).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With