use crate::{
cells::{Alive, CellRef, Dead, State},
rules::Rule,
search::Reason,
world::World,
};
use bitflags::bitflags;
use ca_rules::ParseLife;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct NbhdDesc(usize);
bitflags! {
struct ImplFlags: u8 {
const CONFLICT = 0b_0000_0001;
const SUCC_ALIVE = 0b_0000_0100;
const SUCC_DEAD = 0b_0000_1000;
const SUCC = Self::SUCC_ALIVE.bits | Self::SUCC_DEAD.bits;
const SELF_ALIVE = 0b_0001_0000;
const SELF_DEAD = 0b_0010_0000;
const SELF = Self::SELF_ALIVE.bits | Self::SELF_DEAD.bits;
const NBHD_ALIVE = 0b_0100_0000;
const NBHD_DEAD = 0b_1000_0000;
const NBHD = Self::NBHD_ALIVE.bits | Self::NBHD_DEAD.bits;
}
}
impl Default for ImplFlags {
fn default() -> Self {
ImplFlags::empty()
}
}
pub struct Life {
b0: bool,
impl_table: [ImplFlags; 1 << 12],
}
impl Life {
pub fn new(b: Vec<u8>, s: Vec<u8>) -> Self {
let b0 = b.contains(&0);
let impl_table = [ImplFlags::empty(); 1 << 12];
Life { b0, impl_table }
.init_trans(b, s)
.init_conflict()
.init_impl()
.init_impl_nbhd()
}
fn init_trans(mut self, b: Vec<u8>, s: Vec<u8>) -> Self {
for alives in 0..=8 {
let desc = ((8 - alives) << 8) | alives << 4;
let alives = alives as u8;
self.impl_table[desc | Dead as usize] |= if b.contains(&alives) {
ImplFlags::SUCC_ALIVE
} else {
ImplFlags::SUCC_DEAD
};
self.impl_table[desc | Alive as usize] |= if s.contains(&alives) {
ImplFlags::SUCC_ALIVE
} else {
ImplFlags::SUCC_DEAD
};
self.impl_table[desc] |= if b.contains(&alives) && s.contains(&alives) {
ImplFlags::SUCC_ALIVE
} else if !b.contains(&alives) && !s.contains(&alives) {
ImplFlags::SUCC_DEAD
} else {
ImplFlags::empty()
};
}
for unknowns in 1..=8 {
for alives in 0..=8 - unknowns {
let desc = (8 - alives - unknowns) << 8 | alives << 4;
let desc0 = (8 - alives - unknowns + 1) << 8 | alives << 4;
let desc1 = (8 - alives - unknowns) << 8 | (alives + 1) << 4;
for &state in [Dead as usize, Alive as usize, 0].iter() {
let trans0 = self.impl_table[desc0 | state];
if trans0 == self.impl_table[desc1 | state] {
self.impl_table[desc | state] |= trans0;
}
}
}
}
self
}
fn init_conflict(mut self) -> Self {
for nbhd_state in 0..0xff {
for &state in [Dead as usize, Alive as usize, 0].iter() {
let desc = nbhd_state << 4 | state;
if self.impl_table[desc].contains(ImplFlags::SUCC_ALIVE) {
self.impl_table[desc | (Dead as usize) << 2] = ImplFlags::CONFLICT;
} else if self.impl_table[desc].contains(ImplFlags::SUCC_DEAD) {
self.impl_table[desc | (Alive as usize) << 2] = ImplFlags::CONFLICT;
}
}
}
self
}
fn init_impl(mut self) -> Self {
for unknowns in 0..=8 {
for alives in 0..=8 - unknowns {
let desc = (8 - alives - unknowns) << 8 | alives << 4;
for &succ_state in [Dead as usize, Alive as usize].iter() {
let flag = if succ_state == Dead as usize {
ImplFlags::SUCC_ALIVE | ImplFlags::CONFLICT
} else {
ImplFlags::SUCC_DEAD | ImplFlags::CONFLICT
};
let possibly_dead = !self.impl_table[desc | Dead as usize].intersects(flag);
let possibly_alive = !self.impl_table[desc | Alive as usize].intersects(flag);
let index = desc | succ_state << 2;
if possibly_dead && !possibly_alive {
self.impl_table[index] |= ImplFlags::SELF_DEAD;
} else if !possibly_dead && possibly_alive {
self.impl_table[index] |= ImplFlags::SELF_ALIVE;
} else if !possibly_dead && !possibly_alive {
self.impl_table[index] = ImplFlags::CONFLICT;
}
}
}
}
self
}
fn init_impl_nbhd(mut self) -> Self {
for unknowns in 1..=8 {
for alives in 0..=8 - unknowns {
let desc = (8 - alives - unknowns) << 8 | alives << 4;
let desc0 = (8 - alives - unknowns + 1) << 8 | alives << 4;
let desc1 = (8 - alives - unknowns) << 8 | (alives + 1) << 4;
for &succ_state in [Dead as usize, Alive as usize].iter() {
let flag = if succ_state == Dead as usize {
ImplFlags::SUCC_ALIVE | ImplFlags::CONFLICT
} else {
ImplFlags::SUCC_DEAD | ImplFlags::CONFLICT
};
let index = desc | succ_state << 2;
for &state in [Dead as usize, Alive as usize, 0].iter() {
let possibly_dead = !self.impl_table[desc0 | state].intersects(flag);
let possibly_alive = !self.impl_table[desc1 | state].intersects(flag);
if possibly_dead && !possibly_alive {
self.impl_table[index | state] |= ImplFlags::NBHD_DEAD;
} else if !possibly_dead && possibly_alive {
self.impl_table[index | state] |= ImplFlags::NBHD_ALIVE;
} else if !possibly_dead && !possibly_alive {
self.impl_table[index | state] = ImplFlags::CONFLICT;
}
}
}
}
}
self
}
pub fn parse_rule(input: &str) -> Result<Self, String> {
ParseLife::parse_rule(input).map_err(|e| e.to_string())
}
}
impl Rule for Life {
type Desc = NbhdDesc;
fn b0(&self) -> bool {
self.b0
}
fn new_desc(state: State, succ_state: State) -> Self::Desc {
let nbhd_state = match state {
Dead => 0x80,
Alive => 0x08,
};
NbhdDesc(nbhd_state << 4 | (succ_state as usize) << 2 | state as usize)
}
fn update_desc(cell: CellRef<Self>, old_state: Option<State>, state: Option<State>) {
let old_state_num = match old_state {
Some(Dead) => 0x10,
Some(Alive) => 0x01,
None => 0,
};
let state_num = match state {
Some(Dead) => 0x10,
Some(Alive) => 0x01,
None => 0,
};
for &neigh in cell.nbhd.iter() {
let neigh = neigh.unwrap();
let mut desc = neigh.desc.get();
desc.0 -= old_state_num << 4;
desc.0 += state_num << 4;
neigh.desc.set(desc);
}
let change_num = match (state, old_state) {
(Some(Dead), Some(Alive)) | (Some(Alive), Some(Dead)) => 0b11,
(Some(Dead), None) | (None, Some(Dead)) => 0b10,
(Some(Alive), None) | (None, Some(Alive)) => 0b01,
_ => 0,
};
if let Some(pred) = cell.pred {
let mut desc = pred.desc.get();
desc.0 ^= change_num << 2;
pred.desc.set(desc);
}
let mut desc = cell.desc.get();
desc.0 ^= change_num;
cell.desc.set(desc);
}
fn consistify<'a>(world: &mut World<'a, Self>, cell: CellRef<'a, Self>) -> bool {
let flags = world.rule.impl_table[cell.desc.get().0];
if flags.contains(ImplFlags::CONFLICT) {
return false;
}
if flags.intersects(ImplFlags::SUCC) {
let state = if flags.contains(ImplFlags::SUCC_DEAD) {
Dead
} else {
Alive
};
let succ = cell.succ.unwrap();
return world.set_cell(succ, state, Reason::Deduce);
}
if flags.intersects(ImplFlags::SELF) {
let state = if flags.contains(ImplFlags::SELF_DEAD) {
Dead
} else {
Alive
};
if !world.set_cell(cell, state, Reason::Deduce) {
return false;
}
}
if flags.intersects(ImplFlags::NBHD) {
let state = if flags.contains(ImplFlags::NBHD_DEAD) {
Dead
} else {
Alive
};
for &neigh in cell.nbhd.iter() {
if let Some(neigh) = neigh {
if neigh.state.get().is_none() && !world.set_cell(neigh, state, Reason::Deduce)
{
return false;
}
}
}
}
true
}
}
impl ParseLife for Life {
fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self {
Self::new(b, s)
}
}