From 35502541a2f55aee2a2e9b5a71c099450a7a9623 Mon Sep 17 00:00:00 2001 From: Felix Bauckholt Date: Tue, 26 Feb 2019 18:47:07 +0100 Subject: [PATCH] If a player discards because nobody needed a hint, make that common knowledge "Needing a hint" is defined as having a playable card, but not knowing any specific card is playable. Thus, if a player doesn't know any playable cards and someone else discards, the player (publicly) concludes that all their cards are unplayable. --- README.md | 4 ++-- src/strategies/information.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 45507c0..ae63bb0 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,8 @@ On seeds 0-9999, we have these average scores and win rates: |-------|---------|---------|---------|---------| |cheat | 24.8600 | 24.9781 | 24.9715 | 24.9570 | | | 90.52 % | 98.12 % | 97.74 % | 96.57 % | -|info | 21.9455 | 24.7136 | 24.8868 | 24.8976 | -| | 07.01 % | 79.46 % | 91.26 % | 91.91 % | +|info | 22.3360 | 24.7279 | 24.8889 | 24.8991 | +| | 09.98 % | 80.48 % | 91.37 % | 92.10 % | To reproduce: diff --git a/src/strategies/information.rs b/src/strategies/information.rs index d3d1ec4..eafcd51 100644 --- a/src/strategies/information.rs +++ b/src/strategies/information.rs @@ -617,6 +617,33 @@ impl InformationPlayerStrategy { }) } + fn update_noone_else_needs_hint(&mut self) { + // If it becomes public knowledge that someone_else_needs_hint() returns false, + // update accordingly. + for player in self.last_view.board.get_players() { + if player != self.last_view.board.player { + let knows_playable_card = self.get_player_public_info(&player).iter().any(|table| { + table.probability_is_playable(self.last_view.get_board()) == 1.0 + }); + if !knows_playable_card { + // If player doesn't know any playable cards, player doesn't have any playable + // cards. + let mut hand_info = self.take_public_info(&player); + for ref mut card_table in hand_info.iter_mut() { + let view = &self.last_view; + let possible = card_table.get_possibilities(); + for card in &possible { + if view.get_board().is_playable(card) { + card_table.mark_false(card); + } + } + } + self.return_public_info(&player, hand_info); + } + } + } + } + fn update_public_info_for_discard_or_play( &mut self, view: &BorrowedGameView, @@ -1015,6 +1042,7 @@ impl PlayerStrategy for InformationPlayerStrategy { let public_useless_indices = self.find_useless_cards(view, &self.get_my_public_info()); let useless_indices = self.find_useless_cards(view, &private_info); + // NOTE When changing this, make sure to keep the "discard" branch of update() up to date! let will_hint = if view.board.hints_remaining > 0 && self.someone_else_needs_hint() { true } else if view.board.discard_size() <= discard_threshold && useless_indices.len() > 0 { false } @@ -1083,6 +1111,12 @@ impl PlayerStrategy for InformationPlayerStrategy { known_useless_indices.len() as u32, value as u32 )); } + if self.last_view.board.hints_remaining > 0 { + // TODO It would be more information-efficient to do this before the call to + // update_from_hint_sum(). To do that, we would have to restructure decide() + // as well. + self.update_noone_else_needs_hint(); + } if let &TurnResult::Discard(ref card) = &turn_record.result { self.update_public_info_for_discard_or_play(view, &turn_record.player, index, card);