use super::{
retreat, Adjudicate, AttackOutcome, Context, ConvoyOutcome, HoldOutcome, MappedMainOrder,
OrderState, ResolverState, SupportOutcome,
};
use from_variants::FromVariants;
use std::collections::HashMap;
use std::fmt;
#[derive(FromVariants, PartialEq, Eq)]
pub enum OrderOutcome<'a> {
Invalid(InvalidOrder),
Hold(HoldOutcome<'a>),
Move(AttackOutcome<'a>),
Support(SupportOutcome<'a>),
Convoy(ConvoyOutcome<'a>),
}
impl From<&'_ OrderOutcome<'_>> for OrderState {
fn from(other: &OrderOutcome<'_>) -> Self {
match other {
OrderOutcome::Invalid(i) => i.into(),
OrderOutcome::Hold(h) => h.into(),
OrderOutcome::Move(m) => m.into(),
OrderOutcome::Support(s) => s.into(),
OrderOutcome::Convoy(c) => c.into(),
}
}
}
impl From<OrderOutcome<'_>> for OrderState {
fn from(other: OrderOutcome<'_>) -> Self {
(&other).into()
}
}
impl fmt::Debug for OrderOutcome<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
OrderOutcome::Invalid(oo) => oo.fmt(f),
OrderOutcome::Hold(oo) => oo.fmt(f),
OrderOutcome::Move(oo) => oo.fmt(f),
OrderOutcome::Support(oo) => oo.fmt(f),
OrderOutcome::Convoy(oo) => oo.fmt(f),
}
}
}
impl PartialEq<OrderState> for OrderOutcome<'_> {
fn eq(&self, other: &OrderState) -> bool {
OrderState::from(self) == *other
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum InvalidOrder {
NoUnit,
ForeignUnit,
MultipleToSameUnit,
}
impl From<&'_ InvalidOrder> for OrderState {
fn from(_: &InvalidOrder) -> Self {
OrderState::Fails
}
}
pub struct Outcome<'a, A> {
pub(in crate::judge) context: Context<'a, A>,
pub(in crate::judge) resolver: ResolverState<'a>,
pub(in crate::judge) orders: HashMap<&'a MappedMainOrder, OrderOutcome<'a>>,
}
impl<'a, A: Adjudicate> Outcome<'a, A> {
pub(in crate::judge) fn new(context: Context<'a, A>, resolver: ResolverState<'a>) -> Self {
let mut state = resolver.clone();
let orders = context
.orders()
.map(|ord| (ord, context.rules.explain(&context, &mut state, ord)))
.chain(
context
.invalid_orders
.iter()
.map(|(&ord, &reason)| (ord, reason.into())),
)
.collect();
Self {
context,
resolver,
orders,
}
}
pub fn orders(&self) -> impl Iterator<Item = &MappedMainOrder> {
self.context.orders()
}
pub fn all_orders(&self) -> impl Iterator<Item = &MappedMainOrder> {
self.orders.keys().copied()
}
pub fn get(&'a self, order: &'a MappedMainOrder) -> Option<&'a OrderOutcome<'a>> {
self.orders.get(order)
}
pub fn to_retreat_start(&'a self) -> retreat::Start<'a> {
retreat::Start::new(self)
}
#[cfg(feature = "dependency-graph")]
pub fn dependencies(&self) -> impl fmt::Display {
struct Dependencies(std::collections::BTreeSet<(MappedMainOrder, MappedMainOrder)>);
impl fmt::Display for Dependencies {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "digraph G {{")?;
for (src, dest) in &self.0 {
writeln!(f, r#" "{}" -> "{}""#, src, dest)?;
}
writeln!(f, "}}")
}
}
Dependencies(self.resolver.dependencies())
}
}
#[allow(clippy::implicit_hasher)]
impl<A: Adjudicate> From<Outcome<'_, A>> for HashMap<MappedMainOrder, OrderState> {
fn from(other: Outcome<'_, A>) -> Self {
other
.context
.orders()
.map(|ord| {
(
ord.clone(),
OrderState::from(other.get(ord).expect("Outcome should be complete")),
)
})
.collect()
}
}