CAViewer - A Cellular Automaton Simulator written in Java

For scripts to aid with computation or simulation in cellular automata.
bprentice
Posts: 920
Joined: September 10th, 2009, 6:20 pm
Location: Coos Bay, Oregon

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by bprentice » May 8th, 2020, 11:19 am

martin.novy wrote:
May 8th, 2020, 8:34 am
would you mind, if I upload it to Github
Yes. First it is not a finished product and second I don't like Github.

Brian Prentice

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 9th, 2020, 4:57 am

Update v.1.14:

Added parameter maps (actually there is a very major and very very very annoying bug I have not fixed*)
The parameter map dialog is the same as the rule dialog.
In the rulestring section, you can input rulestrings like b3,"x+3"s2,3,"y+3".
x and y are 0-indexed. Remember to put expression in "<expression goes here>".
Also output is a .gif file.

Added my new notation for naive rules
In transFunc.py, there is also code to simulate Primodia rulespace.

*Arghhhhhhh! Someone pls help. I don't know how to fix the bug. Basically the rule in the parameter map stays the same across the grid. The code is ParamMap.py. Actually I don't think anyone can understand my code.

Source Code + WinPython Installation: https://github.com/jedlimlx/Cellular-Automaton-Viewer
Source Code:
Attachments
CAViewer.zip
(3.36 MiB) Downloaded 181 times
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

bprentice
Posts: 920
Joined: September 10th, 2009, 6:20 pm
Location: Coos Bay, Oregon

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by bprentice » May 9th, 2020, 9:08 am

bprentice wrote:
May 8th, 2020, 8:24 am
I will probably just write a python script to convert Animals.js to Square Cell pattern files
This has been done. All the patterns in Animals.js have been converted, tested and work correctly. They are included in this update:

Primordia.zip
(298.67 KiB) Downloaded 195 times

at ../Patterns

Brian Prentice

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 10th, 2020, 8:22 am

Could someone help me debug this code for the parameter maps?
dict_grid is where the pattern is stored.

Code: Select all

import copy
import importlib
import random
import traceback
from typing import List, Tuple

import CAComputeParse.CACompute as parser
import numpy as np
from PIL import Image

import RuleParser

param_map_array = []


