You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
4.9 KiB
141 lines
4.9 KiB
use rand::seq::SliceRandom;
|
|
use rhai::{
|
|
serde::{from_dynamic, to_dynamic},
|
|
Dynamic, Engine, EvalAltResult, Map,
|
|
};
|
|
|
|
use std::fmt::{Debug, Display};
|
|
|
|
use crate::games::run::types::Card;
|
|
|
|
use super::{
|
|
types::{CardId, Data, Player, RhaiResult, RunningPile},
|
|
};
|
|
// TODO Write somekind of documentation on functions available & stuff
|
|
pub fn setup_engine() -> Engine {
|
|
let mut engine = Engine::new();
|
|
engine.set_max_expr_depths(0, 0);
|
|
engine.register_result_fn("shuffle", shuffle_pile);
|
|
engine
|
|
.on_print(|x| log::info!(target: "`Rhai::STDOUT`", "{}", x))
|
|
.on_debug(|x, _src, _pos| log::debug!(target: "`Rhai::STDOUT`", "{}", x));
|
|
|
|
// Register Player type, with its functions
|
|
engine
|
|
.register_type::<Player>()
|
|
.register_get("val", Player::get)
|
|
.register_set_result("val", Player::set)
|
|
.register_result_fn("add", Player::add)
|
|
.register_result_fn("sub", Player::sub)
|
|
.register_fn("to_string", |p: &mut Player| p.to_string())
|
|
.register_fn("print", |p: &mut Player| p.to_string())
|
|
.register_fn("debug", |p: &mut Player| format!("{:?}", p))
|
|
.register_fn("+", |s: &str, p: Player| format!("{}{}", s, p))
|
|
.register_fn("+", |p: Player, s: &str| p.to_string().push_str(s))
|
|
.register_fn("==", |a: Player, b: Player| a.num == b.num)
|
|
.register_fn("==", |a: Player, b: i64| a.num == b as u32)
|
|
.register_fn("==", |a: i64, b: Player| b.num == a as u32);
|
|
|
|
engine
|
|
.register_type::<Card>()
|
|
.register_get("kind", Card::get_kind)
|
|
.register_get("uuid", Card::get_uuid)
|
|
.register_fn("to_string", |c: &mut Card| c.to_string())
|
|
.register_fn("print", |c: &mut Card| c.to_string())
|
|
.register_fn("debug", |c: &mut Card| format!("{:?}", c))
|
|
.register_fn("+", |s: &str, c: Card| format!("{}{}", s, c))
|
|
.register_fn("+", |c: Card, s: &str| c.to_string().push_str(s));
|
|
|
|
engine
|
|
.register_type::<CardId>() // TODO add constructor for CardId
|
|
.register_result_fn("get_card", get_card_from_id)
|
|
.register_result_fn("pop_card", pop_card_from_id)
|
|
.register_get("pile_kind", |p: &mut CardId| match p.pile_kind {
|
|
super::PileKind::Owned(i) => Dynamic::from(i),
|
|
super::PileKind::Common => Dynamic::from("common"),
|
|
})
|
|
.register_get("pile_name", |p: &mut CardId| p.pile_name.clone())
|
|
.register_get("card_idx", |p: &mut CardId| match p.idx {
|
|
super::CardIdx::Indexed(i) => Dynamic::from(i),
|
|
super::CardIdx::Top => Dynamic::from("top"),
|
|
super::CardIdx::Bottom => Dynamic::from("bottom"),
|
|
})
|
|
.register_fn("to_string", |p: &mut CardId| p.to_string())
|
|
.register_fn("print", |p: &mut CardId| p.to_string())
|
|
.register_fn("debug", |p: &mut CardId| p.to_string())
|
|
.register_fn("+", |s: &str, p: CardId| format!("{}{}", s, p))
|
|
.register_fn("+", |p: CardId, s: &str| p.to_string().push_str(s));
|
|
|
|
engine
|
|
}
|
|
|
|
fn shuffle_pile(pile: Map) -> Result<Dynamic, Box<rhai::EvalAltResult>> {
|
|
let mut pile = RunningPile::from_rhai_map(pile)?;
|
|
let mut rng = rand::thread_rng();
|
|
pile.cards.shuffle(&mut rng);
|
|
to_dynamic(pile)
|
|
}
|
|
|
|
fn get_card_from_id(data: &mut Map, card: CardId) -> Result<Dynamic, Box<rhai::EvalAltResult>> {
|
|
let dynamic: Dynamic = <Dynamic as From<Map>>::from(data.clone());
|
|
let data: Data = from_dynamic(&dynamic)?;
|
|
let pile = &match card.pile_kind {
|
|
super::PileKind::Common => &data.piles,
|
|
super::PileKind::Owned(i) => &data.player_piles[i as usize],
|
|
}[&card.pile_name];
|
|
let card_maybe = match card.idx {
|
|
super::CardIdx::Top => pile.cards.first(),
|
|
super::CardIdx::Bottom => pile.cards.last(),
|
|
super::CardIdx::Indexed(i) => pile.cards.get(i),
|
|
};
|
|
card_maybe
|
|
.map(|x| to_dynamic(x))
|
|
.unwrap_or(Ok(Dynamic::default()))
|
|
}
|
|
|
|
fn pop_card_from_id(data_dyn: &mut Map, card: CardId) -> Result<Dynamic, Box<rhai::EvalAltResult>> {
|
|
let mut dynamic: Dynamic = <Dynamic as From<Map>>::from(data_dyn.clone());
|
|
let mut data: Data = from_dynamic(&dynamic)?;
|
|
let pile = match card.pile_kind {
|
|
super::PileKind::Common => &mut data.piles,
|
|
super::PileKind::Owned(i) => &mut data.player_piles[i as usize],
|
|
}
|
|
.get_mut(&card.pile_name)
|
|
.unwrap();
|
|
let card = match card.idx {
|
|
// FIXME panics if 0 or i is out of bounds
|
|
super::CardIdx::Top => to_dynamic(&pile.cards.remove(0)),
|
|
super::CardIdx::Bottom => pile
|
|
.cards
|
|
.pop()
|
|
.map(|x| to_dynamic(x))
|
|
.unwrap_or(Ok(Dynamic::default())),
|
|
super::CardIdx::Indexed(i) => to_dynamic(&pile.cards.remove(i)),
|
|
};
|
|
dynamic = to_dynamic(&data)?;
|
|
*data_dyn = dynamic.cast();
|
|
card
|
|
}
|
|
|
|
struct GenericError<T: Debug + Display>(T);
|
|
|
|
impl<T: Debug + Display> Debug for GenericError<T> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{:?}", self.0)
|
|
}
|
|
}
|
|
|
|
impl<T: Debug + Display> Display for GenericError<T> {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", self.0)
|
|
}
|
|
}
|
|
|
|
impl<T: Debug + Display> std::error::Error for GenericError<T> {}
|
|
|
|
pub fn rhai_error<T: Display + Debug + 'static + Send + Sync>(s: T) -> RhaiResult<()> {
|
|
Err(Box::new(EvalAltResult::ErrorSystem(
|
|
s.to_string(),
|
|
Box::new(GenericError(s)),
|
|
)))
|
|
}
|
|
|