From 7354b6cc2f08464a3c75418c717d49475f8ce37c Mon Sep 17 00:00:00 2001 From: Sarthak Joshi <100042684+Craniace@users.noreply.github.com> Date: Fri, 31 Oct 2025 23:13:51 +0530 Subject: [PATCH 1/4] Create elementary_cellular_automaton.py Elementary Cellular Automaton (Rule 30) implementation --- .../elementary_cellular_automaton.py | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 cellular_automata/elementary_cellular_automaton.py diff --git a/cellular_automata/elementary_cellular_automaton.py b/cellular_automata/elementary_cellular_automaton.py new file mode 100644 index 000000000000..9f244ae2594b --- /dev/null +++ b/cellular_automata/elementary_cellular_automaton.py @@ -0,0 +1,77 @@ +""" +Elementary Cellular Automaton - Rule 30 +--------------------------------------- + +A one-dimensional cellular automaton introduced by Stephen Wolfram. +Each cell's next state depends on its current state and its two immediate neighbors. + +Reference: +https://en.wikipedia.org/wiki/Rule_30 +""" + +from typing import List + + +def rule_30_step(current: List[int]) -> List[int]: + """ + Compute the next generation of a one-dimensional cellular automaton + following Wolfram's Rule 30. + + Each cell's next state is determined by its left, center, and right neighbors. + + Args: + current (List[int]): The current generation as a list of 0s (dead) and 1s (alive). + + Returns: + List[int]: The next generation as a list of 0s and 1s. + + Example: + >>> rule_30_step([0, 0, 1, 0, 0]) + [0, 1, 1, 1, 0] + """ + next_gen = [] + for i in range(len(current)): + left = current[i - 1] if i > 0 else 0 + center = current[i] + right = current[i + 1] if i < len(current) - 1 else 0 + + # Combine neighbors into a 3-bit pattern + pattern = (left << 2) | (center << 1) | right + + # Rule 30 binary: 00011110 -> 30 in decimal + next_gen.append((30 >> pattern) & 1) + + return next_gen + + +def generate_rule_30( + size: int = 31, generations: int = 15 +) -> List[List[int]]: + """ + Generate multiple generations of Rule 30 automaton. + + Args: + size (int): Number of cells in one generation. + generations (int): Number of generations to evolve. + + Returns: + List[List[int]]: A list of generations (each a list of 0s and 1s). + + Example: + >>> len(generate_rule_30(15, 5)) + 5 + """ + grid = [[0] * size for _ in range(generations)] + grid[0][size // 2] = 1 # Start with a single live cell in the middle + + for i in range(1, generations): + grid[i] = rule_30_step(grid[i - 1]) + + return grid + + +if __name__ == "__main__": + # Run an example simulation + generations = generate_rule_30(31, 15) + for row in generations: + print("".join("█" if cell else " " for cell in row)) From 9da123fbee684aa515171c4fed0b6fe29698bac7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 17:46:31 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- cellular_automata/elementary_cellular_automaton.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cellular_automata/elementary_cellular_automaton.py b/cellular_automata/elementary_cellular_automaton.py index 9f244ae2594b..b089adcf9059 100644 --- a/cellular_automata/elementary_cellular_automaton.py +++ b/cellular_automata/elementary_cellular_automaton.py @@ -44,9 +44,7 @@ def rule_30_step(current: List[int]) -> List[int]: return next_gen -def generate_rule_30( - size: int = 31, generations: int = 15 -) -> List[List[int]]: +def generate_rule_30(size: int = 31, generations: int = 15) -> List[List[int]]: """ Generate multiple generations of Rule 30 automaton. From 4dcecb9ac4646a99c9f489117d6050d9e61fff01 Mon Sep 17 00:00:00 2001 From: Sarthak Joshi <100042684+Craniace@users.noreply.github.com> Date: Fri, 31 Oct 2025 23:24:43 +0530 Subject: [PATCH 3/4] Update elementary_cellular_automaton.py --- .../elementary_cellular_automaton.py | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/cellular_automata/elementary_cellular_automaton.py b/cellular_automata/elementary_cellular_automaton.py index b089adcf9059..76e3e69c6699 100644 --- a/cellular_automata/elementary_cellular_automaton.py +++ b/cellular_automata/elementary_cellular_automaton.py @@ -6,13 +6,11 @@ Each cell's next state depends on its current state and its two immediate neighbors. Reference: -https://en.wikipedia.org/wiki/Rule_30 + https://en.wikipedia.org/wiki/Rule_30 """ -from typing import List - -def rule_30_step(current: List[int]) -> List[int]: +def rule_30_step(current: list[int]) -> list[int]: """ Compute the next generation of a one-dimensional cellular automaton following Wolfram's Rule 30. @@ -20,10 +18,10 @@ def rule_30_step(current: List[int]) -> List[int]: Each cell's next state is determined by its left, center, and right neighbors. Args: - current (List[int]): The current generation as a list of 0s (dead) and 1s (alive). + current (list[int]): The current generation as a list of 0s (dead) and 1s (alive). Returns: - List[int]: The next generation as a list of 0s and 1s. + list[int]: The next generation as a list of 0s and 1s. Example: >>> rule_30_step([0, 0, 1, 0, 0]) @@ -38,22 +36,22 @@ def rule_30_step(current: List[int]) -> List[int]: # Combine neighbors into a 3-bit pattern pattern = (left << 2) | (center << 1) | right - # Rule 30 binary: 00011110 -> 30 in decimal + # Rule 30 binary: 00011110 (bitwise representation of 30) next_gen.append((30 >> pattern) & 1) return next_gen -def generate_rule_30(size: int = 31, generations: int = 15) -> List[List[int]]: +def generate_rule_30(size: int = 31, generations: int = 15) -> list[list[int]]: """ Generate multiple generations of Rule 30 automaton. Args: - size (int): Number of cells in one generation. - generations (int): Number of generations to evolve. + size (int): Number of cells in one generation. Default is 31. + generations (int): Number of generations to evolve. Default is 15. Returns: - List[List[int]]: A list of generations (each a list of 0s and 1s). + list[list[int]]: A list of generations (each a list of 0s and 1s). Example: >>> len(generate_rule_30(15, 5)) From acf2d2c9f01a37f5409e7e7787e8a5f2914bc7c2 Mon Sep 17 00:00:00 2001 From: Sarthak Joshi <100042684+Craniace@users.noreply.github.com> Date: Fri, 31 Oct 2025 23:30:20 +0530 Subject: [PATCH 4/4] Update elementary_cellular_automaton.py --- cellular_automata/elementary_cellular_automaton.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cellular_automata/elementary_cellular_automaton.py b/cellular_automata/elementary_cellular_automaton.py index 76e3e69c6699..582ef1736438 100644 --- a/cellular_automata/elementary_cellular_automaton.py +++ b/cellular_automata/elementary_cellular_automaton.py @@ -18,7 +18,8 @@ def rule_30_step(current: list[int]) -> list[int]: Each cell's next state is determined by its left, center, and right neighbors. Args: - current (list[int]): The current generation as a list of 0s (dead) and 1s (alive). + current (list[int]): The current generation as a list of 0s (dead) + and 1s (alive). Returns: list[int]: The next generation as a list of 0s and 1s.