def param_map(soup_size, x, y, max_generations, dict_grid):
    global param_map_array
    if RuleParser.n_states > 2:
        colour_palette: List[Tuple[int, int, int]] = [(0, 0, 0)] + \
                                                     [(255, 255 // (RuleParser.n_states - 2) * x, 0)
                                                      for x in range(RuleParser.n_states - 1)]
    else:
        colour_palette: List[Tuple[int, int, int]] = [(0, 0, 0), (255, 255, 255)]

    cells_changed = dict_grid.keys()  # Running Simulation
    for generations in range(max_generations):
        if generations == 100: print(sorted(dict_grid.keys()))
        copy_grid = copy.deepcopy(dict_grid)
        cells_changed, dict_grid = parser.compute(cells_changed, copy_grid, dict_grid, generations)

        keys_to_pop = []
        for key in dict_grid:
            if 0 <= key[0] <= soup_size * 3 and 0 <= key[1] <= soup_size * 3:  # Checking Within Bounds
                param_map_array[generations][soup_size * 3 * y + key[1]][soup_size * 3 * x + key[0]] = \
                    colour_palette[dict_grid[key]]
            else:
                keys_to_pop.append(key)

        for key in keys_to_pop:  # Delete cells outside boundary
            dict_grid.pop(key)


def generate_param_map(soup_size, rows, columns, generations):
    global param_map_array
    for i in range(generations):
        param_map_array.append(np.zeros((soup_size * 3 * rows + 1, soup_size * 3 * columns + 1, 3),
                                        dtype=np.uint8))

    dict_grid = {}  # Generating Random Soup
    for i in range(soup_size, soup_size * 2):
        for j in range(soup_size, soup_size * 2):
            if random.randint(0, 1):
                dict_grid[(i, j)] = 1

    for y in range(5):
        for x in range(5):
            print("Running", (x, y))
            try:
                rule = open(f"PMap/rule_{x}_{y}.ca_rule", "r")
                rule_contents = rule.read()
                rule.close()

                new_rule = open("PMap/rule.ca_rule", "w+")  # Transferring Rule
                new_rule.write(rule_contents)
                new_rule.close()

                print(rule_contents)

                parser.load("PMap/rule.ca_rule")
                RuleParser.load("PMap/rule.ca_rule")

                param_map(soup_size, x, y, generations, copy.deepcopy(dict_grid))
            except Exception:
                print(traceback.format_exc())

    img_frames: List = [Image.fromarray(x) for x in param_map_array]
    img_frames[0].save("pmap.gif", format='GIF', append_images=img_frames[1:],
                       save_all=True, loop=0)
    print("Done!")
The bug is that in each of the grid cells the rule is the same.
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 10th, 2020, 10:06 am

bprentice wrote:
May 9th, 2020, 9:08 am

All the patterns in Animals.js have been converted, tested and work correctly.
oh, that's nice

by the way, I guess Primordia could be comparable in behavior to some LtL (but Primordia is much faster).

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 10th, 2020, 10:15 am

lemon41625 wrote:
May 10th, 2020, 8:22 am
Could someone help me debug this code for the parameter maps?
dict_grid is where the pattern is stored.
The bug is that in each of the grid cells the rule is the same.

my own code, PyMartinCA, badly needs compatibility with Python 3,
and several refactorizations ...

I have to learn details about classes in Python

by the way, i guess, i cannot assume, that anybody here uses,
or wants to try,
jupyter notebook or ipython console ?

and i guess, i cannot assume,
that anybody here has scipy installed ?

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 10th, 2020, 11:10 am

Update v1.14.1:
Just a small patch (Bug still not fixed btw)
Added rules to sample rules folder (added some rules from animals.js, not all were added because some were boring and I didn't have time)
They are in the primodia subfolder of regenerating generations.

Also please help to fix problem with isotropic range 2 von neumann transFunc.py (it doesn't simulate SkewLife properly, also probably easier to fix than the param map bug)
The bug has actually been around for some time already. EDIT: Nvm the rulestring was wrong. I am lazy so could someone help me at the right rulestring. Thanks.

Code: Select all

rule_string = "0xgxlxn1cccdcgcickcl2cacccdcenanc3ca/0xn1cgcickcl2cccdcenc3ca"
outside_four_cells = {
    "a": [0, 0, 0, 0],
    "c": [1, 0, 0, 0],
    "d": [0, 1, 0, 0],
    "e": [0, 0, 1, 0],
    "f": [0, 0, 0, 1],
    "g": [1, 1, 0, 0],
    "i": [0, 1, 1, 0],
    "j": [0, 0, 1, 1],
    "k": [1, 0, 0, 1],
    "l": [1, 0, 1, 0],
    "m": [0, 1, 0, 1],
    "n": [1, 1, 1, 0],
    "o": [0, 1, 1, 1],
    "p": [1, 0, 1, 1],
    "q": [1, 1, 0, 1],
    "r": [1, 1, 1, 1]
}
hensel = {0: {"a": [0, 0, 0, 0, 0, 0, 0, 0]},
          1: {"c": [1, 0, 0, 0, 0, 0, 0, 0], "e": [0, 1, 0, 0, 0, 0, 0, 0]},
          2: {"c": [1, 0, 1, 0, 0, 0, 0, 0], "e": [0, 1, 0, 0, 0, 0, 0, 1],
              "k": [0, 1, 0, 0, 1, 0, 0, 0], "a": [1, 1, 0, 0, 0, 0, 0, 0],
              "i": [0, 1, 0, 0, 0, 1, 0, 0], "n": [1, 0, 0, 0, 1, 0, 0, 0]},
          3: {"c": [1, 0, 1, 0, 1, 0, 0, 0], "e": [0, 1, 0, 1, 0, 0, 0, 1],
              "k": [0, 1, 0, 0, 1, 0, 0, 1], "a": [1, 1, 0, 0, 0, 0, 0, 1],
              "i": [1, 0, 0, 0, 0, 0, 1, 1], "n": [1, 0, 1, 0, 0, 0, 0, 1],
              "y": [1, 0, 1, 0, 0, 1, 0, 0], "q": [1, 0, 0, 0, 1, 0, 0, 1],
              "j": [0, 0, 1, 1, 0, 1, 0, 0], "r": [0, 1, 1, 0, 0, 1, 0, 0]},
          4: {"c": [1, 0, 1, 0, 1, 0, 1, 0], "e": [0, 1, 0, 1, 0, 1, 0, 1],
              "k": [0, 1, 1, 0, 1, 0, 0, 1], "a": [1, 0, 0, 0, 0, 1, 1, 1],
              "i": [1, 0, 1, 1, 0, 0, 0, 1], "n": [1, 0, 0, 0, 1, 0, 1, 1],
              "y": [1, 0, 1, 0, 0, 1, 1, 0], "q": [1, 1, 0, 0, 1, 0, 0, 1],
              "j": [0, 0, 1, 1, 0, 1, 0, 1], "r": [0, 1, 1, 1, 0, 1, 0, 0],
              "t": [1, 1, 1, 0, 0, 1, 0, 0], "w": [1, 0, 0, 0, 1, 1, 0, 1],
              "z": [1, 1, 0, 0, 1, 1, 0, 0]},
          5: {"c": [0, 1, 0, 1, 0, 1, 1, 1], "e": [1, 0, 1, 0, 1, 1, 1, 0],
              "k": [1, 0, 1, 1, 0, 1, 1, 0], "a": [0, 0, 1, 1, 1, 1, 1, 0],
              "i": [0, 1, 1, 1, 1, 1, 0, 0], "n": [0, 1, 0, 1, 1, 1, 1, 0],
              "y": [0, 1, 0, 1, 1, 0, 1, 1], "q": [0, 1, 1, 1, 0, 1, 1, 0],
              "j": [1, 1, 0, 0, 1, 0, 1, 1], "r": [1, 0, 0, 1, 1, 0, 1, 1]},
          6: {"c": [0, 1, 0, 1, 1, 1, 1, 1], "e": [1, 0, 1, 1, 1, 1, 1, 0],
              "k": [1, 0, 1, 1, 0, 1, 1, 1], "a": [0, 0, 1, 1, 1, 1, 1, 1],
              "i": [1, 0, 1, 1, 1, 0, 1, 1], "n": [0, 1, 1, 1, 0, 1, 1, 1]},
          7: {"c": [0, 1, 1, 1, 1, 1, 1, 1], "e": [1, 0, 1, 1, 1, 1, 1, 1]},
          8: {"a": [1, 1, 1, 1, 1, 1, 1, 1]}}


def rotate(neighbours):
    return neighbours[2:8] + neighbours[:2] + neighbours[9:12] + [neighbours[8]]


def reflect_1(neighbours):
    return [neighbours[2], neighbours[1], neighbours[0], neighbours[7],
            neighbours[6], neighbours[5], neighbours[4], neighbours[3],
            neighbours[8], neighbours[11], neighbours[10], neighbours[9]]


def reflect_2(neighbours):
    return [neighbours[6], neighbours[5], neighbours[4], neighbours[3],
            neighbours[0], neighbours[1], neighbours[2], neighbours[7],
            neighbours[10], neighbours[9], neighbours[8], neighbours[11]]


def rotate_4_reflect(neighbours):
    lst = []
    rotate_1 = rotate(neighbours)
    rotate_2 = rotate(rotate_1)
    rotate_3 = rotate(rotate_2)

    lst.append(tuple(neighbours))
    lst.append(tuple(reflect_1(neighbours)))
    lst.append(tuple(reflect_2(neighbours)))

    lst.append(tuple(rotate_1))
    lst.append(tuple(reflect_1(rotate_1)))
    lst.append(tuple(reflect_2(rotate_1)))

    lst.append(tuple(rotate_2))
    lst.append(tuple(reflect_1(rotate_2)))
    lst.append(tuple(reflect_2(rotate_2)))

    lst.append(tuple(rotate_3))
    lst.append(tuple(reflect_1(rotate_3)))
    lst.append(tuple(reflect_2(rotate_3)))
    return lst


current_num = 0
current_trans = ""
birth_trans = []
birth_string = rule_string.split("/")[1]

for i in range(len(birth_string)):
    try:
        current_num = int(birth_string[i])
    except ValueError:
        current_trans += birth_string[i]
        if len(current_trans) == 2:
            if current_trans[0] != "x":
                birth_trans += rotate_4_reflect(
                    hensel[current_num][current_trans[0]] + outside_four_cells[current_trans[1]])
            else:
                for key in hensel[current_num]:
                    birth_trans += rotate_4_reflect(
                        hensel[current_num][key] + outside_four_cells[current_trans[1]])

            current_trans = ""

current_num = 0
current_trans = ""
survival_trans = []
survival_string = rule_string.split("/")[0]

for i in range(len(survival_string)):
    try:
        current_num = int(survival_string[i])
    except ValueError:
        current_trans += survival_string[i]
        if len(current_trans) == 2:
            if current_trans[0] != "x":
                survival_trans += rotate_4_reflect(
                    hensel[current_num][current_trans[0]] + outside_four_cells[current_trans[1]])
            else:
                for key in hensel[current_num]:
                    survival_trans += rotate_4_reflect(
                        hensel[current_num][key] + outside_four_cells[current_trans[1]])
            current_trans = ""

birth_trans, survival_trans = set(birth_trans), set(survival_trans)

# Information about the Rule (Must be filled)
n_states = 2  # Number of States
alternating_period = 1  # For alternating rules / neighbourhoods
colour_palette = None  # Colours of the different states
rule_name = "Range 2 Isotropic Von Neumann"  # Rule Name


# Neighbourhood of the Rule (Relative Distance from Central Cell)
def get_neighbourhood(generation):  # Note (y, x) not (x, y)
    return [(1, -1), (1, 0), (1, 1), (0, 1),
            (-1, 1), (-1, 0), (-1, -1), (0, -1),
            (2, 0), (0, 2), (-2, 0), (0, -2)]


# Transition Function of Rule, Last Element of Neighbours is the Central Cell
def transition_func(neighbours, generation):
    if neighbours[-1] == 1:
        if tuple(neighbours[:-1]) in survival_trans:
            return 1
        return 0

    elif neighbours[-1] == 0:
        if tuple(neighbours[:-1]) in birth_trans:
            return 1
        return 0


# Does the next state of the cell depend on its neighbours?
# If yes, return next state
# If no, return -1
def depend_on_neighbours(state, generation):
    return -1
martin.novy wrote:
May 10th, 2020, 10:15 am
lemon41625 wrote:
May 10th, 2020, 8:22 am
Could someone help me debug this code for the parameter maps?
dict_grid is where the pattern is stored.
The bug is that in each of the grid cells the rule is the same.

my own code, PyMartinCA, badly needs compatibility with Python 3,
and several refactorizations ...

I have to learn details about classes in Python

by the way, i guess, i cannot assume, that anybody here uses,
or wants to try,
jupyter notebook or ipython console ?

and i guess, i cannot assume,
that anybody here has scipy installed ?
I have scipy installed since I use Anaconda. Also use jupyter notebook (actually google colab) for making neural nets (because free gpu)
by the way, I guess Primordia could be comparable in behavior to some LtL (but Primordia is much faster).
Why whould primodia behave similiarly to LtL?

Source Code + WinPython Installation: https://github.com/jedlimlx/Cellular-Automaton-Viewer
Source Code:
Attachments
CAViewer.zip
(3.36 MiB) Downloaded 166 times
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 11th, 2020, 9:56 am

lemon41625 wrote:
May 10th, 2020, 8:22 am
Could someone help me debug this code for the parameter maps?
dict_grid is where the pattern is stored.


if 0 <= key[0] <= soup_size * 3 and 0 <= key[1] <= soup_size * 3: # Checking Within Bounds
param_map_array[generations][soup_size * 3 * y + key[1]][soup_size * 3 * x + key[0]] = \

param_map_array.append(np.zeros((soup_size * 3 * rows + 1, soup_size * 3 * columns + 1, 3),

The bug is that in each of the grid cells the rule is the same.
what is the meaning of these constants: 3


.....
can anybody make a small demo, where

CELLS[0:4, 0:4] have 1 rule, and

CELLS[0:4, 4:8] have a different rule ?


.....
or maybe better

CELLS[0:4, 0:4, 0] have 1 rule, and

CELLS[0:4, 0:4, 1] have a different rule ?

....
Last edited by martin.novy on May 11th, 2020, 11:57 am, edited 1 time in total.

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 11th, 2020, 10:36 am

The 3 represents that the size of the grid where the soup is placed is 3x the soup size.
For example,
. . . . . .
. . . . . .
. . * * . .
. . * * . .
. . . . . .
. . . . . .
martin.novy wrote:
May 11th, 2020, 9:56 am
it seems to me, that right now
https://github.com/jedlimlx/Cellular-Au ... le.ca_rule
defines only one rule
Rulestring: b4s2,4
The program transfers the rule contents into the rule file. If you were to actually execute the parameter map function, there will be many more rule files in the PMap folder.
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 11th, 2020, 12:02 pm

lemon41625 wrote:
May 11th, 2020, 10:36 am
The 3 represents that the size of the grid where the soup is placed is 3x the soup size.
and what is the meaning of the 3 at the end :

param_map_array.append(np.zeros((soup_size * 3 * rows + 1, soup_size * 3 * columns + 1, 3),
dtype=np.uint8))

...

i can make a demo ... tomorrow , i hope

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 11th, 2020, 7:24 pm

martin.novy wrote:
May 11th, 2020, 12:02 pm
lemon41625 wrote:
May 11th, 2020, 10:36 am
The 3 represents that the size of the grid where the soup is placed is 3x the soup size.
and what is the meaning of the 3 at the end :

param_map_array.append(np.zeros((soup_size * 3 * rows + 1, soup_size * 3 * columns + 1, 3),
dtype=np.uint8))

...

i can make a demo ... tomorrow , i hope
It represents the 3 colour channels.
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 12th, 2020, 9:53 am

lemon41625 wrote:
May 10th, 2020, 8:22 am
Could someone help me debug this code for the parameter maps?
dict_grid is where the pattern is stored.
The bug is that in each of the grid cells the rule is the same.
my parameter map demo ... jupyter notebook (actually google colab)

https://colab.research.google.com/drive ... sp=sharing

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 13th, 2020, 10:31 am

Update v1.15:

Finished Range 2 Von Neumann INT transFunc.py script (fixed all bugs, I think).
Added Hunting Semi Totalistic Rulespace (Avaliable for Single State, Extended Generations, BSFKL and Regenerating Generations Rules)
Added a Range 2 Von Neumann INT rule to rules folder.
Rulestring is b1en2icig3cd3x5x-3kgs2x3x8x. There are some oscillators and a fairly common diagonal spaceship.

Next update I will add Range 2 Cross INT rules, Range 1 Moore INT Rules (then we can explore BSFKL with hensel notation YAY) and bubblegum's (B/M/S)*2 Notation for 3 state outer totalistic rules.
Also will fixed param map bug. Hopefully martin.novy's demo may help me to fixed the problem.
Why don't I recall the notation being discussed here: https://conwaylife.com/forums/viewtopic ... tic#p88439?

Also are there any feature requests or have any bugs been found?
INT.gif
INT.gif (519.22 KiB) Viewed 7150 times
Source Code + WinPython Installation: https://github.com/jedlimlx/Cellular-Automaton-Viewer
Source Code:
Attachments
CAViewer.zip
(3.61 MiB) Downloaded 172 times
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 14th, 2020, 6:45 am

lemon41625 wrote:
May 9th, 2020, 4:57 am

In the rulestring section, you can input rulestrings like b3,"x+3"s2,3,"y+3".
can you try in CAViewer
the b"x+2"s2,3
x='0..1'
like in my CoLab demo 2
-------------------------------
or should I try it in CAViewer ?
I could try to print values of everything

https://github.com/jedlimlx/Cellular-Au ... in.py#L180

Code: Select all

    param_map_dialog.run_param.connect(lambda: param_map.generate_param_map(50, 5, 5, 500))

i could try param_map.generate_param_map(10, 1, 2, 1)
Last edited by martin.novy on May 14th, 2020, 9:17 am, edited 2 times in total.

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 14th, 2020, 8:01 am

In CAViewer,
the x and y goes from 0 - 4. I will add a way to change this later after I fix the bug.
Alternatively, in the code there is a line “for y in range(5)”. Change the 5 for the x and y loop to 2 for 0 - 1.
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 14th, 2020, 10:13 am

lemon41625 wrote:
May 13th, 2020, 10:31 am
Update v1.15:
i cannot find, who (module.function ) and where
reads the file
"PMap/rule.ca_rule"
, that is written at

https://github.com/jedlimlx/Cellular-Au ... Map.py#L65

Code: Select all

                new_rule = open("PMap/rule.ca_rule", "w+")  # Transferring Rule

... is it somewhere under CAComputeParse ?? .py ? .cpp ? .pyx ?
...
what is the name of the function that can read
"PMap/rule.ca_rule" ?
shouldn't that function be called before
cells_changed, dict_grid = parser.compute(cells_changed, copy_grid, dict_grid, generations)
?

https://github.com/jedlimlx/Cellular-Au ... as.py#L913
there are many times
("rule.ca_rule",
isn't it in a differrent folder than
"PMap/rule.ca_rule" ?

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 14th, 2020, 10:49 am

"PMap/rule.ca_rule" is for the parameter maps.
"rule.ca_rule" is for the normal simulation.

parser.load reloads the rule.
The source code for parser is under CAComputeParse/CACompute.pyx. It is written in Cython because I want a fast simulation and C++ is hard to code.

Code: Select all

new_rule = open("PMap/rule.ca_rule", "w+")
This code transfers the rule contents from PMap/rule_{x}_{y}.ca_rule into PMap/rule.ca_rule where x and y are between 0 and 4 both inclusive.
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 14th, 2020, 1:16 pm

lemon41625 wrote:
May 14th, 2020, 10:49 am
oh, sorry, i didn't notice, what i asked about was 6 lines above what i saw
https://github.com/jedlimlx/Cellular-Au ... Map.py#L25

----
is it possible to do

Code: Select all


import CAComputeParse.CACompute as parser

parser.load("PMap/rule.ca_rule")

from a jupyter notebook ?
edit: it seems possible

----
how can i put a blinker into a dict_grid
EDIT: dict_grid={(1,1):1,(1,2):1,(1,3):1}
seems working
---------
is it possible to use print() inside pyx ?
Attachments
test-CAViewer-calling1.ipynb.zip
(793 Bytes) Downloaded 119 times
Last edited by martin.novy on May 15th, 2020, 7:56 am, edited 1 time in total.

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 14th, 2020, 7:42 pm

No, I wish I could use print but I can't. To get debug info, you need to write to a file.
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 15th, 2020, 5:37 am

lemon41625 wrote:
May 14th, 2020, 7:42 pm
No, I wish I could use print but I can't. To get debug info, you need to write to a file.
is it possible to temporarily , for debugging,
convert .pyx to .py ?
EDIT: i researched for a while, and made some diigo highlights,
https://www.diigo.com/user/martin12333
but it doesn't seem much possible

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 15th, 2020, 7:08 am

lemon41625 wrote:
May 13th, 2020, 10:31 am
Update v1.15:

one strange thing but maybe it is correct?

yesterday,when I installed the version, and
I ran my linux-setup.sh script

Code: Select all

#running apt install twice is almost a no operation
/usr/bin/sudo  apt install  python3-pyqt5  python3-pyperclip  python3-numpy python3-pil
/usr/bin/sudo  apt install  cython3

cd CAViewer/

cd CACompute
touch __init__.py
cp -i Compute.cpp compute.cpp
#python3  setup.py --help
python3  setup.py build_ext --inplace
cd ..

cd CAComputeParse/
touch __init__.py
cp -i Compute.cpp compute.cpp
python3  setup.py build_ext --inplace
cd ..

#export DISPLAY=:0
echo python3   Main.py  


then python3 Main.py ...
could not start
...
ModuleNotFoundError: No module named 'CAComputeParse.CACompute'

, because

the compilation produced

CAViewer/CAComputeParse/CAComputeParse/CACompute.cpython-36m-x86_64-linux-gnu.so

the path
CAViewer/CAComputeParse/CAComputeParse/
is a bit strange?

week ago, the compilation produced
CAViewer/CAComputeParse/CACompute.cpython-36m-x86_64-linux-gnu.so ... a shorter path ... CAViewer/CAComputeParse

my naive fix was to copy the file
CAViewer/CAComputeParse/CAComputeParse/CACompute.cpython-36m-x86_64-linux-gnu.so
to
CAViewer/CAComputeParse/CACompute.cpython-36m-x86_64-linux-gnu.so

then python3 Main.py
could start OK


how do *you* compile it?
Last edited by martin.novy on May 15th, 2020, 10:42 am, edited 3 times in total.

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 15th, 2020, 7:21 am

martin.novy wrote:
May 15th, 2020, 7:08 am
then python3 Main.py ... failed, because

the compilation produced

CAViewer/CAComputeParse/CAComputeParse/CACompute.cpython-36m-x86_64-linux-gnu.so

the path
CAViewer/CAComputeParse/CAComputeParse/
is a bit strange?

week ago, the compilation produced
CAViewer/CAComputeParse/CACompute.cpython-36m-x86_64-linux-gnu.so ... a shorter path ... CAViewer/CAComputeParse

my naive fix was to copy the file CACompute.cpython to
CAViewer/CAComputeParse/CACompute.cpython-36m-x86_64-linux-gnu.so

then it worked


how do *you* compile it?
When you say then it worked do you mean the parameter map thing worked?

I compile it by first "cd" into the CAComputeParse directory.
Then, I run python setup.py build_ext --inplace and leave it as it is.
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 15th, 2020, 7:24 am

lemon41625 wrote:
May 15th, 2020, 7:21 am

When you say then it worked do you mean the parameter map thing worked?
sorry, no, I mean: I was able to start the
python3 Main.py

User avatar
martin.novy
Posts: 142
Joined: October 22nd, 2014, 6:22 am
Location: Czechia, EU
Contact:

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by martin.novy » May 15th, 2020, 7:55 am

lemon41625 wrote:
May 14th, 2020, 10:49 am
"PMap/rule.ca_rule" is for the parameter maps.
parser.load reloads the rule.

this could be interesting:
I have
narrowed-down
steps to reproduce a param map bug

in a jupyter notebook
test-CAViewer-calling2.ipynb.zip
(826 Bytes) Downloaded 124 times
1. run every jupyter cell ... the blinker behaves like a blinker OK
{(0, 2): 1, (1, 2): 1, (2, 2): 1}

2. edit PMap/rule.ca_rule
add birth 2 ... b2,

Code: Select all

Name: uhjhj_2_1

Neighbourhood Range: 2

Neighbourhood:
0,0,0,0,0
0,1,1,1,0
0,1,0,1,0
0,1,1,1,0
0,0,0,0,0

State Weights: 0,1

Rulespace: Single State

B/S Conditions: Outer Totalistic

Rulestring: b2,3,5s2,3,4

Colour Palette:
None
3. rerun these jupyter cells:

Code: Select all


parser.load("PMap/rule.ca_rule")

max_generations=1 #3
dict_grid={(1,1):1,(1,2):1,(1,3):1}


cells_changed = dict_grid.keys()  # Running Simulation
for generations in range(max_generations):
    copy_grid = copy.deepcopy(dict_grid)
    cells_changed, dict_grid = parser.compute(cells_changed, copy_grid, dict_grid, generations)

    
dict_grid
{(0, 2): 1, (1, 2): 1, (2, 2): 1}
...strange

4.jupyter kernel restart
5. run every jupyter cell ... the blinker behaves like with b2
{(0, 1): 1, (0, 2): 1, (0, 3): 1, (1, 2): 1, (2, 1): 1, (2, 2): 1, (2, 3): 1}

...interesting

lemon41625
Posts: 351
Joined: January 24th, 2020, 7:39 am
Location: 小红点 (if you know where that is)

Re: CAViewer - A Cellular Automaton Simulator written in Python

Post by lemon41625 » May 15th, 2020, 8:12 am

Well, that helps to narrow down the problem to the code inside CAComputeParse.pyx.

Try replacing the code in CAComputeParse.pyx with this code and recompile it. It should output what it thinks are the birth and survival conditions into log.log.

Code: Select all

# distutils: language=c++

import re
from libcpp.vector cimport vector
from libcpp.pair cimport pair
from libcpp.map cimport map
from libcpp cimport bool
from libcpp.string cimport string
from libcpp.algorithm cimport sort
from libcpp.unordered_map cimport unordered_map
from libcpp.unordered_set cimport unordered_set

cdef vector[vector[int]] colour_palette
cdef string rule_name
cdef string rule_space, bsconditions
cdef int n_states
cdef vector[unordered_map[pair[int, int], int]] index_map
cdef vector[vector[int]] state_weights
cdef vector[vector[pair[int, int]]] neighbourhood, original_neighbourhood
cdef vector[vector[int]] neighbourhood_weights
cdef int alternating_period, birth_state
cdef vector[unordered_set[int]] birth, survival, forcing, killing, living, \
    regen_birth, regen_survival, activity_list, other_birth, other_survival, \
    other_regen_birth, other_regen_survival, other_forcing, other_killing, other_living
cdef vector[unordered_set[pair[int, int]]] birth_semi_1, survival_semi_1, forcing_semi_1, killing_semi_1, living_semi_1, \
    regen_birth_semi_1, regen_survival_semi_1
cdef vector[string] naive_lst, direction_lst
cdef vector[int] corner_lst, xy_lst
cdef int corner, xy
cdef string direction

cdef extern from "compute.cpp":
    pass

cpdef load(filename):
    global colour_palette, rule_name, rule_space, n_states, state_weights, neighbourhood, neighbourhood_weights,\
        alternating_period, birth, survival, forcing, killing, living, \
        regen_birth, regen_survival, activity_list, birth_state, other_birth, other_survival, bsconditions, \
        original_neighbourhood, index_map, other_forcing, other_killing, other_living, naive_lst, direction_lst, \
        corner_lst, xy_lst, birth_semi_1, survival_semi_1, forcing_semi_1, killing_semi_1, living_semi_1,\
        regen_birth_semi_1, regen_survival_semi_1

    colour_palette.clear()
    rule_name = b""
    rule_space = b""
    bsconditions = b""
    n_states = 0
    state_weights.clear()
    neighbourhood.clear()
    neighbourhood_weights.clear()
    original_neighbourhood.clear()
    alternating_period = 0
    birth_state = 0
    birth.clear()
    survival.clear()
    forcing.clear()
    killing.clear()
    living.clear()
    index_map.clear()
    activity_list.clear()
    regen_birth.clear()
    regen_survival.clear()
    other_birth.clear()
    other_survival.clear()
    other_forcing.clear()
    other_killing.clear()
    other_living.clear()
    other_regen_birth.clear()
    other_regen_survival.clear()
    birth_semi_1.clear()
    survival_semi_1.clear()
    forcing_semi_1.clear()
    killing_semi_1.clear()
    living_semi_1.clear()
    regen_birth_semi_1.clear()
    regen_survival_semi_1.clear()
    naive_lst.clear()
    direction_lst.clear()
    corner_lst.clear()
    xy_lst.clear()
    corner = -1
    xy = -1
    direction = b"o"

    cdef string rule

    cdef int neighbourhood_count = 0
    cdef vector[vector[int]] current_neighbourhood_weights
    cdef vector[vector[vector[int]]] unflattened_neighbourhood_weights
    cdef unordered_set[pair[int, int]] set_neighbourhood
    cdef pair[int, int] neighbour, neighbour2
    cdef bool parsing_neighbourhood = False

    cdef int colour_palette_count = 0
    cdef vector[int] temp
    cdef bool parsing_colour_palette = False

    cdef string section
    cdef vector[string] rule_string

    cdef int neighbourhood_range = 0

    cdef int i, j
    cdef vector[vector[int]] weights
    cdef vector[pair[int, int]] pair_temp
    cdef unordered_map[pair[int, int], int] map_temp

    cdef vector[int] k

    cdef int num, alt
    cdef unordered_set[int] set_temp
    cdef unordered_set[pair[int, int]] temp_semi_1
    cdef vector[int] extended

    file = open(filename, "r")
    rule = file.read().encode("utf-8")

    for section in rule.split(b"\n"):
        if section.find(b"Neighbourhood:") != -1 or section.find(b"#") != -1:
            neighbourhood_count = 0
            parsing_neighbourhood = True
            current_neighbourhood_weights.clear()
            continue
        elif parsing_neighbourhood:
            temp.clear()
            for x in section.split(b","):
                temp.push_back(int(x))
            current_neighbourhood_weights.push_back(temp)
            neighbourhood_count += 1
            if neighbourhood_count == neighbourhood_range * 2 + 1:
                parsing_neighbourhood = False
                unflattened_neighbourhood_weights.push_back(current_neighbourhood_weights)
            continue

        if section.find(b"Colour Palette:") != -1:
            parsing_colour_palette = True
            continue
        elif parsing_colour_palette:
            if section.find(b"None") != -1:
                colour_palette.clear()
                parsing_colour_palette = False
                continue

            temp.clear()
            for x in section.split(b","):
                temp.push_back(int(re.sub(b"[() ]", b"", x)))
            colour_palette.push_back(temp)
            colour_palette_count += 1
            if colour_palette_count == n_states:
                parsing_colour_palette = False
            continue

        if section.find(b"Name:") != -1:
            rule_name = section.replace(b"Name: ", b"")
        elif section.find(b"Neighbourhood Range:") != -1:
            neighbourhood_range = int(section.replace(b"Neighbourhood Range: ", b""))
        elif section.find(b"State Weights:") != -1:
            for x in section.replace(b"State Weights: ", b"").split(b"|"):
                temp.clear()
                for y in x.split(b","):
                    temp.push_back(int(y))
                state_weights.push_back(temp)
            n_states = state_weights[0].size()
        elif section.find(b"Rulespace:") != -1:
            rule_space = section.replace(b"Rulespace: ", b"")
        elif section.find(b"B/S Conditions:") != -1:
            bsconditions = section.replace(b"B/S Conditions: ", b"")
        elif section.find(b"Rulestring:") != -1:
            rule_string = section.replace(b"Rulestring: ", b"").split(b"|")

    alternating_period = state_weights.size()

    for weights in unflattened_neighbourhood_weights:
        pair_temp.clear()
        for i in range(-neighbourhood_range, neighbourhood_range + 1):
            for j in range(-neighbourhood_range, neighbourhood_range + 1):
                if weights[i + neighbourhood_range][j + neighbourhood_range] != 0:
                    pair_temp.push_back(pair[int, int] (i, j))

        neighbourhood.push_back(pair_temp)

    if bsconditions == b"Double Totalistic":
        original_neighbourhood = neighbourhood
        neighbourhood.clear()
        for i in range(alternating_period):
            set_neighbourhood.clear()
            for neighbour in original_neighbourhood[i]:
                for neighbour2 in original_neighbourhood[i]:
                    set_neighbourhood.insert(pair[int, int] (neighbour.first + neighbour2.first,
                                                             neighbour.second + neighbour2.second))
                set_neighbourhood.insert(neighbour)

            pair_temp.clear()
            pair_temp.insert(pair_temp.end(), set_neighbourhood.begin(), set_neighbourhood.end())
            neighbourhood.push_back(pair_temp)

            map_temp.clear()
            for j in range(len(neighbourhood[i])):
                map_temp[neighbourhood[i][j]] = j
            index_map.push_back(map_temp)

    for weights in unflattened_neighbourhood_weights:
        temp.clear()
        for k in weights:
            for j in k:
                if j != 0:
                    temp.push_back(j)

        neighbourhood_weights.push_back(temp)

    if rule_space == b"Single State":
        for individual_rule_string in rule_string:
            if bsconditions == b"Outer Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[1].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[2])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    set_temp.clear()
                    for x in re.split(b"b|s|nn", individual_rule_string)[1].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.split(b"b|s|nn", individual_rule_string)[2].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    try: naive_lst.push_back(re.split(b"b|s|nn", individual_rule_string)[3])
                    except IndexError: naive_lst.push_back(b"-1")
            elif bsconditions == b"Double Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[1])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[0])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[1]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[0]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_survival.push_back(set_temp)

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[2])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"b|s|nn", individual_rule_string)[1])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"b|s|nn", individual_rule_string)[2])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"b|s|nn", individual_rule_string)[1]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"b|s|nn", individual_rule_string)[2]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_survival.push_back(set_temp)

                    try: naive_lst.push_back(re.split(b"b|s|nn", individual_rule_string)[3])
                    except IndexError: naive_lst.push_back(b"-1")
            elif bsconditions == b"Range 1 Moore Semi Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    temp_semi_1.clear()
                    current_trans = []
                    for x in individual_rule_string.split(b"/")[1]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    birth_semi_1.push_back(temp_semi_1)

                    temp_semi_1.clear()
                    current_trans = []
                    for x in individual_rule_string.split(b"/")[0]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    survival_semi_1.push_back(temp_semi_1)

                    file = open("log.log", "a")
                    file.write(str(birth_semi_1) + " " + str(survival_semi_1) + "\n")
                    file.close()

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[2])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    temp_semi_1.clear()
                    current_trans = []
                    for x in re.split(b"b|s|nn", individual_rule_string)[1]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    birth_semi_1.push_back(temp_semi_1)

                    temp_semi_1.clear()
                    for x in re.split(b"b|s|nn", individual_rule_string)[2]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    survival_semi_1.push_back(temp_semi_1)

                    try: naive_lst.push_back(re.split(b"b|s|nn", individual_rule_string)[3])
                    except IndexError: naive_lst.push_back(b"-1")
    elif rule_space == b"BSFKL":
        for individual_rule_string in rule_string:
            if bsconditions == b"Outer Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[1].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[2].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    forcing.push_back(set_temp)

                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[3].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    killing.push_back(set_temp)

                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[4].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    living.push_back(set_temp)

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[5])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    set_temp.clear()
                    for x in re.split(b"b|s|f|k|l|nn", individual_rule_string)[1].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.split(b"b|s|f|k|l|nn", individual_rule_string)[2].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.split(b"b|s|f|k|l|nn", individual_rule_string)[3].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    forcing.push_back(set_temp)

                    set_temp.clear()
                    for x in re.split(b"b|s|f|k|l|nn", individual_rule_string)[4].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    killing.push_back(set_temp)

                    set_temp.clear()
                    for x in re.split(b"b|s|f|k|l|nn", individual_rule_string)[5].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    living.push_back(set_temp)

                    try: naive_lst.push_back(re.split(b"b|s|f|k|l|nn", individual_rule_string)[6])
                    except IndexError: naive_lst.push_back(b"-1")
            elif bsconditions == b"Double Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[0])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[1])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[2])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    forcing.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[3])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    killing.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[4])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    living.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[0]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[1]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[2]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_forcing.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[3]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_killing.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[4]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_living.push_back(set_temp)

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[5])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"b|s|f|k|l|nn", individual_rule_string)[1])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"b|s|f|k|l|nn", individual_rule_string)[2])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"b|s|f|k|l|nn", individual_rule_string)[3])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    forcing.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"b|s|f|k|l|nn", individual_rule_string)[4])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    killing.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"b|s|f|k|l|nn", individual_rule_string)[5])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    living.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"b|s|f|k|l|nn", individual_rule_string)[1]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"b|s|f|k|l|nn", individual_rule_string)[2]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"b|s|f|k|l|nn", individual_rule_string)[3]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_forcing.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"b|s|f|k|l|nn", individual_rule_string)[4]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_killing.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"b|s|f|k|l|nn", individual_rule_string)[5]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_living.push_back(set_temp)

                    try: naive_lst.push_back(re.split(b"b|s|f|k|l|nn", individual_rule_string)[6])
                    except IndexError: naive_lst.push_back(b"-1")
            elif bsconditions == b"Range 1 Moore Semi Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    current_trans = []
                    temp_semi_1.clear()
                    for x in individual_rule_string.split(b"/")[0]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    birth_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in individual_rule_string.split(b"/")[1]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    survival_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in individual_rule_string.split(b"/")[2]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    forcing_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in individual_rule_string.split(b"/")[3]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    killing_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in individual_rule_string.split(b"/")[4]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    living_semi_1.push_back(temp_semi_1)

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[5])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    current_trans = []
                    temp_semi_1.clear()
                    for x in re.split(b"b|s|f|k|l|nn", individual_rule_string)[1]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    birth_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in re.split(b"b|s|f|k|l|nn", individual_rule_string)[2]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    survival_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in re.split(b"b|s|f|k|l|nn", individual_rule_string)[3]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    forcing_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in re.split(b"b|s|f|k|l|nn", individual_rule_string)[4]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    killing_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in re.split(b"b|s|f|k|l|nn", individual_rule_string)[5]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    living_semi_1.push_back(temp_semi_1)

                    try: naive_lst.push_back(re.split(b"b|s|f|k|l|nn", individual_rule_string)[6])
                    except IndexError: naive_lst.push_back(b"-1")
    elif rule_space == b"Extended Generations":
        for individual_rule_string in rule_string:
            if bsconditions == b"Outer Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[1].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    extended.clear()
                    for x in individual_rule_string.split(b"/")[2].split(b"-"):
                        extended.push_back(int(x))

                    try: naive_lst.push_back(int(individual_rule_string.split(b"/")[3]))
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    set_temp.clear()
                    for x in re.split(b"b|s|d|nn", individual_rule_string)[1].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.split(b"b|s|d|nn", individual_rule_string)[2].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    extended.clear()
                    for x in re.split(b"b|s|d|nn", individual_rule_string)[3].split(b"-"):
                        extended.push_back(int(x))

                    try: naive_lst.push_back(re.split(b"b|s|d|nn", individual_rule_string)[4])
                    except IndexError: naive_lst.push_back(b"-1")
            elif bsconditions == b"Double Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[1])[0].split(b","):
                        set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[0])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[1]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[0]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_survival.push_back(set_temp)

                    extended.clear()
                    for x in individual_rule_string.split(b"/")[2].split(b"-"):
                        extended.push_back(int(x))

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[3])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"[bsd]", individual_rule_string)[1])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"[bsd]", individual_rule_string)[2])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"[bsd]", individual_rule_string)[1]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"[bsd]", individual_rule_string)[2]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_survival.push_back(set_temp)

                    extended.clear()
                    for x in re.split(b"[bsd]", individual_rule_string)[3].split(b"-"):
                        extended.push_back(int(x))

                    try: naive_lst.push_back(re.split(b"b|s|d|nn", individual_rule_string)[4])
                    except IndexError: naive_lst.push_back(b"-1")
            elif bsconditions == b"Range 1 Moore Semi Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    temp_semi_1.clear()
                    current_trans = []
                    for x in individual_rule_string.split(b"/")[1]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    birth_semi_1.push_back(temp_semi_1)

                    temp_semi_1.clear()
                    current_trans = []
                    for x in individual_rule_string.split(b"/")[0]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    survival_semi_1.push_back(temp_semi_1)

                    file = open("log.log", "a")
                    file.write(str(birth_semi_1) + " " + str(survival_semi_1) + "\n")
                    file.close()

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[3])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    temp_semi_1.clear()
                    current_trans = []
                    for x in re.split(b"b|s|d|nn", individual_rule_string)[1]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    birth_semi_1.push_back(temp_semi_1)

                    temp_semi_1.clear()
                    for x in re.split(b"b|s|d|nn", individual_rule_string)[2]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    survival_semi_1.push_back(temp_semi_1)

                    extended.clear()
                    for x in re.split(b"b|s|d|nn", individual_rule_string)[3].split(b"-"):
                        extended.push_back(int(x))

                    try: naive_lst.push_back(re.split(b"b|s|nn", individual_rule_string)[4])
                    except IndexError: naive_lst.push_back(b"-1")

            num, alt = 1, 1
            set_temp.clear()
            for i in extended:
                for j in range(num, i + num):
                    if alt > 0:
                        set_temp.insert(j)
                    num += 1
                alt *= -1

            activity_list.push_back(set_temp)
    elif rule_space == b"Regenerating Generations":
        for individual_rule_string in rule_string:
            if bsconditions == b"Outer Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    birth_state = int(individual_rule_string.split(b"/")[1])

                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[2].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[3].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[4].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    regen_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in individual_rule_string.split(b"/")[5].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    regen_survival.push_back(set_temp)

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[6])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    birth_state = int(re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[2])

                    set_temp.clear()
                    for x in re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[3].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[4].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[5].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    regen_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[6].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    regen_survival.push_back(set_temp)

                    try: naive_lst.push_back(re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[7])
                    except IndexError: naive_lst.push_back(b"-1")
            elif bsconditions == b"Double Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    birth_state = int(individual_rule_string.split(b"/")[1])

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[2])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[3])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[2]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[3]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[4])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    regen_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", individual_rule_string.split(b"/")[5])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    regen_survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[4]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_regen_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", individual_rule_string.split(b"/")[5]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_regen_survival.push_back(set_temp)

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[6])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    birth_state = int(re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[2])

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[3])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[4])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[3]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[4]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[5])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    regen_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.findall(b"\((.*?)\)", re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[6])[0].split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    regen_survival.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[5]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_regen_birth.push_back(set_temp)

                    set_temp.clear()
                    for x in re.sub(b"\(.*?\)", b"", re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[6]).split(b","):
                        if x.find(b"-") != -1:
                            for i in range(int(x.split(b"-")[0]), int(x.split(b"-")[1]) + 1):
                                set_temp.insert(i)
                        else:
                            set_temp.insert(int(x))
                    other_regen_survival.push_back(set_temp)

                    try: naive_lst.push_back(re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[7])
                    except IndexError: naive_lst.push_back(b"-1")
            elif bsconditions == b"Range 1 Moore Semi Totalistic":
                if individual_rule_string.find(b"/") != -1:
                    birth_state = int(individual_rule_string.split(b"/")[1])

                    current_trans = []
                    temp_semi_1.clear()
                    for x in individual_rule_string.split(b"/")[2]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    birth_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in individual_rule_string.split(b"/")[3]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    survival_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in individual_rule_string.split(b"/")[4]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    regen_birth_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in individual_rule_string.split(b"/")[5]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    regen_survival_semi_1.push_back(temp_semi_1)

                    try: naive_lst.push_back(individual_rule_string.split(b"/")[6])
                    except IndexError: naive_lst.push_back(b"-1")
                else:
                    birth_state = int(re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[2])

                    current_trans = []
                    temp_semi_1.clear()
                    for x in re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[3]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    birth_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[4]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    survival_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[5]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    regen_birth_semi_1.push_back(temp_semi_1)

                    current_trans = []
                    temp_semi_1.clear()
                    for x in re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[6]:
                        current_trans.append(int(str(x)))
                        if len(current_trans) == 2:
                            temp_semi_1.insert(pair[int, int] (current_trans[0] - 48, current_trans[1] - 48))
                            current_trans = []
                    regen_survival_semi_1.push_back(temp_semi_1)

                    try: naive_lst.push_back(re.split(b"rg|l|b|s|rb|rs|nn", individual_rule_string)[7])
                    except IndexError: naive_lst.push_back(b"-1")

    for x in naive_lst:
        if x != b"-1":
            corner_lst.push_back(int(x.decode("utf-8")[0]))
            direction_lst.push_back(str(x.decode("utf-8")[1]).encode("utf-8"))
            xy_lst.push_back(int(x.decode("utf-8")[2]))
        else:
            corner_lst.push_back(-1)
            direction_lst.push_back(b"")
            xy_lst.push_back(-1)


