use super::{Agent, BatchAgent};
use crate::arena::GameResult;
use crate::mjai::EventExt;
use crate::state::PlayerState;
use anyhow::{Context, Result, ensure};
use ndarray::prelude::*;
pub struct BatchifiedAgent
where
A: Agent,
{
inner: Vec ,
last_actions: Vec>,
}
impl BatchifiedAgent
where
A: Agent,
{
/// Example:
///
/// ```rust
/// use riichi::agent::{BatchAgent, BatchifiedAgent, Tsumogiri};
///
/// let batch_tsumogiri = BatchifiedAgent::new(|i| Ok(Tsumogiri(i)), &[0, 1, 2, 3]).unwrap();
/// fn impl_test(_: T) {}
/// impl_test(batch_tsumogiri);
/// ```
pub fn new(new_fn: F, player_ids: &[u8]) -> Result
where
F: FnMut(u8) -> Result,
{
ensure!(!player_ids.is_empty());
let inner = player_ids
.iter()
.copied()
.map(new_fn)
.collect::>()?;
Ok(Self {
inner,
last_actions: vec![None; player_ids.len()],
})
}
}
impl BatchAgent for BatchifiedAgent
where
A: Agent,
{
#[inline]
fn name(&self) -> String {
self.inner[0].name()
}
#[inline]
fn oracle_obs_version(&self) -> Option {
self.inner[0].oracle_obs_version()
}
#[inline]
fn set_scene(
&mut self,
index: usize,
log: &[EventExt],
state: &PlayerState,
invisible_features: Option>,
) -> Result<()> {
self.last_actions[index] = Some(self.inner[index].react(log, state, invisible_features)?);
Ok(())
}
#[inline]
fn get_reaction(
&mut self,
index: usize,
_: &[EventExt],
_: &PlayerState,
_: Option>,
) -> Result {
self.last_actions[index]
.take()
.context("`get_reaction` without `set_scene`")
}
#[inline]
fn start_game(&mut self, index: usize) -> Result<()> {
self.inner[index].start_game()
}
#[inline]
fn end_kyoku(&mut self, index: usize) -> Result<()> {
self.inner[index].end_kyoku()
}
#[inline]
fn end_game(&mut self, index: usize, game_result: &GameResult) -> Result<()> {
self.inner[index].end_game(game_result)
}
}