use crate::{
cells::{CellRef, LifeCell, State, ALIVE, DEAD},
config::{Symmetry, Transform},
error::Error,
rules::{
private::Sealed,
typebool::{False, True},
Rule,
},
search::{Algorithm, Reason},
world::World,
};
use bitflags::bitflags;
use ca_rules::{ParseNtLife, ParseNtLifeGen};
use std::{collections::HashSet, str::FromStr};
fn permute_bits(n: u8, perm: [u32; 8]) -> u8 {
(0..8)
.map(|i| (n & (1 << i)).rotate_left(perm[i] + 8 - i as u32))
.fold(0, |x, y| x | y)
}
fn transform_neigh(data: u8, transform: Transform) -> u8 {
match transform {
Transform::Id => data,
Transform::Rotate90 => permute_bits(data, [5, 3, 0, 6, 1, 7, 4, 2]),
Transform::Rotate180 => permute_bits(data, [7, 6, 5, 4, 3, 2, 1, 0]),
Transform::Rotate270 => permute_bits(data, [2, 4, 7, 1, 6, 0, 3, 5]),
Transform::FlipRow => permute_bits(data, [5, 6, 7, 3, 4, 0, 1, 2]),
Transform::FlipCol => permute_bits(data, [2, 1, 0, 4, 3, 7, 6, 5]),
Transform::FlipDiag => permute_bits(data, [0, 3, 5, 1, 6, 2, 4, 7]),
Transform::FlipAntidiag => permute_bits(data, [7, 4, 2, 6, 1, 5, 3, 0]),
}
}
bitflags! {
#[derive(Clone, Copy, Debug, Default ,PartialEq, Eq, Hash)]
struct ImplFlags: u32 {
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 = 0xffff << 6;
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct NbhdDesc(u32);
#[derive(Clone)]
pub struct NtLife {
b0: bool,
s8: bool,
symmetry: Symmetry,
impl_table: Vec<ImplFlags>,
}
impl NtLife {
pub fn new(b: &[u8], s: &[u8]) -> Self {
let b0 = b.contains(&0x00);
let s8 = s.contains(&0xff);
let symmetry = Symmetry::C1;
let impl_table = vec![ImplFlags::empty(); 1 << 20];
Self {
b0,
s8,
symmetry,
impl_table,
}
.init_symmetry(b, s)
.init_trans(b, s)
.init_conflict()
.init_impl()
.init_impl_nbhd()
}
fn init_symmetry(mut self, b: &[u8], s: &[u8]) -> Self {
let b_set: HashSet<_> = b.iter().copied().collect();
let s_set: HashSet<_> = s.iter().copied().collect();
self.symmetry = Symmetry::generated_by(
Transform::ALL
.into_iter()
.filter(|transform| {
b.iter()
.map(|data| transform_neigh(*data, *transform))
.collect::<HashSet<_>>()
== b_set
})
.filter(|transform| {
s.iter()
.map(|data| transform_neigh(*data, *transform))
.collect::<HashSet<_>>()
== s_set
}),
);
self
}
fn init_trans(mut self, b: &[u8], s: &[u8]) -> Self {
for alives in 0..=0xff {
let desc = (0xff & !alives) << 12 | 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_usize..=0xff {
let n = unknowns.next_power_of_two() >> usize::from(!unknowns.is_power_of_two());
for alives in (0..=0xff).filter(|a| a & unknowns == 0) {
let desc = (0xff & !alives & !unknowns) << 12 | alives << 4;
let desc0 = (0xff & !alives & !unknowns | n) << 12 | alives << 4;
let desc1 = (0xff & !alives & !unknowns) << 12 | (alives | n) << 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..0xffff {
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..=0xff {
for alives in (0..=0xff).filter(|a| a & unknowns == 0) {
let desc = (0xff & !alives & !unknowns) << 12 | 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_usize..=0xff {
for n in (0..8).map(|i| 1 << i).filter(|n| unknowns & n != 0) {
for alives in 0..=0xff {
let desc = (0xff & !alives & !unknowns) << 12 | alives << 4;
let desc0 = (0xff & !alives & !unknowns | n) << 12 | alives << 4;
let desc1 = (0xff & !alives & !unknowns) << 12 | (alives | n) << 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::from_bits_retain((n.pow(2) << 7) as u32);
} else if !possibly_dead && possibly_alive {
self.impl_table[index | state] |=
ImplFlags::from_bits_retain((n.pow(2) << 6) as u32);
} else if !possibly_dead && !possibly_alive {
self.impl_table[index | state] = ImplFlags::CONFLICT;
}
}
}
}
}
}
self
}
}
impl ParseNtLife for NtLife {
fn from_bs(b: Vec<u8>, s: Vec<u8>) -> Self {
let b = b
.into_iter()
.map(|b| transform_neigh(b, Transform::FlipAntidiag))
.collect::<Vec<_>>();
let s = s
.into_iter()
.map(|s| transform_neigh(s, Transform::FlipAntidiag))
.collect::<Vec<_>>();
Self::new(&b, &s)
}
}
impl FromStr for NtLife {
type Err = Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
let rule: Self = ParseNtLife::parse_rule(input).map_err(Error::ParseRuleError)?;
if rule.has_b0_s8() {
Err(Error::B0S8Error)
} else {
Ok(rule)
}
}
}
impl Sealed for NtLife {}
impl Rule for NtLife {
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 {
self.symmetry
}
#[inline]
fn new_desc(state: State, succ_state: State) -> Self::Desc {
let nbhd_state = match state {
ALIVE => 0x00ff,
_ => 0xff00,
};
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 nbhd_change_num = match state {
ALIVE => 0x0001,
_ => 0x0100,
};
for (i, &neigh) in cell.nbhd.iter().rev().enumerate() {
let neigh = neigh.unwrap();
let mut desc = neigh.desc.get();
desc.0 ^= nbhd_change_num << i << 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) {
for (i, &neigh) in cell.nbhd.iter().enumerate() {
if flags.intersects(ImplFlags::from_bits_retain(3 << (2 * i + 6))) {
if let Some(neigh) = neigh {
let state = if flags.contains(ImplFlags::from_bits_retain(1 << (2 * i + 7)))
{
DEAD
} else {
ALIVE
};
world.set_cell(neigh, state, A::Reason::from_cell(cell))?;
}
}
}
}
Ok(())
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct NbhdDescGen(u32, Option<State>);
#[derive(Clone)]
pub struct NtLifeGen {
b0: bool,
s8: bool,
gen: usize,
symmetry: Symmetry,
impl_table: Vec<ImplFlags>,
}
impl NtLifeGen {
pub fn new(b: &[u8], s: &[u8], gen: usize) -> Self {
let life = NtLife::new(b, s);
let impl_table = life.impl_table;
Self {
b0: life.b0,
s8: life.s8,
gen,
symmetry: life.symmetry,
impl_table,
}
}
pub fn non_gen(self) -> NtLife {
NtLife {
b0: self.b0,
s8: self.s8,
symmetry: self.symmetry,
impl_table: self.impl_table,
}
}
}
impl ParseNtLifeGen for NtLifeGen {
fn from_bsg(b: Vec<u8>, s: Vec<u8>, gen: usize) -> Self {
let b = b
.into_iter()
.map(|b| transform_neigh(b, Transform::FlipAntidiag))
.collect::<Vec<_>>();
let s = s
.into_iter()
.map(|s| transform_neigh(s, Transform::FlipAntidiag))
.collect::<Vec<_>>();
Self::new(&b, &s, gen)
}
}
impl FromStr for NtLifeGen {
type Err = Error;
fn from_str(input: &str) -> Result<Self, Self::Err> {
let rule: Self = ParseNtLifeGen::parse_rule(input).map_err(Error::ParseRuleError)?;
if rule.has_b0_s8() {
Err(Error::B0S8Error)
} else {
Ok(rule)
}
}
}
impl Sealed for NtLifeGen {}
impl Rule for NtLifeGen {
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 {
self.symmetry
}
#[inline]
fn new_desc(state: State, succ_state: State) -> Self::Desc {
let desc = NtLife::new_desc(state, succ_state);
NbhdDescGen(desc.0, Some(succ_state))
}
fn update_desc(cell: &LifeCell<Self>, state: State, new: bool) {
let nbhd_change_num = match state {
ALIVE => 0x0001,
_ => 0x0100,
};
for (i, &neigh) in cell.nbhd.iter().rev().enumerate() {
let neigh = neigh.unwrap();
let mut desc = neigh.desc.get();
desc.0 ^= nbhd_change_num << i << 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) {
for (i, &neigh) in cell.nbhd.iter().enumerate() {
if flags.intersects(ImplFlags::from_bits_retain(1 << (2 * i + 6))) {
if let Some(neigh) = neigh {
world.set_cell(neigh, ALIVE, A::Reason::from_cell(cell))?;
}
}
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rule_symmetry() {
let life: NtLife = "B3/S23".parse().unwrap();
assert_eq!(life.symmetry, Symmetry::D8);
let isotropic: NtLife = "B2ci3ai4c8/S02ae3eijkq4iz5ar6i7e".parse().unwrap();
assert_eq!(isotropic.symmetry, Symmetry::D8);
let hexagonal: NtLife = "B2/S34H".parse().unwrap();
assert_eq!(hexagonal.symmetry, Symmetry::D4Diag);
}
}