cpdef vector[pair[int, int]] get_neighbourhood(int generations):
    return neighbourhood[generations % alternating_period]

cpdef int get_n_states():
    return n_states

cpdef vector[vector[int]] get_colour_palette():
    return colour_palette

cpdef string get_rule_name():
    return rule_name

cdef int transition_func(vector[int] neighbours, int generations):
    cdef int n_living = 0, n_destructive = 0, n = 0, n_birth = 0, n_survival = 0, index, found_index, idx, \
        n_regen_birth = 0, n_regen_survival = 0, n_forcing = 0, n_killing = 0, n1 = 0, n2 = 0, \
        n_edge = 0, n_corner = 0, n_edge_destructive = 0, n_corner_destructive = 0
    cdef pair[int, int] neighbour, neighbour2, alive_semi_1, destructive_semi_1
    
    file = open("log.log", "a")
    file.write(str(birth) + " " + str(survival) + "\n")
    file.close()

    if rule_space == b"BSFKL":
        if bsconditions == b"Outer Totalistic":
            for i in range(neighbours.size() - 1):
                if neighbours[i] == 1:
                    n_living += neighbourhood_weights[generations % alternating_period][i]
                elif neighbours[i] == 2:
                    n_destructive += neighbourhood_weights[generations % alternating_period][i]

            if neighbours[neighbours.size() - 1] == 1:
                if killing[generations % alternating_period].find(n_destructive) != \
                        killing[generations % alternating_period].end():
                    return 0
                elif survival[generations % alternating_period].find(n_living) != \
                        survival[generations % alternating_period].end():
                    return 1
                return 2

            elif neighbours[neighbours.size() - 1] == 2:
                if living[generations % alternating_period].find(n_living) != \
                        living[generations % alternating_period].end():
                    return 0
                return 2

            else:
                if forcing[generations % alternating_period].find(n_destructive) != \
                        forcing[generations % alternating_period].end() and \
                        birth[generations % alternating_period].find(n_living) != \
                        birth[generations % alternating_period].end():
                    return 1
                return 0
        elif bsconditions == b"Double Totalistic":
            n_birth = 0
            n_survival = 0
            n_living = 0
            n_forcing = 0
            n_killing = 0
            for neighbour in original_neighbourhood[generations % alternating_period]:
                n1, n2 = 0, 0
                idx = 0
                for neighbour2 in original_neighbourhood[generations % alternating_period]:
                    if neighbours[index_map[generations % alternating_period][pair[int, int]
                         (neighbour.first + neighbour2.first, neighbour.second + neighbour2.second)]] == 1:
                        n1 += neighbourhood_weights[generations % alternating_period][idx]
                    if neighbours[index_map[generations % alternating_period][pair[int, int]
                         (neighbour.first + neighbour2.first, neighbour.second + neighbour2.second)]] == 2:
                        n2 += neighbourhood_weights[generations % alternating_period][idx]
                    idx += 1

                if other_birth[generations % alternating_period].find(n1) != \
                        other_birth[generations % alternating_period].end():
                    n_birth += 1
                if other_survival[generations % alternating_period].find(n1) != \
                        other_survival[generations % alternating_period].end():
                    n_survival += 1
                if other_living[generations % alternating_period].find(n1) != \
                        other_living[generations % alternating_period].end():
                    n_living += 1
                if other_forcing[generations % alternating_period].find(n2) != \
                        other_forcing[generations % alternating_period].end():
                    n_forcing += 1
                if other_killing[generations % alternating_period].find(n2) != \
                        other_killing[generations % alternating_period].end():
                    n_killing += 1

            if neighbours[neighbours.size() - 1] == 1:
                if killing[generations % alternating_period].find(n_killing) != \
                        killing[generations % alternating_period].end():
                    return 0
                elif survival[generations % alternating_period].find(n_survival) != \
                        survival[generations % alternating_period].end():
                    return 1
                return 2

            elif neighbours[neighbours.size() - 1] == 2:
                if living[generations % alternating_period].find(n_living) != \
                        living[generations % alternating_period].end():
                    return 0
                return 2

            else:
                if forcing[generations % alternating_period].find(n_forcing) != \
                        forcing[generations % alternating_period].end() and \
                        birth[generations % alternating_period].find(n_birth) != \
                        birth[generations % alternating_period].end():
                    return 1
                return 0
        elif bsconditions == b"Range 1 Moore Semi Totalistic":
            for i in range(len(neighbours) - 1):
                if neighbourhood[generations % alternating_period][i] == pair[int, int] (0, -1) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (0, 1) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (1, 0) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (-1, 0):
                    if neighbours[i] == 1:
                        n_edge += 1
                    elif neighbours[i] == 2:
                        n_edge_destructive += 1
                else:
                    if neighbours[i] == 1:
                        n_corner += 1
                    elif neighbours[i] == 2:
                        n_corner_destructive += 1

            alive_semi_1 = pair[int, int] (n_corner, n_edge)
            destructive_semi_1 = pair[int, int] (n_corner_destructive, n_edge_destructive)
            if neighbours[neighbours.size() - 1] == 1:
                if killing_semi_1[generations % alternating_period].find(destructive_semi_1) != \
                        killing_semi_1[generations % alternating_period].end():
                    return 0
                elif survival_semi_1[generations % alternating_period].find(alive_semi_1) != \
                        survival_semi_1[generations % alternating_period].end():
                    return 1
                return 2

            elif neighbours[neighbours.size() - 1] == 2:
                if living_semi_1[generations % alternating_period].find(alive_semi_1) != \
                        living_semi_1[generations % alternating_period].end():
                    return 0
                return 2

            else:
                if forcing_semi_1[generations % alternating_period].find(destructive_semi_1) != \
                        forcing_semi_1[generations % alternating_period].end() and \
                        birth_semi_1[generations % alternating_period].find(alive_semi_1) != \
                        birth_semi_1[generations % alternating_period].end():
                    return 1
                return 0
    elif rule_space == b"Extended Generations":
        if bsconditions == b"Outer Totalistic":
            for i in range(neighbours.size() - 1):
                n += neighbourhood_weights[generations % alternating_period][i] * \
                     state_weights[generations % alternating_period][neighbours[i]]

            if activity_list[generations % alternating_period].find(neighbours[neighbours.size() - 1]) != \
                    activity_list[generations % alternating_period].end():
                if survival[generations % alternating_period].find(n) != \
                        survival[generations % alternating_period].end():
                    return neighbours[neighbours.size() - 1]
                return (neighbours[neighbours.size() - 1] + 1) % n_states

            elif neighbours[neighbours.size() - 1] == 0:
                if birth[generations % alternating_period].find(n) != \
                        birth[generations % alternating_period].end():
                    return 1
                return 0
        elif bsconditions == b"Double Totalistic":
            n_birth = 0
            n_survival = 0
            for neighbour in original_neighbourhood[generations % alternating_period]:
                n = 0
                idx = 0
                for neighbour2 in original_neighbourhood[generations % alternating_period]:
                    n += neighbourhood_weights[generations % alternating_period][idx] * \
                         state_weights[generations % alternating_period][neighbours[index_map[
                             generations % alternating_period][pair[int, int]
                         (neighbour.first + neighbour2.first, neighbour.second + neighbour2.second)]]]
                    idx += 1

                if other_birth[generations % alternating_period].find(n) != \
                        other_birth[generations % alternating_period].end():
                    n_birth += 1
                if other_survival[generations % alternating_period].find(n) != \
                        other_survival[generations % alternating_period].end():
                    n_survival += 1

            if activity_list[generations % alternating_period].find(neighbours[neighbours.size() - 1]) != \
                    activity_list[generations % alternating_period].end():
                if survival[generations % alternating_period].find(n_survival) != \
                    survival[generations % alternating_period].end():
                    return 1
                return 2

            elif neighbours[neighbours.size() - 1] == 0:
                if birth[generations % alternating_period].find(n_birth) != \
                    birth[generations % alternating_period].end():
                    return 1
                return 0
        elif bsconditions == b"Range 1 Moore Semi Totalistic":
            n_edge, n_corner = 0, 0
            for i in range(len(neighbours) - 1):
                if neighbourhood[generations % alternating_period][i] == pair[int, int] (0, -1) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (0, 1) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (1, 0) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (-1, 0):
                    n_edge += state_weights[generations % alternating_period][neighbours[i]]
                else:
                    n_corner += state_weights[generations % alternating_period][neighbours[i]]

            if neighbours[neighbours.size() - 1] == 0:
                if birth_semi_1[generations % alternating_period].find(pair[int, int] (n_corner, n_edge)) != \
                    birth_semi_1[generations % alternating_period].end():
                    return 1
                return 0
            elif neighbours[neighbours.size() - 1] == 1:
                if survival_semi_1[generations % alternating_period].find(pair[int, int] (n_corner, n_edge)) != \
                    survival_semi_1[generations % alternating_period].end():
                    return 1
                return 2
    elif rule_space == b"Single State":
        if bsconditions == b"Outer Totalistic":
            for i in range(neighbours.size() - 1):
                n += neighbourhood_weights[generations % alternating_period][i] * \
                     state_weights[generations % alternating_period][neighbours[i]]

            if neighbours[neighbours.size() - 1] == 1:
                if survival[generations % alternating_period].find(n) != \
                        survival[generations % alternating_period].end():
                    return 1
                return 0
            else:
                if birth[generations % alternating_period].find(n) != \
                        birth[generations % alternating_period].end():
                    return 1
                return 0
        elif bsconditions == b"Double Totalistic":
            n_birth = 0
            n_survival = 0
            for neighbour in original_neighbourhood[generations % alternating_period]:
                n = 0
                idx = 0
                for neighbour2 in original_neighbourhood[generations % alternating_period]:
                    n += neighbourhood_weights[generations % alternating_period][idx] * \
                         state_weights[generations % alternating_period][neighbours[index_map[
                             generations % alternating_period][pair[int, int]
                         (neighbour.first + neighbour2.first, neighbour.second + neighbour2.second)]]]
                    idx += 1

                if other_birth[generations % alternating_period].find(n) != \
                        other_birth[generations % alternating_period].end():
                    n_birth += 1
                if other_survival[generations % alternating_period].find(n) != \
                        other_survival[generations % alternating_period].end():
                    n_survival += 1

            if neighbours[neighbours.size() - 1] == 1:
                if survival[generations % alternating_period].find(n_survival) != \
                    survival[generations % alternating_period].end():
                    return 1
                return 0

            elif neighbours[neighbours.size() - 1] == 0:
                if birth[generations % alternating_period].find(n_birth) != \
                    birth[generations % alternating_period].end():
                    return 1
                return 0
        elif bsconditions == b"Range 1 Moore Semi Totalistic":
            n_edge, n_corner = 0, 0
            for i in range(len(neighbours) - 1):
                if neighbourhood[generations % alternating_period][i] == pair[int, int] (0, -1) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (0, 1) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (1, 0) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (-1, 0):
                    n_edge += neighbours[i]
                else: 
                    n_corner += neighbours[i]

            if neighbours[neighbours.size() - 1] == 0:
                if birth_semi_1[generations % alternating_period].find(pair[int, int] (n_corner, n_edge)) != \
                    birth_semi_1[generations % alternating_period].end():
                    return 1
                return 0
            elif neighbours[neighbours.size() - 1] == 1:
                if survival_semi_1[generations % alternating_period].find(pair[int, int] (n_corner, n_edge)) != \
                    survival_semi_1[generations % alternating_period].end():
                    return 1
                return 0
    elif rule_space == b"Regenerating Generations":
        if bsconditions == b"Outer Totalistic":
            for i in range(neighbours.size() - 1):
                n += neighbourhood_weights[generations % alternating_period][i] * \
                     state_weights[generations % alternating_period][neighbours[i]]

            if neighbours[neighbours.size() - 1] == 0:
                if birth[generations % alternating_period].find(n) != \
                        birth[generations % alternating_period].end():
                    return birth_state
                return 0
            elif neighbours[neighbours.size() - 1] == 1:
                if survival[generations % alternating_period].find(n) != \
                        survival[generations % alternating_period].end():
                    return 1
                return 2
            else:
                if regen_birth[generations % alternating_period].find(n) != \
                        regen_birth[generations % alternating_period].end():
                    return neighbours[neighbours.size() - 1] - 1
                elif regen_survival[generations % alternating_period].find(n) != \
                        regen_survival[generations % alternating_period].end():
                    return neighbours[neighbours.size() - 1]
                return (neighbours[neighbours.size() - 1] + 1) % n_states
        elif bsconditions == b"Double Totalistic":
            n_birth, n_survival, n_regen_birth, n_regen_survival = 0, 0, 0, 0
            for neighbour in original_neighbourhood[generations % alternating_period]:
                n = 0
                idx = 0
                for neighbour2 in original_neighbourhood[generations % alternating_period]:
                    n += neighbourhood_weights[generations % alternating_period][idx] * \
                         state_weights[generations % alternating_period][neighbours[index_map[
                             generations % alternating_period][pair[int, int]
                         (neighbour.first + neighbour2.first, neighbour.second + neighbour2.second)]]]
                    idx += 1
                if other_birth[generations % alternating_period].find(n) != \
                        other_birth[generations % alternating_period].end():
                    n_birth += 1
                if other_survival[generations % alternating_period].find(n) != \
                        other_survival[generations % alternating_period].end():
                    n_survival += 1
                if other_regen_birth[generations % alternating_period].find(n) != \
                        other_regen_birth[generations % alternating_period].end():
                    n_regen_birth += 1
                if other_regen_survival[generations % alternating_period].find(n) != \
                        other_regen_survival[generations % alternating_period].end():
                    n_regen_survival += 1

            if neighbours[neighbours.size() - 1] == 0:
                if birth[generations % alternating_period].find(n_birth) != \
                        birth[generations % alternating_period].end():
                    return birth_state
                return 0
            elif neighbours[neighbours.size() - 1] == 1:
                if survival[generations % alternating_period].find(n_survival) != \
                        survival[generations % alternating_period].end():
                    return 1
                return 2
            else:
                if regen_birth[generations % alternating_period].find(n_regen_birth) != \
                        regen_birth[generations % alternating_period].end():
                    return neighbours[neighbours.size() - 1] - 1
                elif regen_survival[generations % alternating_period].find(n_regen_survival) != \
                        regen_survival[generations % alternating_period].end():
                    return neighbours[neighbours.size() - 1]
                return (neighbours[neighbours.size() - 1] + 1) % n_states
        elif bsconditions == b"Range 1 Moore Semi Totalistic":
            n_edge, n_corner = 0, 0
            for i in range(len(neighbours) - 1):
                if neighbourhood[generations % alternating_period][i] == pair[int, int] (0, -1) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (0, 1) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (1, 0) or \
                        neighbourhood[generations % alternating_period][i] == pair[int, int] (-1, 0):
                    n_edge += state_weights[generations % alternating_period][neighbours[i]]
                else:
                    n_corner += state_weights[generations % alternating_period][neighbours[i]]

            if neighbours[neighbours.size() - 1] == 0:
                if birth_semi_1[generations % alternating_period].find(pair[int, int] (n_edge, n_corner)) != \
                        birth_semi_1[generations % alternating_period].end():
                    return birth_state
                return 0
            elif neighbours[neighbours.size() - 1] == 1:
                if survival_semi_1[generations % alternating_period].find(pair[int, int] (n_edge, n_corner)) != \
                        survival_semi_1[generations % alternating_period].end():
                    return 1
                return 2
            else:
                if regen_birth_semi_1[generations % alternating_period].find(pair[int, int] (n_edge, n_corner)) != \
                        regen_birth_semi_1[generations % alternating_period].end():
                    return neighbours[neighbours.size() - 1] - 1
                elif regen_survival_semi_1[generations % alternating_period].find(
                        pair[int, int] (n_edge, n_corner)) != \
                        regen_survival_semi_1[generations % alternating_period].end():
                    return neighbours[neighbours.size() - 1]
                return (neighbours[neighbours.size() - 1] + 1) % n_states

