How to avoid 'PL-Unit: incompatible test-options: ' ERROR

I’m using: SWI-Prolog version ???
SWI-Prolog version 7.6.4 for amd64
I want the code to:
Run plunit test without cause the ERROR shown in Topic.
But what I’m getting is:
evansl@lje-HP-ubuntu:~/dwnlds/bridge/pybridge/launchpad/oldlady/mylady/mylady-code/oldlady$ swipl -s handeval-test.plt -t “run_tests([handeval:ntp1])” ; cat handeval-test.plt
ERROR: /home/evansl/dwnlds/bridge/pybridge/launchpad/oldlady/mylady/mylady-code/oldlady/handeval-test.plt:16:
PL-Unit: incompatible test-options: [true(_1398=@=14),true(_1414=@=1)]
My code looks like this:

% your code here
% Old Lady
% Copyright (C) 2008 Paul Kuliniewicz <paul@kuliniewicz.org>
%
% PlUnit tests for handeval.pl.

:- use_module(library(plunit)).
:- use_module(handeval).

:- begin_tests(handeval).

evaluate_hand(Spades, Hearts, Diamonds, Clubs, HandInfo) :-
	expand_all_suits(Spades, Hearts, Diamonds, Clubs, AllCards),
	default_knowledge(HandInfo),
	interpret_hand(AllCards, HandInfo).

test(ntp1, [true(HCP =@= 14), true(LCP =@= 1)]) :-
	evaluate_hand([ace, king, 9], [ace, jack, 10, 8, 6], [7, 4], [queen, 7, 5], HandInfo),
	high_card_points(HandInfo, HCP),
	long_card_points(HandInfo, LCP).

:- end_tests(handeval).

The handeval.pl is:

% Old Lady
% Copyright (C) 2008 Paul Kuliniewicz <paul@kuliniewicz.org>
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 2, or (at your option)
% any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA.

% Basic hand evaluation framework, which should be usable for implementing
% any bidding system.  Based on Chapters 1 and 7 of The ABCs of Bridge,
% William Root, % 1998.

:- module(handeval, [
	default_knowledge/1,	% ?HandInfo
	default_everyone/4,	% ?SelfInfo, ?LeftInfo, ?PartnerInfo, ?RightInfo
	interpret_hand/2,	% +Cards, +HandInfo
	expand_suit/3,		% ?Suit, ?ListOfRanks, ?ListOfCards
	expand_all_suits/5,	% +SpadeRanks, +HeartRanks, +DiamondRanks, +ClubRanks, +ListOfCards

	points/2,		% +HandInfo, ?Points
	points/3,		% +HandInfo, +TrumpSuit, ?Points
	high_card_points/2,	% +HandInfo, ?HCP
	high_card_points/3,	% +HandInfo, +Suit, ?HCP
	long_card_points/2,	% +HandInfo, ?LCP
	trump_points/3,		% +HandInfo, +TrumpSuit, ?TP
	demi_quick_tricks/2,	% +HandInfo, ?DQT
	demi_quick_tricks/3,	% +HandInfo, +Suit, ?DQT
	suit_length/3,		% +HandInfo, +Suit, ?Length
	count_cards/3,		% +HandInfo, +Rank, ?Count

	tricks/2,		% +HandInfo, ?Tricks
	tricks/3,		% +HandInfo, +Suit, ?Tricks
	supp_tricks/3,		% +HandInfo, +PartnerSuit, ?Tricks
	supp_demi_tricks/4,	% +HandInfo, +PartnerSuit, +Suit, ?DemiTricks

	distribution/2,		% +HandInfo, +Distributions
	deny_distribution/2,	% +HandInfo, +Distributions
	balanced/1,		% +HandInfo
	balanced_or_semi/1,	% +HandInfo
	unbalanced/1,		% +HandInfo
	strong_suit/2,		% +HandInfo, +Suit
	not_strong_suit/2,	% +HandInfo, +Suit
	very_strong_suit/2,	% +HandInfo, +Suit
	not_very_strong_suit/2,	% +HandInfo, +Suit
	stopper/2,		% +HandInfo, +Suit
	no_stopper/2,		% +HandInfo, +Suit

	game/2,			% ?Level, ?Suit
	unfavorable_vuln/1,	% ?Vuln
	equal_vuln/1,		% ?Vuln
	favorable_vuln/1,	% ?Vuln

	preempt_level/3,	% +Vuln, ?Tricks, ?Level

	suit_lt/2,		% ?SuitA, ?SuitB
	suit_le/2,		% ?SuitA, ?SuitB
	rank_lt/2		% ?RankA, ?RankB
   ]).

