use crate::{
cells::{CellRef, LifeCell, State, ALIVE, DEAD},
config::Symmetry,
error::Error,
rules::{
private::Sealed,
typebool::{False, True},
Rule,
},
search::{Algorithm, Reason},
world::World,
};
use bitflags::bitflags;
use ca_rules::{ParseLife, ParseLifeGen};
use std::str::FromStr;
bitflags! {
#[derive(Clone, Copy, Debug, Default ,PartialEq, Eq, Hash)]
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();
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct NbhdDesc(u16);
#[derive(Clone)]
pub struct Life {
b0: bool,
s8: bool,
impl_table: [ImplFlags; 1 << 12],
}
impl Life {
pub fn new(b: &[u8], s: &[u8]) -> Self {
let b0 = b.contains(&0);
let s8 = s.contains(&8);
let impl_table = [ImplFlags::empty(); 1 << 12];
Self { b0, s8, impl_table }
.init_trans(b, s)
.init_conflict()
.init_impl()
.init_impl_nbhd()
}
fn init_trans(mut self, b: &[u8], s: &[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
}
}
impl ParseLife for Life {
fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self {
Self::new(&b, &s)
}
}
impl FromStr for Life {
type Err = Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
let rule: Self = ParseLife::parse_rule(input).map_err(Error::ParseRuleError)?;
if rule.has_b0_s8() {
Err(Error::B0S8Error)
} else {
Ok(rule)
}
}
}
impl Sealed for Life {}
impl Rule for Life {
type Desc = NbhdDesc;
type IsGen = False;
#[inline]
fn has_b0(&self) -> bool {
self.b0
}
#[inline]
fn has_b0_s8(&self) -> bool {
self.b0 && self.s8
}
#[inline]
fn gen(&self) -> usize {
2
}
#[inline]
fn symmetry(&self) -> Symmetry {
Symmetry::D8
}
fn new_desc(state: State, succ_state: State) -> Self::Desc {
let nbhd_state = match state {
ALIVE => 0x08,
_ => 0x80,
};
let succ_state = match succ_state {
ALIVE => 0b01,
_ => 0b10,
};
let state = match state {
ALIVE => 0b01,
_ => 0b10,
};
NbhdDesc(nbhd_state << 4 | succ_state << 2 | state)
}
fn update_desc(cell: &LifeCell<Self>, state: State, new: bool) {
let state_num = match state {
ALIVE => 0x01,
_ => 0x10,
};
for &neigh in &cell.nbhd {
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);
}
let change_num = match state {
ALIVE => 0b01,
_ => 0b10,
};
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: Algorithm<Self>>(
world: &mut World<Self, A>,
cell: CellRef<Self>,
) -> Result<(), A::ConflReason> {
let flags = world.rule.impl_table[cell.desc.get().0 as usize];
if flags.is_empty() {
return Ok(());
}
if flags.contains(ImplFlags::CONFLICT) {
return Err(A::confl_from_cell(cell));
}
if flags.intersects(ImplFlags::SUCC) {
let state = if flags.contains(ImplFlags::SUCC_DEAD) {
DEAD
} else {
ALIVE
};
if let Some(succ) = cell.succ {
return world.set_cell(succ, state, A::Reason::from_cell(cell));
} else {
return Ok(());
}
}
if flags.intersects(ImplFlags::SELF) {
let state = if flags.contains(ImplFlags::SELF_DEAD) {
DEAD
} else {
ALIVE
};
world.set_cell(cell, state, A::Reason::from_cell(cell))?;
}
if flags.intersects(ImplFlags::NBHD) {
let state = if flags.contains(ImplFlags::NBHD_DEAD) {
DEAD
} else {
ALIVE
};
for &neigh in &cell.nbhd {
if let Some(neigh) = neigh {
if neigh.state.get().is_none() {
world.set_cell(neigh, state, A::Reason::from_cell(cell))?;
}
}
}
}
Ok(())
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct NbhdDescGen(u16, Option<State>);
#[derive(Clone)]
pub struct LifeGen {
b0: bool,
s8: bool,
gen: usize,
impl_table: [ImplFlags; 1 << 12],
}
impl LifeGen {
pub fn new(b: &[u8], s: &[u8], gen: usize) -> Self {
let life = Life::new(b, s);
let impl_table = life.impl_table;
Self {
b0: life.b0,
s8: life.s8,
gen,
impl_table,
}
}
pub const fn non_gen(self) -> Life {
Life {
b0: self.b0,
s8: self.s8,
impl_table: self.impl_table,
}
}
}
impl ParseLifeGen for LifeGen {
fn from_bsg(b: Vec<u8>, s: Vec<u8>, gen: usize) -> Self {
Self::new(&b, &s, gen)
}
}
impl FromStr for LifeGen {
type Err = Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
let rule: Self = ParseLifeGen::parse_rule(input).map_err(Error::ParseRuleError)?;
if rule.has_b0_s8() {
Err(Error::B0S8Error)
} else {
Ok(rule)
}
}
}
impl Sealed for LifeGen {}
impl Rule for LifeGen {
type Desc = NbhdDescGen;
type IsGen = True;
#[inline]
fn has_b0(&self) -> bool {
self.b0
}
#[inline]
fn has_b0_s8(&self) -> bool {
self.b0 && self.s8
}
#[inline]
fn gen(&self) -> usize {
self.gen
}
#[inline]
fn symmetry(&self) -> Symmetry {
Symmetry::D8
}
#[inline]
fn new_desc(state: State, succ_state: State) -> Self::Desc {
let desc = Life::new_desc(state, succ_state);
NbhdDescGen(desc.0, Some(succ_state))
}
fn update_desc(cell: &LifeCell<Self>, state: State, new: bool) {
{
let state_num = match state {
ALIVE => 0x01,
_ => 0x10,
};
for &neigh in &cell.nbhd {
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);
}
}
let change_num = match state {
ALIVE => 0b01,
_ => 0b10,
};
if let Some(pred) = cell.pred {
let mut desc = pred.desc.get();
desc.0 ^= change_num << 2;
desc.1 = if new { Some(state) } else { None };
pred.desc.set(desc);
}
let mut desc = cell.desc.get();
desc.0 ^= change_num;
cell.desc.set(desc);
}
fn consistify<A: Algorithm<Self>>(
world: &mut World<Self, A>,
cell: CellRef<Self>,
) -> Result<(), A::ConflReason> {
let desc = cell.desc.get();
let flags = world.rule.impl_table[desc.0 as usize];
let gen = world.rule.gen;
match cell.state.get() {
Some(DEAD) => {
if let Some(State(j)) = desc.1 {
if j >= 2 {
return Err(A::confl_from_cell(cell));
}
}
if flags.intersects(ImplFlags::SUCC) {
let state = if flags.contains(ImplFlags::SUCC_DEAD) {
DEAD
} else {
ALIVE
};
if let Some(succ) = cell.succ {
return world.set_cell(succ, state, A::Reason::from_cell(cell));
} else {
return Ok(());
}
}
}
Some(ALIVE) => {
if let Some(State(j)) = desc.1 {
if j == 0 || j > 2 {
return Err(A::confl_from_cell(cell));
}
}
if flags.intersects(ImplFlags::SUCC) {
let state = if flags.contains(ImplFlags::SUCC_DEAD) {
State(2)
} else {
ALIVE
};
if let Some(succ) = cell.succ {
return world.set_cell(succ, state, A::Reason::from_cell(cell));
} else {
return Ok(());
}
}
}
Some(State(i)) => {
if let Some(State(j)) = desc.1 {
if j == (i + 1) % gen {
return Ok(());
} else {
return Err(A::confl_from_cell(cell));
}
} else if let Some(succ) = cell.succ {
return world.set_cell(succ, State((i + 1) % gen), A::Reason::from_cell(cell));
} else {
return Ok(());
}
}
None => match desc.1 {
Some(DEAD) => {
if flags.contains(ImplFlags::SELF_ALIVE) {
return world.set_cell(cell, State(gen - 1), A::Reason::from_cell(cell));
} else {
return Ok(());
}
}
Some(ALIVE) => {
if flags.intersects(ImplFlags::SELF) {
let state = if flags.contains(ImplFlags::SELF_DEAD) {
DEAD
} else {
ALIVE
};
world.set_cell(cell, state, A::Reason::from_cell(cell))?;
}
}
Some(State(j)) => {
return world.set_cell(cell, State(j - 1), A::Reason::from_cell(cell));
}
None => return Ok(()),
},
}
if flags.is_empty() {
return Ok(());
}
if flags.contains(ImplFlags::CONFLICT) {
return Err(A::confl_from_cell(cell));
}
if flags.intersects(ImplFlags::NBHD_ALIVE) {
for &neigh in &cell.nbhd {
if let Some(neigh) = neigh {
if neigh.state.get().is_none() {
world.set_cell(neigh, ALIVE, A::Reason::from_cell(cell))?;
}
}
}
}
Ok(())
}
}