mod action;
mod agari;
mod cache;
mod step;
mod reaction;
mod scoring;
pub mod utils;
use std::default::Default;
use riichi_elements::prelude::*;
use crate::{
model::*,
};
use self::{
action::check_action,
cache::EngineCache,
reaction::{check_reaction, resolve_reaction},
step::{next_normal, next_agari, next_abort}
};
pub use self::{
action::ActionError,
reaction::ReactionError,
scoring::*,
};
const RIICHI_POT: GamePoints = 1000;
#[derive(Default)]
pub struct Engine {
begin: RoundBegin,
state: State,
action: Option<Action>,
reactions: [Option<Reaction>; 4],
end: Option<RoundEnd>,
cache: EngineCache,
}
impl Engine {
pub fn new() -> Self { Default::default() }
pub fn state(&self) -> &State { &self.state }
pub fn end(&self) -> &Option<RoundEnd> { &self.end }
pub fn begin_round(&mut self, begin: RoundBegin) -> &mut Self {
self.begin = begin;
self.state = State::new(&self.begin);
self.action = Default::default();
self.reactions = Default::default();
self.end = None;
self.cache.init_wait_cache(&self.state.closed_hands);
self
}
pub fn jump_to_state(&mut self, state: State) -> &mut Self {
debug_assert!(wall::is_valid_wall(self.begin.wall));
self.state = state;
self.action = Default::default();
self.reactions = Default::default();
self.end = None;
self.cache.init_wait_cache(&self.state.closed_hands);
self
}
pub fn register_action(&mut self, action: Action) -> Result<&mut Self, ActionError> {
assert!(self.state.core.num_drawn_head >= 53);
self.action = None;
self.reactions = Default::default();
self.cache.meld = Default::default();
self.cache.win = Default::default();
check_action(&self.begin, &self.state, action, &mut self.cache)?;
self.action = Some(action);
Ok(self)
}
pub fn register_reaction(&mut self, reactor: Player, reaction: Reaction)
-> Result<&mut Self, ReactionError> {
self.reactions[reactor.to_usize()] = None;
check_reaction(
&self.begin,
&self.state,
self.action.unwrap(),
reactor,
reaction,
&mut self.cache)?;
self.reactions[reactor.to_usize()] = Some(reaction);
Ok(self)
}
pub fn step(&mut self) -> GameStep {
let actor = self.state.core.actor;
let action = self.action.unwrap();
let (action_result, reactor_reaction) =
resolve_reaction(&self.begin.ruleset, &self.state, action, &self.reactions);
match action_result {
ActionResult::Pass | ActionResult::CalledBy(_) => {
let next_core = next_normal(
&self.begin, &self.state, action, action_result, &self.cache);
self.state.evolve(action, next_core);
GameStep {
actor,
action,
reactor_reaction,
action_result,
next_state_core: Some(next_core),
}
}
ActionResult::Agari(agari_kind) => {
self.end = Some(next_agari(
&self.begin, &self.state, action, &self.reactions, agari_kind, &self.cache));
GameStep {
actor,
action,
reactor_reaction,
action_result,
next_state_core: None,
}
}
ActionResult::Abort(abort_reason) => {
self.end = Some(next_abort(&self.begin, &self.state, abort_reason, &self.cache));
GameStep {
actor,
action,
reactor_reaction,
action_result,
next_state_core: None,
}
}
}
}
}