Let's use some of our computing skills to build a simulation, but this time let's have some interation among the objects to see if we can get some interesting behavior to emerge.
First, we'll need some ability to create objects in random places, with random properties. And we'll want to visualize our results.
import random
import Graphics
For these simulations, we want to have sheep who eat grass and wolves who eat sheep.
Let's start with a Sheep object, using the "class" notation.
class Sheep:
def __init__(self, world):
self.world = world
self.x = random.randint(0, world.width - 1)
self.y = random.randint(0, world.height - 1)
self.energy = self.initial_energy()
self.state = "alive"
self.t = 0
self.gestation = random.randint(int(self.energy * 1.5),
int(self.energy * 2.0))
def initial_energy(self):
return 10
def move(self):
self.t += 1
if self.energy <= 0:
self.state = "dead"
elif self.t % self.gestation == 0:
newSheep = Sheep(self.world)
if self.clear(newSheep.x, newSheep.y):
self.world.sheep.append(newSheep)
else:
if self.world.grass[self.x][self.y] > 0:
self.world.grass[self.x][self.y] -= 1
self.energy += 1
else:
self.energy -= 1
self.x += random.choice([-1, 0, 1])
self.y += random.choice([-1, 0, 1])
if self.x < 0:
self.x = self.world.width - 1
elif self.x >= self.world.width:
self.x = 0
if self.y < 0:
self.y = self.world.height - 1
elif self.y >= self.world.height:
self.y = 0
def clear(self, x, y):
for w in self.world.wolf:
if w.x == x and w.y == y:
return False
for s in self.world.sheep:
if s.x == x and s.y == y:
return False
return True
Next, we'll create a Wolf that extends, and overrides some of the Sheep's properties.
class Wolf(Sheep):
def initial_energy(self):
return 20
def move(self):
self.t += 1
if self.energy <= 0:
self.state = "dead"
elif self.t % self.gestation == 0:
newWolf = Wolf(self.world)
if self.clear(newWolf.x, newWolf.y):
self.world.wolf.append(newWolf)
else:
for s in self.world.sheep:
if s.state == "alive" and s.x == self.x and s.y == self.y:
# yum!
s.state = "dead"
self.energy += s.initial_energy()
return
self.energy -= 1
self.x += random.choice([-1, 0, 1])
self.y += random.choice([-1, 0, 1])
if self.x < 0:
self.x = self.world.width - 1
elif self.x >= self.world.width:
self.x = 0
if self.y < 0:
self.y = self.world.height - 1
elif self.y >= self.world.height:
self.y = 0
def clear(self, x, y):
for w in self.world.wolf:
if w.x == x and w.y == y:
return False
return True
A now a World where they can both live.
class World:
def __init__(self, width, height, wolves, sheep):
self.width = width
self.height = height
self.wolf = [Wolf(self) for w in range(wolves)]
self.sheep = [Sheep(self) for s in range(sheep)]
self.grass = [[0 for y in range(height)] for x in range(width)]
for x in range(width):
for y in range(height):
if random.random() < .3:
self.grass[x][y] = 10
self.size = 20
self.window = Graphics.Window(width * self.size, height * self.size)
self.window.mode = "bitmap"
def show(self):
for x in range(self.width):
for y in range(self.height):
grass = self.grass[x][y]
rec = Graphics.Rectangle((x * self.size, y * self.size),
((x + 1) * self.size, (y + 1) * self.size))
rec.fill = Graphics.Color(0, grass/20 * 255, 0)
rec.draw(self.window)
for w in self.wolf:
if w.state == "alive":
wolf = Graphics.Text((w.x * self.size + self.size/2,
w.y * self.size + self.size/2), "W")
wolf.draw(self.window)
for s in self.sheep:
if s.state == "alive":
sheep = Graphics.Text((s.x * self.size + self.size/2,
s.y * self.size + self.size/2), "s")
sheep.fill = Graphics.Color(255,255,255)
sheep.draw(self.window)
self.window.step()
return self.window
def move(self):
for s in self.sheep[:]:
if s.state == "alive":
s.move()
else:
self.sheep.remove(s)
for w in self.wolf[:]:
if w.state == "alive":
w.move()
else:
self.wolf.remove(w)
for x in range(self.width):
for y in range(self.height):
if random.random() < .005:
self.grass[x][y] = max(10, self.grass[x][y])
world = World(25, 25, 0, 50)
world.show()
count = 0
while True:
world.move()
calico.animate(world.show())
print(count,
len([w for w in world.wolf if w.state == "alive"]),
len([s for s in world.sheep if s.state == "alive"]))
count += 1
40 0 160
Running script aborted!
world.show()
world = World(25, 25, 10, 50)
world.show()
count = 0
while True:
world.move()
calico.animate(world.show())
print(count,
len([w for w in world.wolf if w.state == "alive"]),
len([s for s in world.sheep if s.state == "alive"]))
count += 1
65 9 142
Running script aborted!
world.show()