Compare commits
No commits in common. "slime-grid" and "main" have entirely different histories.
slime-grid
...
main
@ -1,26 +0,0 @@
|
|||||||
from slime.grid import Grid
|
|
||||||
from slime.rules import SimpleMapping, Movement, Combine
|
|
||||||
|
|
||||||
grid = Grid(10, 10, wrap_y=True)
|
|
||||||
grid[0, 0, "state"] = 1
|
|
||||||
grid[1, 1, "state"] = 1
|
|
||||||
grid[2, 0, "state"] = 1
|
|
||||||
grid[3, 1, "state"] = 1
|
|
||||||
grid[4, 0, "state"] = 1
|
|
||||||
grid[5, 1, "state"] = 1
|
|
||||||
grid[6, 0, "state"] = 1
|
|
||||||
grid[7, 1, "state"] = 1
|
|
||||||
grid[8, 0, "state"] = 1
|
|
||||||
grid[9, 1, "state"] = 1
|
|
||||||
|
|
||||||
# grid.rules.append(SimpleMapping("state", {0: 1, 1: 0}))
|
|
||||||
# grid.rules.append(Movement("state", 0, 1))
|
|
||||||
grid.rules.append(
|
|
||||||
Combine(SimpleMapping("state", {0: 1, 1: 0}), Movement("state", 0, 1))
|
|
||||||
)
|
|
||||||
|
|
||||||
while True:
|
|
||||||
# grid.render_text("state")
|
|
||||||
grid.render_text(lambda cell: {0: "|", 1: "-"}[cell["state"]])
|
|
||||||
input()
|
|
||||||
grid.step()
|
|
@ -1,118 +0,0 @@
|
|||||||
from enum import Enum
|
|
||||||
from collections import defaultdict
|
|
||||||
from .rules import Rule
|
|
||||||
|
|
||||||
|
|
||||||
class Connected(Enum):
|
|
||||||
FOUR_WAYS = 4
|
|
||||||
EIGHT_WAYS = 8
|
|
||||||
|
|
||||||
|
|
||||||
class Grid:
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
*,
|
|
||||||
connected=Connected.FOUR_WAYS,
|
|
||||||
wrap_x=False,
|
|
||||||
wrap_y=False,
|
|
||||||
default_value=dict,
|
|
||||||
):
|
|
||||||
self.width = width
|
|
||||||
self.height = height
|
|
||||||
self.connected = connected
|
|
||||||
self.wrap_x = wrap_x
|
|
||||||
self.wrap_y = wrap_y
|
|
||||||
self.grid = defaultdict(default_value)
|
|
||||||
self.rules = []
|
|
||||||
|
|
||||||
def neighbors(self, x, y):
|
|
||||||
x1 = x - 1
|
|
||||||
x2 = x + 1
|
|
||||||
y1 = y - 1
|
|
||||||
y2 = y + 1
|
|
||||||
if x1 < 0:
|
|
||||||
x1 = self.width - 1 if self.wrap_x else None
|
|
||||||
if x2 >= self.width:
|
|
||||||
x2 = 0 if self.wrap_x else None
|
|
||||||
if y1 < 0:
|
|
||||||
y1 = self.height - 1 if self.wrap_y else None
|
|
||||||
if y2 >= self.height:
|
|
||||||
y2 = 0 if self.wrap_y else None
|
|
||||||
|
|
||||||
if x1 is not None:
|
|
||||||
yield (x1, y)
|
|
||||||
if x2 is not None:
|
|
||||||
yield (x2, y)
|
|
||||||
if y1 is not None:
|
|
||||||
yield (x, y1)
|
|
||||||
if y2 is not None:
|
|
||||||
yield (x, y2)
|
|
||||||
if self.connected == Connected.EIGHT_WAYS:
|
|
||||||
if x1 is not None and y1 is not None:
|
|
||||||
yield (x1, y1)
|
|
||||||
if x1 is not None and y2 is not None:
|
|
||||||
yield (x1, y2)
|
|
||||||
if x2 is not None and y1 is not None:
|
|
||||||
yield (x2, y1)
|
|
||||||
if x2 is not None and y2 is not None:
|
|
||||||
yield (x2, y2)
|
|
||||||
|
|
||||||
def __getitem__(self, item):
|
|
||||||
x, y, prop = item
|
|
||||||
if self.wrap_x:
|
|
||||||
x %= self.width
|
|
||||||
if self.wrap_y:
|
|
||||||
y %= self.height
|
|
||||||
if x < 0 or x >= self.width or y < 0 or y >= self.height:
|
|
||||||
raise IndexError
|
|
||||||
return self.grid[item][prop]
|
|
||||||
|
|
||||||
def __setitem__(self, item, value):
|
|
||||||
x, y, prop = item
|
|
||||||
if self.wrap_x:
|
|
||||||
x %= self.width
|
|
||||||
if self.wrap_y:
|
|
||||||
y %= self.height
|
|
||||||
if x < 0 or x >= self.width or y < 0 or y >= self.height:
|
|
||||||
raise IndexError
|
|
||||||
self.grid[x, y][prop] = value
|
|
||||||
|
|
||||||
def __iter__(self):
|
|
||||||
return iter(self.grid.items())
|
|
||||||
|
|
||||||
def render_text(self, prop_or_func):
|
|
||||||
if callable(prop_or_func):
|
|
||||||
func = prop_or_func
|
|
||||||
else:
|
|
||||||
func = lambda x: x[prop_or_func]
|
|
||||||
for y in range(self.height):
|
|
||||||
for x in range(self.width):
|
|
||||||
if (x, y) in self.grid:
|
|
||||||
print(func(self.grid[(x, y)]), end="")
|
|
||||||
else:
|
|
||||||
print(" ", end="")
|
|
||||||
print()
|
|
||||||
|
|
||||||
def add_rule(self, rule):
|
|
||||||
self.rules.append(rule)
|
|
||||||
|
|
||||||
def step(self):
|
|
||||||
new_grid = defaultdict(dict)
|
|
||||||
for (x, y), cell in self.grid.items():
|
|
||||||
for rule in self.rules:
|
|
||||||
for update in rule.step(x, y, cell, self):
|
|
||||||
# TODO: two rules shouldn't be able to update the same cell
|
|
||||||
if update.x < 0 or update.x >= self.width:
|
|
||||||
if not self.wrap_x:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
update.x %= self.width
|
|
||||||
if update.y < 0 or update.y >= self.height:
|
|
||||||
if not self.wrap_y:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
update.y %= self.height
|
|
||||||
new_grid[update.x, update.y].update(update.data)
|
|
||||||
self.grid = new_grid
|
|
@ -1,51 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from typing import Generator
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CellUpdate:
|
|
||||||
x: int
|
|
||||||
y: int
|
|
||||||
data: dict
|
|
||||||
|
|
||||||
|
|
||||||
class Rule(ABC):
|
|
||||||
@abstractmethod
|
|
||||||
def step(
|
|
||||||
self, x: int, y: int, cell: dict, grid: "Grid"
|
|
||||||
) -> Generator[CellUpdate, None, None]:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleMapping(Rule):
|
|
||||||
def __init__(self, prop, mapping):
|
|
||||||
self.mapping = mapping
|
|
||||||
self.prop = prop
|
|
||||||
|
|
||||||
def step(self, x, y, cell, grid):
|
|
||||||
yield CellUpdate(x, y, {self.prop: self.mapping.get(cell.get(self.prop))})
|
|
||||||
|
|
||||||
|
|
||||||
class Movement(Rule):
|
|
||||||
def __init__(self, prop, dx, dy):
|
|
||||||
self.prop = prop
|
|
||||||
self.dx = dx
|
|
||||||
self.dy = dy
|
|
||||||
|
|
||||||
def step(self, x, y, cell, grid):
|
|
||||||
yield CellUpdate(x + self.dx, y + self.dy, cell)
|
|
||||||
|
|
||||||
|
|
||||||
class Combine(Rule):
|
|
||||||
def __init__(self, *rules):
|
|
||||||
self.rules = rules
|
|
||||||
|
|
||||||
def step(self, x, y, cell, grid):
|
|
||||||
updates = list(self.rules[0].step(x, y, cell, grid))
|
|
||||||
for rule in self.rules[1:]:
|
|
||||||
next_updates = []
|
|
||||||
for upd in updates:
|
|
||||||
next_updates.extend(rule.step(upd.x, upd.y, upd.data, grid))
|
|
||||||
updates = next_updates
|
|
||||||
yield from updates
|
|
Loading…
Reference in New Issue
Block a user