use std::cell::RefCell;
use crate::{
core::{
GameTags, PageId, Response,
game_state::{PageKey, PageMap},
},
view::{Object, View},
};
#[derive(Debug)]
pub struct PageState<'a> {
view: View,
page_state: RefCell<&'a mut PageMap>, #[cfg(feature = "rand")]
pub seed: Option<u64>,
fresh: bool,
game_tags: &'a mut GameTags,
pub simulating: bool,
}
impl<'a> PageState<'a> {
pub fn new(
name: impl Into<PageId>,
fresh: bool,
simulating: bool,
page_state: &'a mut PageMap,
game_tags: &'a mut GameTags,
) -> Self {
Self {
view: View::new(name.into()),
page_state: RefCell::new(page_state),
#[cfg(feature = "rand")]
seed: None,
fresh,
game_tags,
simulating,
}
}
}
impl<'a> PageState<'a> {
pub fn push(&mut self, object: Object) {
self.view.push(object);
}
pub fn id(&self) -> PageId {
self.view.pageid.clone()
}
pub fn into_response(self) -> Response {
Response::View(self.view)
}
pub fn fresh(&self) -> bool {
self.fresh
}
pub fn get(&self, key: PageKey) -> Option<u64> {
self.page_state.borrow().get(&key).copied()
}
pub fn get_mask_indices(&self, key: PageKey) -> Vec<usize> {
let val = match self.page_state.borrow().get(&key).copied() {
Some(v) => v,
None => return Vec::new(),
};
let mut bits = Vec::new();
for i in 0..64 {
if (val & (1 << i)) != 0 {
bits.push(i);
}
}
bits
}
pub fn get_mask<const N: usize>(&self, key: PageKey) -> [bool; N] {
let val = match self.page_state.borrow().get(&key).copied() {
Some(v) => v,
None => return [false; N],
};
std::array::from_fn(|i| i < 64 && (val & (1 << i)) != 0)
}
pub fn get_mask_last(&self, key: PageKey) -> Option<u8> {
let val = match self.page_state.borrow().get(&key).copied() {
Some(v) => v,
None => return None,
};
if val == 0 {
None
} else {
Some(val.trailing_zeros() as u8)
}
}
pub fn remove_mask_last(&mut self, key: PageKey) -> Option<u8> {
let val = match self.page_state.borrow_mut().remove(&key) {
Some(v) => v,
None => return None,
};
if val == 0 {
None
} else {
Some(val.trailing_zeros() as u8)
}
}
#[cfg(feature = "rand")]
pub fn rand(&self, range: usize, exclude: &[usize]) -> usize {
use rand::{SeedableRng, rngs::StdRng, seq::IndexedRandom};
let excl: std::collections::HashSet<usize> = exclude.iter().copied().collect();
let pool: Vec<usize> = (0..range).filter(|i| !excl.contains(i)).collect();
if pool.is_empty() {
panic!("rand(): range exhausted by exclusion list");
}
if let Some(seed) = self.seed {
*pool.choose(&mut StdRng::seed_from_u64(seed)).unwrap()
} else {
*pool.choose(&mut rand::rng()).unwrap()
}
}
pub fn insert(&self, key: PageKey, value: u64) {
self.page_state.borrow_mut().insert(key, value);
}
pub fn remove(&self, key: PageKey) -> Option<u64> {
self.page_state.borrow_mut().remove(&key)
}
pub fn was_zero(&self, key: PageKey) -> bool {
if let Some(x) = self.page_state.borrow_mut().get_mut(&key)
&& *x == 0
{
*x = 1;
true
} else {
false
}
}
pub fn tag(&mut self, s: &str) -> bool {
let q: PageId = s.into();
self.view.tags.push(q.clone());
self.game_tags.insert(q)
}
pub fn untag(&mut self, s: &str) -> bool {
self.game_tags.remove(&s.into())
}
}
use std::fmt;
impl<'a> fmt::Display for PageState<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.view.pageid)
}
}