use super::fallback_all_seats;
use super::uncontested;
use super::{Trie, call};
use crate::bidding::Rules;
use crate::bidding::constraint::{balanced, hcp, len, partner_suit_is, pred, support};
use crate::bidding::fallback::{Fallback, Undisturbed};
use contract_bridge::auction::Call;
use contract_bridge::{Bid, Strain, Suit};
use std::sync::Arc;
fn opener_rebid(major: Suit, resp: Suit) -> Rules {
let major_strain = Strain::from(major);
let resp_strain = Strain::from(resp);
let mut rules = Rules::new()
.rule(call(3, major_strain), 1.7, len(major, 6..) & hcp(15..))
.rule(call(3, resp_strain), 1.6, support(4..))
.rule(call(2, major_strain), 1.4, len(major, 6..))
.rule(
call(2, Strain::Notrump),
1.2,
balanced() & (hcp(12..=14) | hcp(18..=19)),
);
let other_suits: Vec<Suit> = [Suit::Clubs, Suit::Diamonds, Suit::Hearts, Suit::Spades]
.into_iter()
.filter(|&x| x != major && x != resp)
.collect();
let mut two_level_weight = 1.0_f32;
for &x in &other_suits {
let x_strain = Strain::from(x);
if x_strain > resp_strain {
rules = rules.rule(call(2, x_strain), two_level_weight, len(x, 4..));
two_level_weight -= 0.05;
}
}
for &x in &other_suits {
let x_strain = Strain::from(x);
if x_strain < resp_strain {
rules = rules.rule(call(3, x_strain), 0.9, len(x, 4..));
}
}
rules.rule(call(2, major_strain), 0.3, len(major, 5..))
}
fn responder_rebid(major: Suit, resp: Suit) -> Rules {
let major_strain = Strain::from(major);
let resp_strain = Strain::from(resp);
let mut rules = Rules::new()
.rule(call(3, major_strain), 2.0, len(major, 3..))
.rule(call(3, resp_strain), 1.2, len(resp, 6..))
.rule(
call(4, major_strain),
1.0,
partner_suit_is(major) & len(major, 2..),
)
.rule(call(3, Strain::Notrump), 0.8, hcp(13..));
for &x in &[Suit::Clubs, Suit::Diamonds, Suit::Hearts, Suit::Spades] {
if x != major && x != resp {
let x_strain = Strain::from(x);
rules = rules.rule(call(3, x_strain), 1.4, partner_suit_is(x) & support(4..));
}
}
rules
}
fn opener_third(major: Suit) -> Rules {
let major_strain = Strain::from(major);
Rules::new()
.rule(call(4, Strain::Notrump), 1.0, hcp(15..))
.rule(call(4, major_strain), 0.5, hcp(0..))
}
fn opener_rebid_1d_2c() -> Rules {
Rules::new()
.rule(call(3, Strain::Clubs), 1.6, support(4..))
.rule(
call(2, Strain::Notrump),
1.2,
balanced() & (hcp(12..=14) | hcp(18..=19)),
)
.rule(call(2, Strain::Hearts), 1.0, len(Suit::Hearts, 4..))
.rule(call(2, Strain::Spades), 0.95, len(Suit::Spades, 4..))
.rule(call(2, Strain::Diamonds), 1.0, len(Suit::Diamonds, 6..))
.rule(call(2, Strain::Notrump), 0.2, hcp(0..))
}
fn responder_rebid_1d_2c() -> Rules {
Rules::new()
.rule(
call(3, Strain::Diamonds),
1.2,
partner_suit_is(Suit::Diamonds) & len(Suit::Diamonds, 4..),
)
.rule(call(3, Strain::Clubs), 1.1, len(Suit::Clubs, 6..))
.rule(call(3, Strain::Notrump), 0.8, hcp(13..))
}
fn game_backstop() -> Rules {
Rules::new()
.rule(
call(4, Strain::Hearts),
0.7,
pred(|_, ctx| ctx.we_bid(Strain::Hearts)) & len(Suit::Hearts, 3..),
)
.rule(
call(4, Strain::Spades),
0.7,
pred(|_, ctx| ctx.we_bid(Strain::Spades)) & len(Suit::Spades, 3..),
)
.rule(call(3, Strain::Notrump), 0.5, hcp(0..))
}
pub(super) fn register(book: &mut Trie) {
for &major in &[Suit::Spades, Suit::Hearts] {
for &resp in &[Suit::Clubs, Suit::Diamonds, Suit::Hearts] {
if Strain::from(resp) >= Strain::from(major) {
continue;
}
register_major(book, major, resp);
}
}
register_minor(book);
}
fn register_major(book: &mut Trie, major: Suit, resp: Suit) {
let major_strain = Strain::from(major);
let resp_strain = Strain::from(resp);
let opener_calls = &[call(1, major_strain), call(2, resp_strain)];
let rebid = opener_rebid(major, resp);
let rebid_calls: Vec<Call> = {
let mut seen = std::collections::HashSet::new();
rebid
.rules()
.iter()
.filter_map(|r| {
let c = r.call();
if seen.insert(c) { Some(c) } else { None }
})
.collect()
};
super::insert_uncontested(book, opener_calls, rebid);
let three_m_bid = Bid::new(3, major_strain);
for &r_call in &rebid_calls {
let resp_calls = &[call(1, major_strain), call(2, resp_strain), r_call];
super::insert_uncontested(book, resp_calls, responder_rebid(major, resp));
if let Call::Bid(r_bid) = r_call
&& r_bid < three_m_bid
{
let third_calls = &[
call(1, major_strain),
call(2, resp_strain),
r_call,
call(3, major_strain),
];
super::insert_uncontested(book, third_calls, opener_third(major));
super::slam::install_rkcb(book, third_calls, major);
}
}
let anchor = uncontested(opener_calls);
fallback_all_seats(
book,
&anchor,
2,
Arc::new(Undisturbed),
Fallback::classify(game_backstop()),
);
}
fn register_minor(book: &mut Trie) {
let opener_calls = &[call(1, Strain::Diamonds), call(2, Strain::Clubs)];
let rebid = opener_rebid_1d_2c();
let rebid_calls: Vec<Call> = {
let mut seen = std::collections::HashSet::new();
rebid
.rules()
.iter()
.filter_map(|r| {
let c = r.call();
if seen.insert(c) { Some(c) } else { None }
})
.collect()
};
super::insert_uncontested(book, opener_calls, rebid);
for &r_call in &rebid_calls {
let resp_calls = &[call(1, Strain::Diamonds), call(2, Strain::Clubs), r_call];
super::insert_uncontested(book, resp_calls, responder_rebid_1d_2c());
}
let anchor = uncontested(opener_calls);
fallback_all_seats(
book,
&anchor,
2,
Arc::new(Undisturbed),
Fallback::classify(game_backstop()),
);
}