The only difficulty comes from the Joker card, which can be used in place of any other card. As a result, we cannot use a notion of binary equivalence of two cards, which would not be transitive. Instead, we define an asymmetric relation agrees_with: for instance, the card Joker agrees with King, but not the converse. For convenience, we also define the relation disagree_with, which is the negation of the symmetric relation agrees_with.
let agrees_with x y = match x, y with Card u, Card v -> = | _, Joker -> true | Joker, Card _ -> false let disagrees_with x y = not (agrees_with y x);;
We actually provide a more general solution find_similar that searches sets of k similar cards among a hand. This function is defined by induction. If the hand is empty, there is no solution. If the first element of the hand is a Joker, we search for sets of k-1 similar elements in the rest of the hand and add the Joker in front of each set. Otherwise, the first element of hand is a regular card h: we first search for the set of all elements matching the card h in the rest of the hand; this set constitutes a solution if its size if at least k; then, we add all other solutions among the rest of the hand that disagree with h. Otherwise, the solutions are only those that disagree with h.
let rec find_similar k hand = match hand with | [] -> [] | Joker :: t -> (fun p -> Joker::p) (find_similar (k - 1) t) | h :: t -> let similar_to_h = h :: List.find_all (agrees_with h) t in let others = find_similar k (List.find_all (disagrees_with h) t) in if List.length similar_to_h >= k then similar_to_h :: others else others;; let find_carre = find_similar 4;;
Here is an example of search:
find_carre [ king Spade; Joker; king Diamond; Joker; king Heart; king Club; card Queen Spade; card Queen Club; club_jack ];;
- : card list list = [[Card {suit=Spade; name=King}; Joker; Card {suit=Diamond; name=King}; Joker; Card {suit=Heart; name=King}; Card {suit=Club; name=King}]; [Joker; Joker; Card {suit=Spade; name=Queen}; Card {suit=Club; name=Queen}]]