use super::abstraction::Abstraction;
use super::abstractor::Abstractor;
use super::learner::Hierarchical;
use crate::cards::observation::Observation;
use crate::cards::street::Street;
use crate::mccfr::bucket::Bucket;
use crate::mccfr::bucket::Path;
use crate::mccfr::data::Data;
use crate::mccfr::edge::Edge;
use crate::mccfr::node::Node;
use crate::mccfr::player::Player;
use crate::mccfr::profile::Profile;
use crate::play::game::Game;
use crate::Probability;
use rand::distributions::Distribution;
use rand::distributions::WeightedIndex;
use rand::Rng;
use std::collections::BTreeMap;
pub struct Explorer(Abstractor);
impl Explorer {
pub fn download() -> Self {
log::info!("downloading abstraction lookup table for Explorer");
let mut map = BTreeMap::default();
map.extend(Hierarchical::load(Street::Turn).0);
map.extend(Hierarchical::load(Street::Flop).0);
Self(Abstractor(map))
}
pub fn sample(&self, node: &Node, profile: &Profile) -> Vec<(Data, Edge)> {
let mut children = self.children(node);
if node.player() == profile.walker() || children.is_empty() {
children
}
else if node.player() == Player::chance() {
let ref mut rng = profile.rng(node);
let n = children.len();
let choice = rng.gen_range(0..n);
let chosen = children.remove(choice);
vec![chosen]
}
else {
let ref mut rng = profile.rng(node);
let policy = children
.iter()
.map(|(_, edge)| profile.policy(node, edge))
.collect::<Vec<Probability>>();
let choice = WeightedIndex::new(policy)
.expect("at least one policy > 0")
.sample(rng);
let chosen = children.remove(choice);
vec![chosen]
}
}
fn children(&self, node: &Node) -> Vec<(Data, Edge)> {
let ref game = node.datum().game();
let ref past = node.history().into_iter().collect::<Vec<&Edge>>();
game.children()
.into_iter()
.map(|(g, a)| (g, Edge::from(a)))
.map(|(g, e)| self.explore(g, e, past))
.collect()
}
fn explore(&self, game: Game, edge: Edge, history: &Vec<&Edge>) -> (Data, Edge) {
let mut history = history.clone();
history.push(&edge);
(self.data(game, history), edge)
}
fn data(&self, game: Game, path: Vec<&Edge>) -> Data {
let bucket = self.bucket(&game, &path);
Data::from((game, bucket))
}
fn bucket(&self, game: &Game, path: &Vec<&Edge>) -> Bucket {
let path = self.path_abstraction(path);
let info = self.card_abstraction(game);
Bucket::from((path, info))
}
fn card_abstraction(&self, game: &Game) -> Abstraction {
let ref observation = Observation::from(game);
self.0.abstraction(observation)
}
fn path_abstraction(&self, path: &Vec<&Edge>) -> Path {
todo!("pseudoharmonic action mapping for path abstraction")
}
}