use contract_bridge::auction::{Auction, Call};
use contract_bridge::{AbsoluteVulnerability, Bid, Contract, Penalty, Seat, Strain};
use ddss::{TrickCountRow, TrickCountTable};
use pons::scoring::{final_contract, imps, ns_score_bid, ns_score_contract, ns_score_pd};
const fn bid(level: u8, strain: Strain) -> Call {
Call::Bid(Bid::new(level, strain))
}
fn auction(calls: impl IntoIterator<Item = Call>) -> Auction {
let mut auction = Auction::new();
auction.try_extend(calls).expect("test auction is legal");
auction
}
#[test]
fn test_final_contract_doubled() {
let auction = auction([
bid(2, Strain::Spades),
Call::Double,
Call::Pass,
Call::Pass,
Call::Pass,
]);
assert_eq!(
final_contract(&auction, Seat::West),
Some((
Contract::new(2, Strain::Spades, Penalty::Doubled),
Seat::West
))
);
}
#[test]
fn test_final_contract_bid_resets_penalty() {
let auction = auction([
bid(1, Strain::Hearts),
Call::Double,
bid(1, Strain::Spades),
Call::Pass,
Call::Pass,
Call::Pass,
]);
assert_eq!(
final_contract(&auction, Seat::North),
Some((
Contract::new(1, Strain::Spades, Penalty::Undoubled),
Seat::South
))
);
}
#[test]
fn test_final_contract_declarer_named_strain_first() {
let auction = auction([
bid(1, Strain::Hearts),
Call::Pass,
bid(4, Strain::Hearts),
Call::Pass,
Call::Pass,
Call::Pass,
]);
assert_eq!(
final_contract(&auction, Seat::North),
Some((
Contract::new(4, Strain::Hearts, Penalty::Undoubled),
Seat::North
))
);
}
#[test]
fn test_final_contract_pass_out() {
let auction = auction([Call::Pass; 4]);
assert_eq!(final_contract(&auction, Seat::North), None);
}
#[test]
fn test_ns_score_contract_signs_and_vulnerability() {
let row = TrickCountRow::new(9, 9, 9, 9);
let table = TrickCountTable([row; 5]);
let three_nt = Contract::new(3, Strain::Notrump, Penalty::Undoubled);
let by_south = Some((three_nt, Seat::South));
assert_eq!(
ns_score_contract(by_south, &table, AbsoluteVulnerability::NONE),
400
);
assert_eq!(
ns_score_contract(by_south, &table, AbsoluteVulnerability::NS),
600
);
let by_west = Some((three_nt, Seat::West));
assert_eq!(
ns_score_contract(by_west, &table, AbsoluteVulnerability::NS),
-400
);
assert_eq!(
ns_score_contract(by_west, &table, AbsoluteVulnerability::EW),
-600
);
assert_eq!(
ns_score_contract(None, &table, AbsoluteVulnerability::ALL),
0
);
}
#[test]
fn test_ns_score_bid_perfect_defense_doubling() {
let three_nt = Bid::new(3, Strain::Notrump);
let makes = TrickCountTable([TrickCountRow::new(9, 9, 9, 9); 5]);
assert_eq!(
ns_score_bid(
Some((three_nt, Seat::South)),
&makes,
AbsoluteVulnerability::NONE
),
400
);
let fails = TrickCountTable([TrickCountRow::new(7, 7, 7, 7); 5]);
assert_eq!(
ns_score_bid(
Some((three_nt, Seat::South)),
&fails,
AbsoluteVulnerability::NONE
),
-300
);
let undoubled = Contract::new(3, Strain::Notrump, Penalty::Undoubled);
assert_eq!(
ns_score_contract(
Some((undoubled, Seat::South)),
&fails,
AbsoluteVulnerability::NONE
),
-100
);
assert_eq!(ns_score_bid(None, &makes, AbsoluteVulnerability::ALL), 0);
}
#[test]
fn test_ns_score_pd_carries_table_double() {
let two_hearts_x = Contract::new(2, Strain::Hearts, Penalty::Doubled);
let bare = Bid::new(2, Strain::Hearts);
let makes = TrickCountTable([TrickCountRow::new(8, 8, 8, 8); 5]);
let pd_makes = ns_score_pd(
Some((two_hearts_x, Seat::South)),
&makes,
AbsoluteVulnerability::NONE,
);
assert_eq!(
pd_makes,
ns_score_contract(
Some((two_hearts_x, Seat::South)),
&makes,
AbsoluteVulnerability::NONE
),
);
assert!(
pd_makes
> ns_score_bid(
Some((bare, Seat::South)),
&makes,
AbsoluteVulnerability::NONE
)
);
let fails = TrickCountTable([TrickCountRow::new(7, 7, 7, 7); 5]);
let two_hearts = Contract::new(2, Strain::Hearts, Penalty::Undoubled);
assert_eq!(
ns_score_pd(
Some((two_hearts, Seat::South)),
&fails,
AbsoluteVulnerability::NONE
),
ns_score_bid(
Some((bare, Seat::South)),
&fails,
AbsoluteVulnerability::NONE
),
);
assert_eq!(
ns_score_pd(
Some((two_hearts_x, Seat::South)),
&fails,
AbsoluteVulnerability::NONE
),
ns_score_contract(
Some((two_hearts_x, Seat::South)),
&fails,
AbsoluteVulnerability::NONE
),
);
assert_eq!(ns_score_pd(None, &makes, AbsoluteVulnerability::ALL), 0);
}
#[test]
fn test_imps_scale() {
assert_eq!(imps(0), 0);
assert_eq!(imps(19), 0);
assert_eq!(imps(20), 1);
assert_eq!(imps(-20), -1);
assert_eq!(imps(440), 10);
assert_eq!(imps(-450), -10);
assert_eq!(imps(4000), 24);
assert_eq!(imps(-100_000), -24);
}