cdef int depend_on_neighbours(int state, int generations):
    if rule_space == b"BSFKL" or rule_space == b"Single State" or rule_space == b"Regenerating Generations":
        return -1
    elif rule_space == b"Extended Generations":
        if activity_list[generations % alternating_period].find(state) != \
                activity_list[generations % alternating_period].end() or state == 0:
            return -1
        else:
            return (state + 1) % n_states

cdef unordered_map[pair[int, int], int] depends_cache
cdef map[pair[vector[int], int], int] transition_func_cache

cdef bool compare_pairs(pair[int, int] a, pair[int, int] b):
    if direction == b"o":
        if corner == 0:
            if xy == 0:
                if a.second == b.second:
                    return a.first < b.first
                return a.second < b.second
            elif xy == 1:
                if a.first == b.first:
                    return a.second < b.second
                return a.first < b.first

        elif corner == 1:
            if xy == 0:
                if a.second == b.second:
                    return a.first < b.first
                return a.second > b.second
            elif xy == 1:
                if a.first == b.first:
                    return a.second > b.second
                return a.first < b.first

        elif corner == 2:
            if xy == 0:
                if a.second == b.second:
                    return a.first > b.first
                return a.second < b.second
            elif xy == 1:
                if a.first == b.first:
                    return a.second < b.second
                return a.first > b.first

        elif corner == 3:
            if xy == 0:
                if a.second == b.second:
                    return a.first > b.first
                return a.second > b.second
            elif xy == 1:
                if a.first == b.first:
                    return a.second > b.second
                return a.first > b.first
    elif direction == b"d":
        if corner == 0:
            if xy == 0:
                if a.first + a.second == b.first + b.second:
                    return a.first < b.first
                return a.first + a.second < b.first + b.second
            elif xy == 1:
                if a.first + a.second == b.first + b.second:
                    return a.first > b.first
                return a.first + a.second < b.first + b.second

        elif corner == 1:
            if xy == 0:
                if a.first - a.second == b.first - b.second:
                    return a.first < b.first
                return a.first - a.second < b.first - b.second
            elif xy == 1:
                if a.first - a.second == b.first - b.second:
                    return a.first > b.first
                return a.first - a.second < b.first - b.second

        elif corner == 2:
            if xy == 0:
                if a.first - a.second == b.first - b.second:
                    return a.first < b.first
                return a.first - a.second > b.first - b.second
            elif xy == 1:
                if a.first - a.second == b.first - b.second:
                    return a.first > b.first
                return a.first - a.second > b.first - b.second

        elif corner == 3:
            if xy == 0:
                if a.first + a.second == b.first + b.second:
                    return a.first < b.first
                return a.first + a.second > b.first + b.second
            elif xy == 1:
                if a.first + a.second == b.first + b.second:
                    return a.first > b.first
                return a.first + a.second > b.first + b.second

