use brydz_core::karty::cards::Card;
use log::debug;
use smallvec::SmallVec;
use brydz_core::contract::{Contract, ContractMechanics};
use brydz_core::error::{BridgeCoreError, BridgeCoreErrorGen};
use brydz_core::karty::hand::CardSet;
use brydz_core::player::axis::Axis;
use brydz_core::player::axis::Axis::{NorthSouth, EastWest};
use brydz_core::player::side::Side;
use crate::actions::ActionOptimiser;
use crate::error::DoubleDummyError;
use crate::explore::{ExplorerGameState, ExplorerStateUpdate};
use crate::hash::NodeStoreTrait;
use crate::node::TrickNode;
use crate::actions::CardPackVec;
use crate::explore::ExploreOutput::Number;
use crate::explore::track::{CardPackResult, TrackStep};
#[derive(Debug, Clone)]
pub struct BinaryExplorer<G: ActionOptimiser, A: NodeStoreTrait>{
game_state: ExplorerGameState<G>,
north_south_target: u8,
#[allow(dead_code)]
node_store: A
}
impl<G: ActionOptimiser, A:NodeStoreTrait> BinaryExplorer<G, A>{
pub fn new_checked(contract: Contract, initial_node: TrickNode, north_south_target: u8) -> Result<Self, BridgeCoreError>{
Ok(Self{game_state: ExplorerGameState::new_checked(contract, initial_node)?,
node_store: A::default(), north_south_target
})
}
pub fn current_side(&self) -> Side{
self.state().contract().current_side()
}
pub fn explore_actions(&mut self) -> Result<bool, DoubleDummyError>{
let next_actions = self.state().available_actions();
debug!("Exploring actions for side: {:?}.\nTricks completed: {:?}.\nCurrent trick: {:#}. Available action groups: {:#}",
self.current_side(), self.state().contract().count_completed_tricks(),
self.state().contract().current_trick(), CardPackVec(next_actions.clone().into_iter().collect()));
if next_actions.and(SmallVec::is_empty){
debug!("No next actions: current side: {:?}, tricks completed: {:?}, cards in current trick: {:?}", self.current_side(), self.state().contract().count_completed_tricks(), self.state().contract().current_trick().count_cards());
return Ok((self.state().contract().total_tricks_taken_axis(Axis::NorthSouth) as u8) >= self.north_south_target)
}
if self.game_state.contract().current_trick().is_empty(){
let potential = <CardSet as Into<u64>>::into(self.game_state.actual_node().hands()[&self.current_side()]).count_ones() as u8;
let actual = self.game_state.contract().total_tricks_taken_axis(NorthSouth);
if actual as u8 >= self.north_south_target{
return Ok(true)
}
if actual as u8 + potential < self.north_south_target{
return Ok(false)
}
}
match self.current_side().axis() {
NorthSouth => {
for card_pack in next_actions {
self.update(ExplorerStateUpdate::PlaceCard(card_pack.lowest_card()))?;
let v = self.explore_actions()?;
self.update(ExplorerStateUpdate::Undo)?;
if v {
return Ok(true);
}
}
Ok(false)
},
EastWest => {
for card_pack in next_actions {
self.update(ExplorerStateUpdate::PlaceCard(card_pack.lowest_card()))?;
let v = self.explore_actions()?;
self.update(ExplorerStateUpdate::Undo)?;
if !v {
return Ok(false);
}
}
Ok(true)
}
}
}
pub fn hint(&mut self) -> Result<TrackStep, DoubleDummyError>{
let next_actions = self.state().available_actions();
debug!("Exploring actions for side: {:?}.\nTricks completed: {:?}.\nCurrent trick: {:#}. Available action groups: {:#}",
self.current_side(), self.state().contract().count_completed_tricks(),
self.state().contract().current_trick(), CardPackVec(next_actions.clone().into_iter().collect()));
if next_actions.and(SmallVec::is_empty){
debug!("No next actions: current side: {:?}, tricks completed: {:?}, cards in current trick: {:?}", self.current_side(), self.state().contract().count_completed_tricks(), self.state().contract().current_trick().count_cards());
todo!()
}
let mut track_step = TrackStep::new(self.current_side());
match self.current_side().axis(){
Axis::NorthSouth => {
for card_pack in next_actions{
self.update(ExplorerStateUpdate::PlaceCard(card_pack.lowest_card()))?;
let tmp_value = self.explore_actions()?;
if tmp_value{
track_step.push_and_hint(CardPackResult::new(card_pack, Number(1)));
} else {
track_step.push(CardPackResult::new(card_pack, Number(0)));
}
self.update(ExplorerStateUpdate::Undo)?;
}
Ok(track_step)
},
Axis::EastWest => {
for card_pack in next_actions{
self.update(ExplorerStateUpdate::PlaceCard(card_pack.lowest_card()))?;
let tmp_value = self.explore_actions()?;
if !tmp_value{
track_step.push_and_hint(CardPackResult::new(card_pack, Number(0)));
} else {
track_step.push(CardPackResult::new(card_pack, Number(1)));
}
self.update(ExplorerStateUpdate::Undo)?;
}
Ok(track_step)
}
}
}
pub fn update(&mut self, state_update: ExplorerStateUpdate) -> Result<(), BridgeCoreErrorGen<Card>> {
self.game_state.update(state_update)
}
pub fn state(&self) -> &ExplorerGameState<G> {
&self.game_state
}
}