1use std::fmt::{Debug, Display, Formatter};
2use brydz_core::contract::{Contract, ContractMechanics};
3use brydz_core::error::{BridgeCoreError, ContractError, DistributionError, CardSetErrorGen};
4use brydz_core::error::ContractErrorGen::{BadTrick, CurrentSidePresume};
5use brydz_core::error::TrickErrorGen::DuplicateCard;
6use brydz_core::karty::cards::Card;
7use brydz_core::karty::set::{CardSet, CardSetStd};
8use brydz_core::meta::{CONTRACT_ACTION_ESTIMATED_SUIT_MAP_BOUND,  CONTRACT_ACTION_STACK_SIZE_BOUND};
9use brydz_core::player::side::{Side, SideMap, SIDES};
10use brydz_core::player::side::Side::{East, North, South, West};
11use log::debug;
12use smallvec::SmallVec;
13use brydz_core::karty::suits::SuitMap;
14use crate::actions::{CardPack, ActionOptimiser};
16use crate::explore::ExplorerStateUpdate::PlaceCard;
17use crate::node::TrickNode;
18
19#[derive(Debug, Clone)]
20pub struct ExplorerGameState<G: ActionOptimiser>{
21    contract: Contract,
22    node_stack: SmallVec<[TrickNode; CONTRACT_ACTION_STACK_SIZE_BOUND]>,
24    action_optimiser: G,
26    current_analysis_depth: u8,
27    }
30
31impl<G: ActionOptimiser> ExplorerGameState<G>{
32    pub fn new_checked(contract: Contract, initial_node: TrickNode) -> Result<Self, BridgeCoreError>{
33        let mut v = SmallVec::new();
34        v.push(initial_node);
35        let mut explorer_state = Self{contract, node_stack: v, current_analysis_depth:0, action_optimiser: G::default() };
37        match explorer_state.contract().current_trick().is_empty(){
41            true =>{
42                explorer_state.update_cache_new_trick()?;
43            },
44            false => {
45                explorer_state.update_cache_partial_trick()?;
46            }
47        }
48
49
50        explorer_state.check_valid().map(|()| explorer_state)
51
52    }
53    pub fn convert_optimiser<NG: ActionOptimiser>(self) -> Result<ExplorerGameState<NG>, BridgeCoreError>{
65        let n = ExplorerGameState::<NG>{
66            contract: self.contract,
67            node_stack: self.node_stack,
68            action_optimiser: NG::default(),
69            current_analysis_depth: self.current_analysis_depth,
70        };
71        let ap = match n.contract().current_trick().is_empty(){
72                true => {
73                    let mut opt = NG::default();
74                    opt.cache_on_trick_new(&n)?;
75                    opt
76                }
77                false => {
78                    let mut opt = NG::default();
79                    opt.cache_on_partial_trick(&n)?;
80                    opt
81                }
82            };
83        Ok(ExplorerGameState::<NG>{
84            contract: n.contract,
85            node_stack:  n.node_stack,
86            action_optimiser: ap,
87            current_analysis_depth: n.current_analysis_depth,
88        })
89    }
90
91    pub fn hands(&self) -> &SideMap<CardSetStd>{
92        self.node_stack.last().unwrap().hands()
93    }
94    pub fn hand(&self, side: Side) -> &CardSetStd {
95        &self.hands()[&side]
96    }
97
98    fn check_current_side(&self) -> Result<Side, ContractError>{
99        let node_side = self.node_stack.last().unwrap().current_side();
100        match self.contract.current_side() == node_side {
108            true => Ok(node_side),
109            false => Err(CurrentSidePresume(self.contract.current_side() ,
110            node_side))
111        }
112    }
113
114    pub fn contract(&self) -> &Contract{
122        &self.contract
123    }
124
125    pub fn check_valid(&self) -> Result<(), BridgeCoreError>{
126        self.check_current_side()?;
127        let all_hands = self.node_stack.last().unwrap().hands();
128        let hands_sum = all_hands[&North].union(&all_hands[&East])
129            .union(&all_hands[&South]).union(&all_hands[&West]);
130        let trick = self.contract.current_trick();
131        let mut card_numbers = all_hands.transform(|hand| hand.len());
133
134        for side in SIDES{
136            if let Some(card) = trick[side]{
137                if hands_sum.contains(&card){
138                    return Err(BadTrick(DuplicateCard(card)).into());
139                }
140                card_numbers[&side] += 1;
143            } else{
144
145                }
147        }
148        match card_numbers.are_all_equal(){
150            true => Ok(()),
151            false => Err(DistributionError::NotEqualCardNumbers(card_numbers).into())
152        }
153
154    }
155
156    fn place_card(&mut self, card: &Card) -> Result<(), BridgeCoreError>{
157        let mut node = *self.actual_node();
159        let side = self.check_current_side()?;
160        let completed_tricks = self.contract.count_completed_tricks();
161        let cards_in_trick = self.contract.current_trick().count_cards();
162        let called_suit = self.contract.current_trick().called_suit().map(|st| st.to_owned());
163        match node.hands()[&side].contains(card){
164            true => match self.contract.insert_card(side, *card){
165                Ok(s) => {
166                    match node.remove_card_current_side(card){
167                        Ok(()) => {
168                            debug!("{:?} placed card {:#} on table with {:?} completed tricks and {:?} cards in current trick (called suit: {:?}).",
169                                side, card, completed_tricks, cards_in_trick, called_suit);
170                            node.set_current_side(s);
171                            self.node_stack.push(node);
172
173                            Ok(())
174                        }
175                        Err(e) => {
176                            self.contract.undo()?;
177                            Err(e.into())
178                        }
179                    }
180
181                }
182                Err(e) => Err(e.into())
183            }
184            false => Err(CardSetErrorGen::CardNotInSet(*card).into())
185        }
186
187    }
188    pub fn actual_node(&self) -> &TrickNode{
189        self.node_stack.last().unwrap()
190    }
191
192    pub fn current_hand(&self) -> CardSetStd {
193        self.hands()[&self.contract().current_side()]
194    }
195    pub fn current_side(&self) -> Side{
196        self.contract.current_side()
197    }
198
199    fn update_cache_new_trick(&mut self) -> Result<(), BridgeCoreError>{
200        let mut preparer = std::mem::take(&mut self.action_optimiser);
201        preparer.cache_on_trick_new(self)?;
202        self.action_optimiser = preparer;
203        Ok(())
204    }
205
206    fn update_cache_dropped_trick(&mut self) -> Result<(), BridgeCoreError>{
207        let mut preparer = std::mem::take(&mut self.action_optimiser);
208        preparer.cache_on_trick_drop(self)?;
209        self.action_optimiser = preparer;
210        Ok(())
211    }
212
213    fn update_cache_partial_trick(&mut self) -> Result<(), BridgeCoreError>{
214        let mut preparer = std::mem::take(&mut self.action_optimiser);
215        preparer.cache_on_partial_trick(self)?;
216        self.action_optimiser = preparer;
217        Ok(())
218    }
219
220    pub(crate) fn update(&mut self, update: ExplorerStateUpdate) -> Result<(), BridgeCoreError> {
221        match update{
222            PlaceCard(card) => {
223
224                self.place_card(&card)?;
225                self.current_analysis_depth+=1;
226                if self.contract().current_trick().is_empty(){
227                   self.update_cache_new_trick()?;
229
230                }
231                Ok(())
232
233            },
234            ExplorerStateUpdate::Undo => {
235                let completed_tricks = self.contract.count_completed_tricks();
236                let cards_in_trick = self.contract.current_trick().count_cards();
237                debug!("Undoing on table with {:?} tricks completed and {:?} cards in current trick.",
238                    completed_tricks, cards_in_trick);
239                let update_cards_cache = self.contract().current_trick().is_empty();
240
241                match self.contract.undo(){
242                    Ok(_) => {
243                        self.node_stack.pop().unwrap();
244                        if update_cards_cache{
245                            self.update_cache_dropped_trick()?;
247                        }
248                        self.current_analysis_depth -= 1;
249                        Ok(())
250                    }
251                    Err(e) => Err(e.into())
252                }
253            }
254        }
255    }
256
257    pub fn available_actions(&self) -> SuitMap<SmallVec<[CardPack;CONTRACT_ACTION_ESTIMATED_SUIT_MAP_BOUND]>> {
258        self.action_optimiser.prepare_vec(self)
262
263
264    }
265
266
267
268}
269
270#[derive(Debug, Clone)]
271pub enum ExplorerStateUpdate{
272    PlaceCard(Card),
273    Undo
274}
275
276
277impl Display for ExplorerStateUpdate {
278    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
279        match self{
280            PlaceCard(c) => write!(f, "Update [ Card placed: {} ]", c),
281            ExplorerStateUpdate::Undo => write!(f, "Update [ Undo previous update ]")
282        }
283
284    }
285}
286#[derive(Clone, Debug)]
293pub struct DoubleDummyExplorerDomain {
294
295}
296#[cfg(test)]
386mod tests{
387    use brydz_core::{
388        cards::trump::Trump,
389        bidding::Bid,
390        contract::{Contract, ContractParametersGen, ContractMechanics},
391        player::side::{Side::*, SideMap},
392        karty::{suits::Suit::*, card_set, cards::{ACE_SPADES, QUEEN_SPADES, JACK_CLUBS, KING_CLUBS, ACE_HEARTS, KING_DIAMONDS, KING_HEARTS, JACK_DIAMONDS, ACE_DIAMONDS, ACE_CLUBS, QUEEN_HEARTS, QUEEN_CLUBS, KING_SPADES, QUEEN_DIAMONDS, JACK_SPADES, JACK_HEARTS}},
393       
394    };
395    use crate::{node::{TrickNode}, };
398    use crate::actions::DistinctCardGrouper;
399    use crate::explore::ExplorerStateUpdate;
400
401    use super::ExplorerGameState;
402
403    
404
405
406    #[test]
407    fn double_dummy_aupdate_state(){
408        
409        
410        let contract = Contract::new(
411             ContractParametersGen::new(West, Bid::init(Trump::Colored(Diamonds), 1).unwrap()));
412 
413        let hands = SideMap::new(
414            card_set![ACE_SPADES, QUEEN_SPADES, JACK_CLUBS, KING_CLUBS],
415            card_set!(ACE_HEARTS, KING_DIAMONDS, KING_HEARTS, JACK_DIAMONDS),
416            card_set![ACE_DIAMONDS, ACE_CLUBS, QUEEN_HEARTS, QUEEN_CLUBS],
417            card_set![KING_SPADES, QUEEN_DIAMONDS, JACK_SPADES, JACK_HEARTS ]);
418            
419        let node = TrickNode::new_checked(hands, contract.current_side()).unwrap();
420    
421        let mut explorer_state = ExplorerGameState::<DistinctCardGrouper>::new_checked(contract, node).unwrap();
422        assert_eq!(explorer_state.available_actions().map(|a|a.len()).sum(), 4);
423        assert!(explorer_state.update(ExplorerStateUpdate::PlaceCard(JACK_DIAMONDS)).is_err());
424        explorer_state.update(ExplorerStateUpdate::PlaceCard(KING_CLUBS)).unwrap();
425        assert_eq!(explorer_state.available_actions().map(|a|a.len()).sum(), 4);
426        explorer_state.update(ExplorerStateUpdate::PlaceCard(KING_DIAMONDS)).unwrap();
427        assert_eq!(explorer_state.available_actions().map(|a|a.len()).sum(), 2);
428        explorer_state.update(ExplorerStateUpdate::PlaceCard(QUEEN_HEARTS)).unwrap();
429        assert_eq!(explorer_state.available_actions().map(|a|a.len()).sum(), 4);
430        explorer_state.update(ExplorerStateUpdate::PlaceCard(JACK_HEARTS)).unwrap();
431        assert_eq!(explorer_state.contract.current_side(), East);
432        assert_eq!(explorer_state.available_actions().map(|a|a.len()).sum(), 3);
433        assert!(explorer_state.update(ExplorerStateUpdate::PlaceCard(KING_DIAMONDS)).is_err());
434        explorer_state.update(ExplorerStateUpdate::PlaceCard(JACK_DIAMONDS)).unwrap();
435        assert_eq!(explorer_state.available_actions().map(|a|a.len()).sum(), 1);
436        assert_eq!(explorer_state.contract.current_side(), South);
437        explorer_state.update(ExplorerStateUpdate::Undo).unwrap();
438        assert_eq!(explorer_state.contract.current_side(), East);
439        explorer_state.update(ExplorerStateUpdate::PlaceCard(KING_HEARTS)).unwrap();
440        assert_eq!(explorer_state.available_actions().map(|a|a.len()).sum(), 3);
441
442
443        
444
445    }
446}