use crate::{
cells::{CellRef, State, ALIVE, DEAD},
rules::Rule,
search::Reason,
world::World,
};
use bitflags::bitflags;
use ca_rules::{ParseLife, ParseLifeGen, ParseRuleError};
use std::str::FromStr;
bitflags! {
#[derive(Default)]
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_rule! {
pub struct NbhdDesc(u16);
pub struct Life {
Parser: ParseLife,
impl_table: [ImplFlags; 1 << 12],
}
pub struct LifeGen {
Parser: ParseLifeGen,
}
fn new_desc {
ALIVE => 0x08,
DEAD => 0x80,
}
fn update_desc(cell, state, new, change_num) {
let state_num = match state {
Some(ALIVE) => 0x01,
Some(_) => 0x10,
None => 0,
};
for &neigh in cell.nbhd.iter() {
let neigh = neigh.unwrap();
let mut desc = neigh.desc.get();
if new {
desc.0 += state_num << 4;
} else {
desc.0 -= state_num << 4;
}
neigh.desc.set(desc);
}
}
fn consistify<'a>(world, cell, flags) {
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;
}
}
}
}
fn consistify_gen<'a>(world, cell, flags) {
if flags.intersects(ImplFlags::NBHD_ALIVE) {
for &neigh in cell.nbhd.iter() {
if let Some(neigh) = neigh {
if neigh.state.get().is_none() && !world.set_cell(neigh, ALIVE, Reason::Deduce)
{
return false;
}
}
}
}
}
}
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 | 0b10] |= if b.contains(&alives) {
ImplFlags::SUCC_ALIVE
} else {
ImplFlags::SUCC_DEAD
};
self.impl_table[desc | 0b01] |= 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 0..=2 {
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 0..=2 {
let desc = nbhd_state << 4 | state;
if self.impl_table[desc].contains(ImplFlags::SUCC_ALIVE) {
self.impl_table[desc | 0b10 << 2] = ImplFlags::CONFLICT;
} else if self.impl_table[desc].contains(ImplFlags::SUCC_DEAD) {
self.impl_table[desc | 0b01 << 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 1..=2 {
let flag = if succ_state == 0b10 {
ImplFlags::SUCC_ALIVE | ImplFlags::CONFLICT
} else {
ImplFlags::SUCC_DEAD | ImplFlags::CONFLICT
};
let possibly_dead = !self.impl_table[desc | 0b10].intersects(flag);
let possibly_alive = !self.impl_table[desc | 0b01].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 1..=2 {
let flag = if succ_state == 0b10 {
ImplFlags::SUCC_ALIVE | ImplFlags::CONFLICT
} else {
ImplFlags::SUCC_DEAD | ImplFlags::CONFLICT
};
let index = desc | succ_state << 2;
for state in 0..=2 {
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
}
}