cpdef compute(unordered_set[pair[int, int]] cells_changed,
              unordered_map[pair[int, int], int] copy_grid, unordered_map[pair[int, int], int] dict_grid,
              int generations):

    global corner, direction, xy

    cdef vector[int] neighbours
    neighbours.reserve(neighbourhood[generations % alternating_period].size() + 1)

    cdef unordered_set[pair[int, int]] cells_to_check

    cdef int i, j
    cdef int ans
    cdef vector[pair[int, int]] cells_to_check_vector
    cdef pair[int, int] coordinates, coordinates2
    cdef pair[int, int] neighbour

    for coor in cells_changed:
        for neighbour in neighbourhood[generations % alternating_period]:
            coordinates.first = coor.first + neighbour.first
            coordinates.second = coor.second + neighbour.second
            cells_to_check.insert(coordinates)

        cells_to_check.insert(coor)

    if alternating_period > 1:
        if generations % (alternating_period - 1) == 0:
            cells_changed.clear()
    else:
        cells_changed.clear()

    corner = corner_lst[generations % alternating_period]
    direction = direction_lst[generations % alternating_period]
    xy = xy_lst[generations % alternating_period]

    if corner == -1:
        for coordinates in cells_to_check:
            neighbours.clear()
            ans = -1

            if copy_grid.find(coordinates) == copy_grid.end():
                if depends_cache.find(pair[int, int] (0, generations % alternating_period)) == \
                        depends_cache.end():
                    ans = depend_on_neighbours(0, generations % alternating_period)
                    depends_cache[pair[int, int] (0, generations % alternating_period)] = ans
                else:
                    ans = depends_cache[pair[int, int] (0, generations % alternating_period)]
            else:
                if depends_cache.find(pair[int, int] (copy_grid[coordinates],
                                                      generations % alternating_period)) == \
                        depends_cache.end():
                    ans = depend_on_neighbours(copy_grid[coordinates], generations % alternating_period)
                    depends_cache[pair[int, int] (copy_grid[coordinates], generations % alternating_period)] = ans
                else:
                    ans = depends_cache[pair[int, int] (copy_grid[coordinates], generations % alternating_period)]

            if ans == -1:
                for neighbour in neighbourhood[generations % alternating_period]:
                    coordinates2 = pair[int, int] (coordinates.first + neighbour.first,
                                                   coordinates.second + neighbour.second)
                    if copy_grid.find(coordinates2) != copy_grid.end():
                        neighbours.push_back(copy_grid[coordinates2])
                    else:
                        neighbours.push_back(0)

            if copy_grid.find(coordinates) != copy_grid.end():
                neighbours.push_back(copy_grid[coordinates])
                if transition_func_cache.find(
                        pair[vector[int], int] (neighbours, generations % alternating_period)) == \
                        transition_func_cache.end():
                    if ans == -1:
                        ans = transition_func(neighbours, generations % alternating_period)
                        transition_func_cache[
                            pair[vector[int], int] (neighbours, generations % alternating_period)] = ans
                else:
                    if ans == -1: ans = transition_func_cache[
                        pair[vector[int], int] (neighbours, generations % alternating_period)]

                if ans == 0:
                    dict_grid.erase(coordinates)
                    cells_changed.insert(coordinates)
                elif ans != copy_grid[coordinates]:
                    dict_grid[coordinates] = ans
                    cells_changed.insert(coordinates)
            else:
                neighbours.push_back(0)
                if transition_func_cache.find(
                        pair[vector[int], int] (neighbours, generations % alternating_period)) == \
                        transition_func_cache.end():
                    if ans == -1:
                        ans = transition_func(neighbours, generations % alternating_period)
                        transition_func_cache[
                            pair[vector[int], int] (neighbours, generations % alternating_period)] = ans
                else:
                    if ans == -1: ans = transition_func_cache[
                        pair[vector[int], int] (neighbours, generations % alternating_period)]

                if ans != 0:
                    dict_grid.insert(pair[pair[int, int], int] (coordinates, ans))
                    cells_changed.insert(coordinates)
    else:
        cells_to_check_vector.assign(cells_to_check.begin(), cells_to_check.end())
        sort(cells_to_check_vector.begin(), cells_to_check_vector.end(), compare_pairs)
        for coordinates in cells_to_check_vector:
            neighbours.clear()
            ans = -1

            if dict_grid.find(coordinates) == dict_grid.end():
                if depends_cache.find(pair[int, int] (0, generations % alternating_period)) == \
                        depends_cache.end():
                    ans = depend_on_neighbours(0, generations % alternating_period)
                    depends_cache[pair[int, int] (0, generations % alternating_period)] = ans
                else:
                    ans = depends_cache[pair[int, int] (0, generations % alternating_period)]
            else:
                if depends_cache.find(pair[int, int] (dict_grid[coordinates],
                                                      generations % alternating_period)) == \
                        depends_cache.end():
                    ans = depend_on_neighbours(dict_grid[coordinates], generations % alternating_period)
                    depends_cache[pair[int, int] (dict_grid[coordinates], generations % alternating_period)] = ans
                else:
                    ans = depends_cache[pair[int, int] (dict_grid[coordinates], generations % alternating_period)]

            if ans == -1:
                for neighbour in neighbourhood[generations % alternating_period]:
                    coordinates2 = pair[int, int] (coordinates.first + neighbour.first,
                                                   coordinates.second + neighbour.second)
                    if dict_grid.find(coordinates2) != dict_grid.end():
                        neighbours.push_back(dict_grid[coordinates2])
                    else:
                        neighbours.push_back(0)

            if dict_grid.find(coordinates) != dict_grid.end():
                neighbours.push_back(dict_grid[coordinates])
                if transition_func_cache.find(
                        pair[vector[int], int] (neighbours, generations % alternating_period)) == \
                        transition_func_cache.end():
                    if ans == -1:
                        ans = transition_func(neighbours, generations % alternating_period)
                        transition_func_cache[
                            pair[vector[int], int] (neighbours, generations % alternating_period)] = ans
                else:
                    if ans == -1: ans = transition_func_cache[
                        pair[vector[int], int] (neighbours, generations % alternating_period)]

                if ans == 0:
                    dict_grid.erase(coordinates)
                    cells_changed.insert(coordinates)
                elif ans != dict_grid[coordinates]:
                    dict_grid[coordinates] = ans
                    cells_changed.insert(coordinates)
            else:
                neighbours.push_back(0)
                if transition_func_cache.find(
                        pair[vector[int], int] (neighbours, generations % alternating_period)) == \
                        transition_func_cache.end():
                    if ans == -1:
                        ans = transition_func(neighbours, generations % alternating_period)
                        transition_func_cache[
                            pair[vector[int], int] (neighbours, generations % alternating_period)] = ans
                else:
                    if ans == -1: ans = transition_func_cache[
                        pair[vector[int], int] (neighbours, generations % alternating_period)]

                if ans != 0:
                    dict_grid.insert(pair[pair[int, int], int] (coordinates, ans))
                    cells_changed.insert(coordinates)

    return cells_changed, dict_grid
NVM, I know the problem YAY!
Download CAViewer: https://github.com/jedlimlx/Cellular-Automaton-Viewer

Supports:
BSFKL, Extended Generations, Regenerating Generations, Naive Rules, R1 Moore, R2 Cross and R2 Von Neumann INT
And some others...

Post Reply