fix copying

This commit is contained in:
James Turk 2024-04-22 00:11:55 -05:00
parent 802ba51875
commit aa82295182
5 changed files with 55 additions and 36 deletions

View File

@ -36,7 +36,11 @@ class Doodle(ABC):
# All references to _pos_vec are internal to the class,
# so it will be trivial to swap this out later.
self._pos_vec = (0, 0)
if parent:
self._register()
def _register(self):
""" register with parent and world """
if self._parent:
# register with parent for updates
self._parent.add(self)
world.add(self)
@ -63,20 +67,20 @@ class Doodle(ABC):
Additionally, while a shallow copy is enough for most
cases, it will be possible for child classes to override
this to opt for a deepcopy or other logic.
this.
"""
new = copy.copy(self)
world.add(new)
new._register()
return new
def color(self, r: int, g: int, b: int) -> "Doodle":
def color(self, color: tuple[int, int, int]) -> "Doodle":
"""
Color works as a kind of setter function.
The only unique part is that it returns self, accomodating the
chained object pattern.
"""
self._color = (r, g, b)
self._color = color
return self
def pos(self, x: float, y: float) -> "Doodle":
@ -111,11 +115,11 @@ class Doodle(ABC):
"""
x = random.random() * world.WIDTH
y = random.random() * world.HEIGHT
r, g, b = Color.random()
color = Color.random()
# again here, we opt to use the setters so that
# future extensions to their behavior will be
# used by all downstream functions
return self.pos(x, y).color(r, g, b)
return self.pos(x, y).color(color)
@property
def x(self) -> float:
@ -265,10 +269,13 @@ class Group(Doodle):
in some languages would be much trickier to pull off.
"""
def __init__(self):
super().__init__()
def __init__(self, parent=None):
super().__init__(parent)
self._doodles = []
def __repr__(self):
return f"Group(pos={self.pos_vec}, doodles={len(self._doodles)})"
def draw(self, screen):
"""
Groups, despite being an abstract concept, are drawable.
@ -285,11 +292,16 @@ class Group(Doodle):
We are storing a list, so deep copies are necessary.
"""
new = copy.deepcopy(self)
world.add(new)
new = copy.copy(self)
new._register()
new._doodles = []
for child in self._doodles:
child = copy.copy(child)
child._parent = new
child._register()
return new
def color(self, r: int, g: int, b: int) -> "Doodle":
def color(self, color: tuple[int, int, int]) -> "Doodle":
"""
Another override.
@ -299,9 +311,9 @@ class Group(Doodle):
We don't cascade pos() calls, why not?
"""
super().color(r, g, b)
super().color(color)
for d in self._doodles:
d.color(r, g, b)
d.color(color)
return self
def add(self, doodle: "Doodle") -> "Group":
@ -338,7 +350,7 @@ class Circle(Doodle):
self._radius = 0
def __repr__(self):
return f"Circle(pos={self.pos_vec}, radius={self._radius}, {self._color})"
return f"Circle(pos={self.pos_vec}, radius={self._radius}, {self._color}, parent={self._parent}))"
def draw(self, screen):
pygame.draw.circle(screen, self._color, self.pos_vec, self._radius)
@ -359,4 +371,4 @@ class Circle(Doodle):
def random(self) -> "Doodle":
super().random()
# constrain to 10-100
return self.radius(random.random*90 + 10)
return self.radius(random.random()*90 + 10)

View File

@ -0,0 +1,16 @@
from doodles.doodles import Group, Line, Circle, Color
def original():
g = Group()
c = Circle(g).radius(80).color(Color.RED).pos(0, 0)
for _ in range(15):
c = c.copy().move(45, 45)
return g
r = original()
r.copy().move(200, 0).color(Color.GREEN)
r.copy().move(400, 0).color(Color.BLUE)
# from doodles.world import world
# for d in world._drawables:
# print(" >", d)

View File

@ -1,10 +1,13 @@
from doodles.doodles import Group, Line
from doodles.layouts import make_grid, copies
from doodles.layouts import make_grid
# Create a group of lines all with same origin, different angles.
g = Group()
for d in range(0, 180, 10):
Line(g).vec(d, 200 - d)
def same_spiral():
while True:
# Create a group of lines all with same origin, different angles.
g = Group()
for d in range(0, 180, 10):
Line(g).vec(d, 200 - d)
yield g
# Make copies, moving each one and modifying the color
make_grid(copies(g), 3, 4, 250, 140, x_offset=70, y_offset=20)
make_grid(same_spiral(), 3, 4, 250, 140, x_offset=70, y_offset=20)

View File

@ -5,21 +5,9 @@ def make_grid(iterable, cols, rows, width, height, *, x_offset=0, y_offset=0):
Arranges the objects in iterable in a grid with the given parameters.
"""
try:
doodle = next(iterable)
for c in range(cols):
for r in range(rows):
doodle.pos(width * c + x_offset, height * r + y_offset)
doodle = next(iterable)
doodle.pos(width * c + x_offset, height * r + y_offset)
except StopIteration:
pass
def copies(doodle):
"""
Lazily makes an infinite number of copies of a given doodle.
Can be combined with things like `make_grid` that require
an iterable of doodles to repeat.
"""
while True:
yield doodle.copy()

View File

@ -29,7 +29,7 @@ def main(modname: str):
pygame.quit()
sys.exit()
world.render()
# print(f"world contains {world._drawables}")
#print(f"world contains {len(world._drawables)}")
pygame.display.flip()