:- use_module(library(clpfd)).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Notes and notation
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Cards are represented with the tuple:
%         card(Suit, Rank)
% where Suit = spades, hearts, diamonds, or clubs
%       Rank = ace, king, queen, jack, 10, 9, ..., 2

% Bids are represented with the tuple:
%         bid(Level, Trumps)
% where Trumps = no_trump, spades, hearts, diamonds, or clubs
%       Level = 7, 6, ..., 1
% The following tuples are also bids:
%         bid(pass)
%         bid(double)
%         bid(redouble)

% A player's hand is represented by a list of cards.

% Incomplete knowledge of a player's hand is represented with the tuple:
%         dealt(Spades, Hearts, Diamonds, Clubs)
% where each subterm is a 13-element list, one element for each card of
% that suit (from ace down to 2).  Each element is a CLP variable in the
% range 0..1, specifying whether the hand has that card in it.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Hand structure
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% default_knowledge(?HandInfo)
%     Initializes HandInfo with the bare minimum knowledge of the structure
%     of a hand.

default_knowledge(dealt(Spades, Hearts, Diamonds, Clubs)) :-
	length(Spades, 13),
	length(Hearts, 13),
	length(Diamonds, 13),
	length(Clubs, 13),
	append([Spades, Hearts, Diamonds, Clubs], AllCards),
	AllCards ins 0..1,
	sum(AllCards, #=, 13).

% default_everyone(?SelfInfo, ?LeftInfo, ?PartnerInfo, ?RightInfo)
%     Initializes a HandInfo for each player's hand, and assures that
%     their individual holdings are disjoint.

default_everyone(SelfInfo, LeftInfo, PartnerInfo, RightInfo) :-
	maplist(default_knowledge, [SelfInfo, LeftInfo, PartnerInfo, RightInfo]),
	maplist(all_cards, [SelfInfo, LeftInfo, PartnerInfo, RightInfo],
	                   [AllSelf, AllLeft, AllPartner, AllRight]),
	disjoint_holdings(AllSelf, AllLeft, AllPartner, AllRight).

% disjoint_holdings(?AllSelf, ?AllLeft, ?AllPartner, ?AllRight)
%     Given four lists of all-cards, assures that each card's CLP variable
%     is 1 in exactly one of the lists.

disjoint_holdings([], [], [], []) :- !.
disjoint_holdings([SelfH | SelfT], [LeftH | LeftT], [PartnerH | PartnerT], [RightH | RightT]) :-
	SelfH + LeftH + PartnerH + RightH #= 1,
	disjoint_holdings(SelfT, LeftT, PartnerT, RightT).

% fully_determined(+HandInfo)
%     Succeeds if all CLP variables in the hand have been fully determined.

fully_determined(HandInfo) :-
	all_cards(HandInfo, AllCards),
	forall(member(CardVar, AllCards),
		integer(CardVar)).

% not_fully_determined(+HandInfo)
%     Succeeds if there is at least one CLP variable in the hand that has
%     not yet been fully determined.

not_fully_determined(HandInfo) :-
	all_cards(HandInfo, AllCards),
	member(CardVar, AllCards),
	fd_var(CardVar).

% rank_index(+Rank, ?Index)
%     Looks up the sublist index for a card of the specified rank; this is
%     where the card's CLP variable will be in the proper suit's sublist in
%     a hand information term.

rank_index(ace, 0) :- !.
rank_index(king, 1) :- !.
rank_index(queen, 2) :- !.
rank_index(jack, 3) :- !.
rank_index(Rank, Index) :-
	Rank =< 10,
	Rank >= 2,
	Index is 14 - Rank.

% all_cards(+HandInfo, ?AllCards)
%     Concatenates the sublists for each suit into a single list of all
%     52 CLP variables, in the order spades, hearts, diamonds, clubs.

all_cards(dealt(Spades, Hearts, Diamonds, Clubs), AllCards) :-
	append([Spades, Hearts, Diamonds, Clubs], AllCards).

% suit_sublist(+Suit, +HandInfo, ?Sublist)
%     Looks up the sublist in a hand description that corresponds to the
%     specified suit.

suit_sublist(spades, dealt(Spades, _, _, _), Spades).
suit_sublist(hearts, dealt(_, Hearts, _, _), Hearts).
suit_sublist(diamonds, dealt(_, _, Diamonds, _), Diamonds).
suit_sublist(clubs, dealt(_, _, _, Clubs), Clubs).

% card_flag(+HandInfo, +Card, ?Flag)
%     Looks up the CLP variable in a hand that corresponds to the given card.

card_flag(HandInfo, card(Suit, Rank), Flag) :-
	suit_sublist(Suit, HandInfo, Sublist),
	rank_index(Rank, Index),
	nth0(Index, Sublist, Flag).

% interpret_hand(+Cards, +HandInfo)
%     Assigns concrete values to HandInfo's CLP variables to match the list
%     of known cards belonging to that hand.

interpret_hand([], _) :- !.
interpret_hand([Card | Cards], HandInfo) :-
	card_flag(HandInfo, Card, Flag),
	Flag #= 1,
	interpret_hand(Cards, HandInfo).

% expand_suit(?Suit, ?ListOfRanks, ?ListOfCards)
%     Takes a suit and a list of card ranks and converts that into a list
%     of card(Suit, Rank) terms.  This predicate is primarily for
%     convenience when writing test cases, to mimimize the verbosity of
%     test inputs.

expand_suit(_, [], []) :- !.
expand_suit(Suit, [Rank | Ranks], [card(Suit, Rank) | Cards]) :-
	expand_suit(Suit, Ranks, Cards).

% expand_all_suits(+SpadeRanks, +HeartRanks, +DiamondRanks, +ClubRanks, ?ListOfCards)
%     Takes four lists of ranks, one for each suit, and creates a list
%     of card(Suit, Rank) terms that correspond to them.  This predicate
%     is primarily for convenience when writing test cases, to minimize
%     the verbosity of test inputs.

expand_all_suits(SpadeRanks, HeartRanks, DiamondRanks, ClubRanks, ListOfCards) :-
	expand_suit(spades, SpadeRanks, SpadeCards),
	expand_suit(hearts, HeartRanks, HeartCards),
	expand_suit(diamonds, DiamondRanks, DiamondCards),
	expand_suit(clubs, ClubRanks, ClubCards),
	append([SpadeCards, HeartCards, DiamondCards, ClubCards], ListOfCards).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Basics of hand evaluation
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% points(+HandInfo, ?Points)
%     Tallies the total points in a hand, if no trump suit exists.

points(HandInfo, Points) :-
	high_card_points(HandInfo, HCP),
	long_card_points(HandInfo, LCP),
	Points #= HCP + LCP.

% points(+HandInfo, +TrumpSuit, ?Points)
%     Tallies the total points in a hand, in a trump contract.

points(HandInfo, TrumpSuit, Points) :-
	points(HandInfo, NTP),
	trump_points(HandInfo, TrumpSuit, TP),
	Points #= NTP + TP.

% high_card_points(+HandInfo, ?HCP)
%     Tallies the high-card points in a hand.

high_card_points(HandInfo, HCP) :-
	maplist(high_card_points(HandInfo), [spades, hearts, diamonds, clubs], SuitHCPs),
	sum(SuitHCPs, #=, HCP).

% high_card_points(+HandInfo, +Suit, ?HCP)
%     Tallies the high-card points within a single suit in a hand.

high_card_points(HandInfo, Suit, HCP) :-
	suit_sublist(Suit, HandInfo, [Ace, King, Queen, Jack | _]),
	HCP #= Ace * 4 + King * 3 + Queen * 2 + Jack.

% long_card_points(+HandInfo, ?LCP)
%     Tallies the long-card points in a hand.

long_card_points(HandInfo, LCP) :-
	maplist(long_card_points(HandInfo), [spades, hearts, diamonds, clubs], SuitLCPs),
	sum(SuitLCPs, #=, LCP).

% long_card_points(+HandInfo, +Suit, ?LCP)
%     Tallies the long-card points within a single suit in a hand.

long_card_points(HandInfo, Suit, LCP) :-
	suit_length(HandInfo, Suit, Length),
	LCP #= max(Length - 4, 0).

% trump_points(+HandInfo, +TrumpSuit, ?TP)
%     Tallies points from short non-trump suits if playing in trumps.

trump_points(HandInfo, TrumpSuit, TP) :-
	maplist(trump_points(HandInfo, TrumpSuit), [spades, hearts, diamonds, clubs], SuitTPs),
	sum(SuitTPs, #=, TP).

% trump_points(+HandInfo, +TrumpSuit, +InSuit, ?TP)
%     Tallies points from short non-trump suits in a single suit, if
%     playing in trumps.

trump_points(_, TrumpSuit, TrumpSuit, 0) :- !.
trump_points(HandInfo, _, InSuit, TP) :-
	suit_length(HandInfo, InSuit, Length),
	TP #= max(3 - Length, 0).

% demi_quick_tricks(+HandInfo, ?DQT)
%     Tallies the demi-quick-tricks in a hand -- i.e., quick tricks,
%     measured in units of 1/2 quick tricks, since the CLP solver only
%     handles integers, not fractional values.  For example, DQT = 3
%     means 1 1/2 quick tricks.

demi_quick_tricks(HandInfo, DQT) :-
	maplist(demi_quick_tricks(HandInfo), [spades, hearts, diamonds, clubs], SuitDQTs),
	sum(SuitDQTs, #=, DQT).

% demi_quick_tricks(+HandInfo, +Suit, ?DQT)
%     Tallies the demi-quick-tricks in a single suit.

demi_quick_tricks(HandInfo, Suit, DQT) :-
	suit_sublist(Suit, HandInfo, SuitedCards),
	SuitedCards = [Ace, King, Queen | _],
	suit_length(HandInfo, Suit, Length),
	DQT in 0..4,
	DQT #= 4 #<==> (Ace #= 1 #/\ King #= 1),					% AK   = 2   qt
	DQT #= 3 #<==> (Ace #= 1 #/\ King #= 0 #/\ Queen #= 1),				% AQ   = 1.5 qt
	DQT #= 2 #<==> ((Ace #= 1 #/\ King #= 0 #/\ Queen #= 0) #\/			% A    = 1   qt
	                (Ace #= 0 #/\ King #= 1 #/\ Queen #= 1)),			% KQ   = 1   qt
	DQT #= 1 #<==> (Ace #= 0 #/\ King #= 1 #/\ Queen #= 0 #/\ Length #>= 2),	% Kx   = 0.5 qt
	DQT #= 0 #<==> (Ace #= 0 #/\ King #= 0).					% else = 0 qt

% suit_length(+HandInfo, +Suit, ?Length)
%     Determines the length of a suit in the hand.

suit_length(HandInfo, Suit, Length) :-
	suit_sublist(Suit, HandInfo, SuitedCards),
	sum(SuitedCards, #=, Length).

% count_cards(+HandInfo, +Rank, ?Count)
%     Count the number of cards of a given rank held in the hand.

count_cards(HandInfo, Rank, Count) :-
	findall(Flag, card_flag(HandInfo, card(_, Rank), Flag), Flags),
	sum(Flags, #=, Count).

% tricks(+HandInfo, ?Tricks)
%     Count the tricks a hand is expected to get.
%
%     FIXME: Constrain HandInfo based on information provided by Tricks.

tricks(HandInfo, Tricks) :-
	fully_determined(HandInfo),
	maplist(tricks(HandInfo), [spades, hearts, diamonds, clubs], SuitTricks),
	sum(SuitTricks, #=, Tricks).
tricks(HandInfo, _) :-
	not_fully_determined(HandInfo).

% tricks(+HandInfo, +Suit, ?Tricks)
%     Count the tricks within a suit a hand is expected to get.
%
%     FIXME: Constrain HandInfo based on information provided by Tricks.

tricks(HandInfo, Suit, Tricks) :-
	fully_determined(HandInfo),
	suit_sublist(Suit, HandInfo, SuitedCards),
	sublist_to_holdings(SuitedCards, Held, NotHeld),
	held_tricks(Held, NotHeld, Tricks).
tricks(HandInfo, _, _) :-
	not_fully_determined(HandInfo).

% sublist_to_holdings(+SuitedCards, ?Held, ?NotHeld)
%     Convert a list of CLP variables into a list of the card ranks held and
%     not held.

sublist_to_holdings(SuitedCards, Held, NotHeld) :-
	sublist_to_holdings(SuitedCards, [ace, king, queen, jack, 10, 9, 8, 7, 6, 5, 4, 3, 2], Held, NotHeld).

% sublist_to_holdings(+SuitedCards, +Ranks, ?Held, ?NotHeld)
%     Convert a list of CLP variables into a list of the card ranks held and
%     not held.  Ranks is the name/value of each rank listed in SuitedCards.

sublist_to_holdings([], [], [], []).
sublist_to_holdings([0 | SuitedCards], [Rank | Ranks], Held, [Rank | NotHeld]) :-
	sublist_to_holdings(SuitedCards, Ranks, Held, NotHeld).
sublist_to_holdings([1 | SuitedCards], [Rank | Ranks], [Rank | Held], NotHeld) :-
	sublist_to_holdings(SuitedCards, Ranks, Held, NotHeld).

% held_tricks(+Held, +NotHeld, ?Tricks)
%     Determine the number of tricks that can be gotten in a suit, by
%     simulating "expected" play in that suit.  The two lists of cards
%     must be sorted from greatest to least.  This relaxes the pessimism
%     of held_tricks/4 a bit.

held_tricks(Held, NotHeld, Winners) :-
	held_tricks(Held, NotHeld, Winners, Losers),
	Losers #< 3 #\/ Winners + Losers #< 7.
held_tricks(Held, NotHeld, Tricks) :-
	held_tricks(Held, NotHeld, Winners, Losers),
	Losers #>= 3,
	Winners + Losers #>= 7,
	Tricks #= Winners + 1.

% held_tricks(+Held, +NotHeld, ?Winners, ?Losers)
%    Determine the number of tricks that will be won and lost in a suit,
%    by simulating "expected" play in that suit.  The two lists of cards
%    must be sorted from greatest to least.  Winners + Losers will be
%    the length of Held.  The simulation is pessimistic, assuming the
%    enemies will always play a higher card if they can.

held_tricks([], _, 0, 0).
held_tricks(Held, [], Winners, 0) :-
	length(Held, Winners).
held_tricks([Held | RestHeld], [NotHeld], Winners, Losers) :-
	rank_lt(Held, NotHeld),
	held_tricks(RestHeld, [], Winners, RestLosers),
	Losers #= RestLosers + 1.
held_tricks([Held | RestHeld], [NotHeld], Winners, Losers) :-
	rank_lt(NotHeld, Held),
	held_tricks(RestHeld, [], RestWinners, Losers),
	Winners #= RestWinners + 1.
held_tricks([Held | RestHeld], [NotHeld | RestNotHeld], Winners, Losers) :-
	rank_lt(Held, NotHeld),
	append(Remaining, [_], RestNotHeld),
	held_tricks(RestHeld, Remaining, Winners, RestLosers),
	Losers #= RestLosers + 1.
held_tricks([Held | RestHeld], [NotHeld | RestNotHeld], Winners, Losers) :-
	rank_lt(NotHeld, Held),
	append(Remaining, [_, _], [NotHeld | RestNotHeld]),
	held_tricks(RestHeld, Remaining, RestWinners, Losers),
	Winners #= RestWinners + 1.

% supp_tricks(+HandInfo, +PartnerSuit, ?Tricks)
%     Determine the number of tricks that can be gotten with a hand after
%     partner has made a preemptive opening in the given suit.  Basically,
%     quick tricks in the off suits, ace and/or king in partner's suit,
%     and if 3-card support for partner's suit, voids/singletons in off
%     suits.

supp_tricks(HandInfo, PartnerSuit, Tricks) :-
	maplist(supp_demi_tricks(HandInfo, PartnerSuit), [spades, hearts, diamonds, clubs], SuitDemiTricks),
	sum(SuitDemiTricks, #=, DemiTricks),
	Tricks #= DemiTricks / 2.

% supp_demi_tricks(+HandInfo, +PartnerSuit, +Suit, ?DemiTricks)
%     Determine the number of tricks that can be gotten with a single suit
%     after partner has made a preemptive opening.  "Demi" in order to
%     represent half tricks with integer CLP variables.
%
%     FIXME: Represent in a more CLP-way instead of having two cases for
%     the off-suit condition.

supp_demi_tricks(HandInfo, PartnerSuit, PartnerSuit, DemiTricks) :-
	suit_sublist(PartnerSuit, HandInfo, [Ace, King | _]),
	DemiTricks #= 2 * (Ace + King).
supp_demi_tricks(HandInfo, PartnerSuit, Suit, 2) :-
	dif(PartnerSuit, Suit),
	suit_length(HandInfo, PartnerSuit, SupportLength),
	SupportLength #>= 3,
	suit_length(HandInfo, Suit, Length),
	Length #=< 1.
supp_demi_tricks(HandInfo, PartnerSuit, Suit, DemiTricks) :-
	dif(PartnerSuit, Suit),
	suit_length(HandInfo, PartnerSuit, SupportLength),
	suit_length(HandInfo, Suit, Length),
	SupportLength #< 3 #\/ Length #> 1,
	demi_quick_tricks(HandInfo, Suit, DemiTricks).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% More sophisticated hand evaluation
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% distribution(+HandInfo, +Distributions)
%     Succeeds if the hand's distribution matches Distributions, which is one
%     or more A-B-C-D values.  Distribution can either be a single item or
%     a list of candidates.

distribution(HandInfo, A-B-C-D) :-
	distribution(HandInfo, [A-B-C-D]),
	!.
distribution(HandInfo, Distributions) :-
	maplist(suit_length(HandInfo), [spades, hearts, diamonds, clubs], SuitLengths),
	maplist(expand_distribution, Distributions, PermSets),
	union_permutation_sets(PermSets, PermSet),
	tuples_in([SuitLengths], PermSet).

% deny_distribution(+HandInfo, +Distributions)
%     Succeeds if the hand's distribution does *not* match Distributions,
%     which is one or more A-B-C-D values.  Distribution can either be a
%     single item or a list of candidates.

deny_distribution(HandInfo, A-B-C-D) :-
	deny_distribution(HandInfo, [A-B-C-D]),
	!.
deny_distribution(HandInfo, Distributions) :-
	maplist(suit_length(HandInfo), [spades, hearts, diamonds, clubs], SuitLengths),
	maplist(expand_distribution, Distributions, PermSets),
	union_permutation_sets(PermSets, PermSet),
	all_distributions(AllPerm),
	ord_subtract(AllPerm, PermSet, AllowedPermSet),
	tuples_in([SuitLengths], AllowedPermSet).

% expand_distribution(?Distribution, ?PermSet)
%     Converts between a distribution in A-B-C-D format (used in the
%     interface) and an ordered set of permutations of [A, B, C, D].

expand_distribution(A-B-C-D, PermSet) :-
	findall(Perm, permutation([A, B, C, D], Perm), PermList),
	list_to_ord_set(PermList, PermSet).

% union_permutation_sets(+PermSets, -PermSet)
% union_permutation_sets(+PermSets, +Acc, -PermSet)
%     Computes the set-union of a list of permutation sets.  The
%     non-accumulator version is a wrapper.

union_permutation_sets(PermSets, PermSet) :-
	union_permutation_sets(PermSets, [], PermSet).

union_permutation_sets([], Acc, Acc) :- !.
union_permutation_sets([Head | Tail], Acc, PermSet) :-
	ord_union(Head, Acc, NewAcc),
	union_permutation_sets(Tail, NewAcc, PermSet).

% all_distributions(-AllPerms)
%     Computes a list of all possible distribution permutations.

all_distributions(AllPerms) :-
	length(Dist, 4),
	Dist ins 0..13,
	sum(Dist, #=, 13),
	findall(Dist, label(Dist), AllPermsList),
	list_to_ord_set(AllPermsList, AllPerms).

% balanced(+HandInfo)
%     Succeeds if the hand's distribution is balanced: 4-3-3-3, 4-4-3-2, or
%     5-3-3-2.  In other words, no voids, no singletons, and at most one
%     doubleton.  Another horrid implementation.

balanced(HandInfo) :-
	distribution(HandInfo, [4-3-3-3, 4-4-3-2, 5-3-3-2]).

% balanced(+HandInfo)
%     Succeeds if the hand's distribution is balanced (4-3-3-2, 4-4-3-2, or
%     5-3-3-2) or semi-balanced (5-4-2-2 or 6-3-2-2).

balanced_or_semi(HandInfo) :-
	distribution(HandInfo, [4-3-3-3, 4-4-3-2, 5-3-3-2, 5-4-2-2, 6-3-2-2]).

% unbalanced(+HandInfo)
%     Succeeds if the hand's distribution is unbalanced (x-x-1-1 or x-x-2-1).

unbalanced(HandInfo) :-
	distribution(HandInfo, [
		10-1-1-1, 9-2-1-1, 8-3-1-1, 7-4-1-1, 6-5-1-1,
		8-2-2-1, 7-3-2-1, 6-4-2-1, 5-5-2-1]).

% strong_suit(+HandInfo, +Suit)
%     Succeeds if the suit's cards can be considered "strong".  This isn't
%     well-defined, so we'll consider a suit strong if it has high HCP.

strong_suit(HandInfo, Suit) :-
	high_card_points(HandInfo, Suit, HCP),
	HCP #>= 6.

% not_strong_suit(+HandInfo, +Suit)
%     Succeeds if strong_suit would fail.

not_strong_suit(HandInfo, Suit) :-
	high_card_points(HandInfo, Suit, HCP),
	HCP #< 6.

% very_strong_suit(+HandInfo, +Suit)
%     Succeeds if the suit's cards can be considered "very strong".  This isn't
%     well-defined, so we'll consider a suit strong if it has very high HCP.

very_strong_suit(HandInfo, Suit) :-
	high_card_points(HandInfo, Suit, HCP),
	HCP #>= 7.

% not_very_strong_suit(+HandInfo, +Suit)
%     Succeeds if very_strong_suit would fail.

not_very_strong_suit(HandInfo, Suit) :-
	high_card_points(HandInfo, Suit, HCP),
	HCP #< 7.

% stopper(+HandInfo, +Suit)
%     Succeeds if a hand has a stopper in the specified suit.

stopper(HandInfo, Suit) :-
	suit_sublist(Suit, HandInfo, [Ace, King, Queen | _]),
	Ace + King + Queen #>= 1.

% no_stopper(+HandInfo, +Suit)
%     Succeeds if a hand has no stoppers in the specified suit.

no_stopper(HandInfo, Suit) :-
	suit_sublist(Suit, HandInfo, [Ace, King, Queen | _]),
	Ace + King + Queen #= 0.

% game(?Level, ?Suit)
%     Succeeds if bid(Level, Suit) is a game-level contract.

game(5, clubs).
game(5, diamonds).
game(4, hearts).
game(4, spades).
game(3, no_trump).

% unfavorable_vuln(?Vuln)
%     Succeeds if the vulnerability is unfavorable.

unfavorable_vuln(vuln(yes, no)).

% equal_vuln(?Vuln)
%     Succeeds if the vulnerability is equal.

equal_vuln(vuln(no, no)).
equal_vuln(vuln(yes, yes)).

% favorable_vuln(?Vuln)
%     Succeeds if the vulnerability is favorable.

favorable_vuln(vuln(no, yes)).

% preempt_level(+Vuln, ?Tricks, ?Level)
%     Succeeds if a preemptive bid at Level is possible with the given number
%     of Tricks and the current vulnerability.

preempt_level(Vuln, Tricks, Level) :-
	preempt_overbid(Vuln, Overbid),
	Tricks + Overbid #= Level + 6.

% preempt_overbid(+Vuln, ?Overbid)
%     Determine how many tricks to overbid for picking the level of a
%     preemptive opening.

preempt_overbid(Vuln, 2) :-
	unfavorable_vuln(Vuln).
preempt_overbid(Vuln, 3) :-
	equal_vuln(Vuln).
preempt_overbid(Vuln, Overbid) :-
	favorable_vuln(Vuln),
	Overbid in 3..5.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Suit ordering
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% suit_lt(?SuitA, ?SuitB)
%     Succeeds if SuitA < SuitB.

suit_lt(SuitA, SuitB) :-
	suit_lt_imm(SuitA, SuitB).
suit_lt(SuitA, SuitB) :-
	suit_lt_imm(SuitA, SuitC),
	suit_lt(SuitC, SuitB).

% suit_lt_imm(?SuitA, ?SuitB)
%     Succeeds if SuitA < SuitB and there is no SuitC such that
%     SuitA < SuitC < SuitB.

suit_lt_imm(clubs, diamonds).
suit_lt_imm(diamonds, hearts).
suit_lt_imm(hearts, spades).

% suit_le(?SuitA, ?SuitB)
%     Succeeds if SuitA <= SuitB.

suit_le(Suit, Suit).
suit_le(SuitA, SuitB) :-
	suit_lt(SuitA, SuitB).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Rank ordering
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% rank_lt(?RankA, ?RankB)
%     Succeeds if RankA < RankB.

rank_lt(RankA, RankB) :-
	rank_lt_imm(RankA, RankB).
rank_lt(RankA, RankB) :-
	rank_lt_imm(RankA, RankC),
	rank_lt(RankC, RankB).

% rank_lt_imm(?RankA, ?RankB)
%     Succeeds if RankA < RankB and there is no RankC such that
%     RankA < RankC < RankB.

rank_lt_imm(2, 3).
rank_lt_imm(3, 4).
rank_lt_imm(4, 5).
rank_lt_imm(5, 6).
rank_lt_imm(6, 7).
rank_lt_imm(7, 8).
rank_lt_imm(8, 9).
rank_lt_imm(9, 10).
rank_lt_imm(10, jack).
rank_lt_imm(jack, queen).
rank_lt_imm(queen, king).
rank_lt_imm(king, ace).

% vim: ft=prolog

Seems you should follow the advice from docs, combining different variables by means of an arbitrary functor. This could do:

test(ntp1, [true(HCP-LCP =@= 14-1)]) :- ...

Thanks @CapelliC, that worked, although I see no where in:

doc_for_plunit or in library_plunit that
describes the solution you’ve given :frowning:

The condition can be simplified to true(HCP-LCP == 14-1).

1 Like

The bit that mentions combining multiple terms in the true(...) option is here.

2 Likes