NNlk05's Big-Bag-'o'-Scripts™
This thread is for all of my scripts, its modifications thereof, my ideas about scripts, and any discussion about any above.
Instead of creating tons of threads regarding all of my scripts, I decided to create one Big-Bag-'o'-Scripts™ to keep the Forums tidy.
Links to scripts
NNlk05's Big-Bag-'o'-Scripts™
- NNlk05
- Posts: 668
- Joined: January 14th, 2026, 8:42 pm
- Location: Exploring in the Jungle of the INT Rulespace
- Contact:
NNlk05's Big-Bag-'o'-Scripts™
Last edited by NNlk05 on July 17th, 2026, 8:26 am, edited 2 times in total.
Feci quod potui, faciant meliora potentes.
https://nnlk05.github.io
=3
Code: Select all
x = 10, y = 3, rule = B34twz/S23
b2o4b2o$obo4bobo$2bo4bo!
[[ AUTOSTART AUTOHIDEGUI TRACK 0 -47/270 ZOOM 4 GPS 45 STEP 3 THEME BOOK ]]
=3
- NNlk05
- Posts: 668
- Joined: January 14th, 2026, 8:42 pm
- Location: Exploring in the Jungle of the INT Rulespace
- Contact:
Re: NNlk05's Big-Bag-'o'-Scripts™
OR-Tools still lifes searcher
This was intended to to find max-density still lifes and later modded to find still lifes with a certain population.
Setup
Try these in order:
Code
Usage:
This was intended to to find max-density still lifes and later modded to find still lifes with a certain population.
Setup
Try these in order:
Code: Select all
python3 -m pip install ortools
python -m pip install ortools
pip3 install ortools
pip install ortools
Code: Select all
"""
OR-Tools still life searcher
By: NNlk05
Find still lifes in Conway's Game of Life
Versions:
1.0.0 (2026-7-17): Release
OR-Tools still life searcher - Find still lifes in Conway's Game of Life
Copyright (C) 2026 NNlk05
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import argparse
from ortools.sat.python import cp_model
from sys import exit, stderr
from platform import system
def get_python_exe() -> str:
current_system = system()
if current_system == "Linux":
return "python"
if current_system == 'Windows':
return 'py'
if current_system == 'Darwin':
return "python3"
return "python"
def print_error(message: str) -> None:
print(f"{message} Exiting.", file=stderr)
exit(1)
def parse_args() -> tuple[int, int, int | None, bool, bool]:
parser = argparse.ArgumentParser(
prog=get_python_exe() + " " + __file__,
description="""
OR-Tools still life searcher
By: NNlk05
Find still lifes in Conway's Game of Life
"""
)
parser.add_argument("x", type=int, help="Grid width")
parser.add_argument("y", type=int, help="Grid height")
parser.add_argument(
"cells",
nargs="?",
type=int,
default=None,
help="Optional: Target number of live cells (if not specified, maximizes population)"
)
parser.add_argument(
"-a", "--all",
action="store_true",
help="Print all solutions without prompting"
)
parser.add_argument(
"-y", "--yes",
action="store_true",
help="Print all solutions without prompting (alias for --all)"
)
parser.add_argument(
"-q", "--quiet",
action="store_true",
help="Skip the 'Population: x' message"
)
try:
args = parser.parse_args()
except SystemExit:
raise
if args.x <= 0 or args.y <= 0:
print_error("Grid dimensions must be positive integers!")
if args.cells is not None and args.cells <= 0:
print_error("Cell count must be a positive integer!")
all_solutions = args.all or args.yes
return args.x, args.y, args.cells, all_solutions, args.quiet
class Grid:
def __init__(self, x: int, y: int):
self.x: int = x
self.y: int = y
self.grid: list[list[int]] = [
[0 for _ in range(x)] for _ in range(y)
]
def __str__(self) -> str:
output: str = ""
for row in self.grid:
for cell in row:
if cell == 1:
output += "O"
elif cell == 0:
output += "."
else:
print_error("Invalid value in Grid!")
output += "\n"
return output
def pop(self) -> int:
pop: int = 0
for row in self.grid:
for cell in row:
if cell == 1:
pop += 1
elif cell == 0:
pass
else:
print_error("Invalid value in Grid!")
return pop
def is_still(self, x: int, y: int) -> bool:
if not (0 <= x < self.x and 0 <= y < self.y):
print_error(f"Coordinates ({x}, {y}) out of grid bounds!")
count: int = 0
for dx in (-1, 0, 1):
for dy in (-1, 0, 1):
if dx == 0 and dy == 0:
continue
nx: int = x + dx
ny: int = y + dy
if 0 <= nx < self.x and 0 <= ny < self.y:
if self.grid[ny][nx] == 1:
count += 1
current_state: int = self.grid[y][x]
if current_state == 1:
return count in (2, 3)
elif current_state == 0:
return count == 3
else:
print_error("Invalid value in Grid!")
return False
def main() -> None:
x, y, target_cells, all_solutions, quiet = parse_args()
padded_x: int = x + 2
padded_y: int = y + 2
model: cp_model.CpModel = cp_model.CpModel()
grid: Grid = Grid(x, y)
grid_vars: list[list[cp_model.IntVar]] = [
[model.NewIntVar(0, 1, f"cell_{i}_{j}") for j in range(padded_x)]
for i in range(padded_y)
]
for i in range(padded_y):
for j in range(padded_x):
if i == 0 or i == padded_y - 1 or j == 0 or j == padded_x - 1:
model.Add(grid_vars[i][j] == 0)
for i in range(padded_y):
for j in range(padded_x):
neighbors: list[cp_model.IntVar] = []
for di in (-1, 0, 1):
for dj in (-1, 0, 1):
if di == 0 and dj == 0:
continue
ni: int = i + di
nj: int = j + dj
if 0 <= ni < padded_y and 0 <= nj < padded_x:
neighbors.append(grid_vars[ni][nj])
neighbor_sum: cp_model.IntVar = model.NewIntVar(0, 8, f"neighbors_{i}_{j}")
model.Add(neighbor_sum == sum(neighbors))
cell: cp_model.IntVar = grid_vars[i][j]
model.Add(neighbor_sum >= 2).OnlyEnforceIf(cell)
model.Add(neighbor_sum <= 3).OnlyEnforceIf(cell)
model.Add(neighbor_sum != 3).OnlyEnforceIf(cell.Not())
interior_sum = sum(
grid_vars[i][j]
for i in range(1, padded_y - 1)
for j in range(1, padded_x - 1)
)
if target_cells is not None:
model.Add(interior_sum == target_cells)
else:
model.Maximize(interior_sum)
solver: cp_model.CpSolver = cp_model.CpSolver()
status: cp_model.CpSolverStatus = solver.Solve(model)
if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):
if target_cells is None:
optimal_pop = int(solver.ObjectiveValue())
model.Add(interior_sum == optimal_pop)
while True:
for i in range(y):
for j in range(x):
grid.grid[i][j] = int(solver.Value(grid_vars[i + 1][j + 1]))
print(grid)
if not quiet:
print(f"Population: {grid.pop()}")
if all_solutions:
forbid_clause = []
for i in range(1, padded_y - 1):
for j in range(1, padded_x - 1):
if solver.Value(grid_vars[i][j]) == 1:
forbid_clause.append(grid_vars[i][j].Not())
else:
forbid_clause.append(grid_vars[i][j])
model.AddBoolOr(forbid_clause)
status = solver.Solve(model)
if status not in (cp_model.OPTIMAL, cp_model.FEASIBLE):
print("\nNo more unique solutions found.")
break
else:
ans = input("Another solution (Y/n)? ").strip().lower()
if ans != 'n':
break
forbid_clause = []
for i in range(1, padded_y - 1):
for j in range(1, padded_x - 1):
if solver.Value(grid_vars[i][j]) == 1:
forbid_clause.append(grid_vars[i][j].Not())
else:
forbid_clause.append(grid_vars[i][j])
model.AddBoolOr(forbid_clause)
status = solver.Solve(model)
if status not in (cp_model.OPTIMAL, cp_model.FEASIBLE):
print("\nNo more unique solutions with the same population found.")
break
else:
print_error("No solution found!")
if __name__ == "__main__":
main()
Code: Select all
positional arguments:
x Grid width
y Grid height
cells Optional: Target number of live cells (if not specified, maximizes population)
options:
-h, --help show this help message and exit
-a, --all Print all solutions without prompting
-y, --yes Print all solutions without prompting (alias for --all)
-q, --quiet Skip the 'Population: x' messageFeci quod potui, faciant meliora potentes.
https://nnlk05.github.io
=3
Code: Select all
x = 10, y = 3, rule = B34twz/S23
b2o4b2o$obo4bobo$2bo4bo!
[[ AUTOSTART AUTOHIDEGUI TRACK 0 -47/270 ZOOM 4 GPS 45 STEP 3 THEME BOOK ]]
=3
- NNlk05
- Posts: 668
- Joined: January 14th, 2026, 8:42 pm
- Location: Exploring in the Jungle of the INT Rulespace
- Contact:
Re: NNlk05's Big-Bag-'o'-Scripts™
Here's 5 (out of many) 10x10 cases as a benchmark found by my program first with LifeWiki's version:
Code: Select all
x = 29, y = 58, rule = B3/S23
ob2ob2ob2o9bob2ob2ob2o$2ob2obob2o9b2ob2obob2o$6bo18bo$4ob2ob2o9b2ob3o
b3o$o2bobo2b2o10bobo2bo2bo$bobo2bo12bo2bo2bobo$2ob3ob3o9b3ob3ob2o$6bo
2bo12bo$2ob2obobo10b2obob2ob2o$2obob2ob2o9b2ob2ob2obo3$ob2ob2ob2o$2ob
2obob2o$6bo$4ob2ob2o$o2bobo2b2o$bobo2bo$2ob3ob3o$o5bo2bo$bob2obobo$2o
bob2ob2o3$o2bob2ob2o$5obobo$6bo2bo$4obob3o$o2bob2o$bobo4b2o$2ob4ob2o$
6bo$2ob2obob2o$2ob2ob2obo3$o2bob2ob2o$5obob2o$6bo$4ob2ob2o$o2bobo2b2o
$bobo2bo$2ob3ob3o$o5bo2bo$bob2obobo$2obob2ob2o3$ob2ob2ob2o$2ob2obob2o
$6bo$5obob2o$o3bobob2o$bobo2bo$2ob3ob3o$o5bo2bo$bob2obobo$2obob2ob2o!
Feci quod potui, faciant meliora potentes.
https://nnlk05.github.io
=3
Code: Select all
x = 10, y = 3, rule = B34twz/S23
b2o4b2o$obo4bobo$2bo4bo!
[[ AUTOSTART AUTOHIDEGUI TRACK 0 -47/270 ZOOM 4 GPS 45 STEP 3 THEME BOOK ]]
=3
- NNlk05
- Posts: 668
- Joined: January 14th, 2026, 8:42 pm
- Location: Exploring in the Jungle of the INT Rulespace
- Contact:
Re: NNlk05's Big-Bag-'o'-Scripts™
I just realized ikpx2 already uses MitM... just not the way I exepected it to.NNlk05 wrote: July 16th, 2026, 10:32 pm I realized there's a big space-time tradeoff in spaceship searching. One way to deal with that is using the Meet-in-the-Middle attack, in my other field of expertise, I've seen that MitM allows a 2^64 brute force that will normally take years to take less then a minute in WASM.
(Note: I'm not meaning this as a modification to the xfind family of programs. They already use way too much memory.)
Is there a way to apply MitM to spaceship searching?
Feci quod potui, faciant meliora potentes.
https://nnlk05.github.io
=3
Code: Select all
x = 10, y = 3, rule = B34twz/S23
b2o4b2o$obo4bobo$2bo4bo!
[[ AUTOSTART AUTOHIDEGUI TRACK 0 -47/270 ZOOM 4 GPS 45 STEP 3 THEME BOOK ]]
=3