use super::bucket::Bucket;
use super::player::Player;
use crate::mccfr::data::Data;
use crate::mccfr::edge::Edge;
use crate::play::continuation::Transition;
use crate::Utility;
use petgraph::graph::DiGraph;
use petgraph::graph::NodeIndex;
use petgraph::Direction::Incoming;
use petgraph::Direction::Outgoing;
use std::ptr::NonNull;
pub struct Node {
graph: NonNull<DiGraph<Self, Edge>>,
index: NodeIndex,
datum: Data,
}
impl From<(NodeIndex, NonNull<DiGraph<Node, Edge>>, Data)> for Node {
fn from((index, graph, datum): (NodeIndex, NonNull<DiGraph<Node, Edge>>, Data)) -> Self {
Self {
index,
graph,
datum,
}
}
}
impl Node {
pub fn datum(&self) -> &Data {
&self.datum
}
pub fn index(&self) -> NodeIndex {
self.index
}
pub fn bucket(&self) -> &Bucket {
self.datum.bucket()
}
pub fn player(&self) -> Player {
self.datum.player()
}
pub fn payoff(&self, player: &Player) -> Utility {
let position = match player {
Player::Choice(Transition::Decision(x)) => x.to_owned(),
_ => unreachable!("payoffs defined relative to decider"),
};
match player {
Player::Choice(_) => unreachable!("payoffs defined relative to decider"),
Player::Chance => self
.datum()
.game()
.settlement()
.get(position)
.clone()
.map(|settlement| settlement.pnl() as f32)
.expect("player index in bounds"),
}
}
pub fn history(&self) -> Vec<&Edge> {
if let (Some(edge), Some(head)) = (self.incoming(), self.parent()) {
let mut history = head.history();
history.push(edge);
history
} else {
vec![]
}
}
pub fn outgoing(&self) -> Vec<&Edge> {
self.graph_ref()
.edges_directed(self.index, Outgoing)
.map(|e| e.weight())
.collect()
}
pub fn incoming(&self) -> Option<&Edge> {
self.graph_ref()
.edges_directed(self.index, Incoming)
.next()
.map(|e| e.weight())
}
pub fn parent(&self) -> Option<&Self> {
self.graph_ref()
.neighbors_directed(self.index, Incoming)
.next()
.map(|p| {
self.graph_ref()
.node_weight(p)
.expect("if incoming edge, then parent")
})
}
pub fn children(&self) -> Vec<&Self> {
self.graph_ref()
.neighbors_directed(self.index, Outgoing)
.map(|c| {
self.graph_ref()
.node_weight(c)
.expect("if outgoing edge, then child")
})
.collect()
}
pub fn follow(&self, edge: &Edge) -> &Self {
self.children()
.iter()
.find(|child| edge == child.incoming().unwrap())
.expect("valid edge to follow")
}
pub fn leaves(&self) -> Vec<&Self> {
if self.children().is_empty() {
vec![self]
} else {
self.children()
.iter()
.flat_map(|child| child.leaves())
.collect()
}
}
fn graph_ref(&self) -> &DiGraph<Self, Edge> {
unsafe { self.graph.as_ref() }
}
}