my professor has given me this code and the only part im suppose to do is the TODO area. i am rather new to python still and have never touched on this type of project so i am rather confused. all this project is for is to get the plotted graph image.
import math, random, pylab
class Location(object):
def __init__(self, x, y):
self.x = float(x)
self.y = float(y)
def move(self, xc, yc):
return Location(self.x+float(xc), self.y+float(yc))
def getCoords(self):
return self.x, self.y
def getDist(self, other):
ox, oy = other.getCoords()
xDist = self.x - ox
yDist = self.y - oy
return math.sqrt(xDist**2 + yDist**2)
class CompassPt(object):
possibles = ('N', 'S', 'E', 'W')
def __init__(self, pt):
if pt in self.possibles: self.pt = pt
else: raise ValueError('in CompassPt.__init__')
def move(self, dist):
if self.pt == 'N': return (0, dist)
elif self.pt == 'S': return (0, -dist)
elif self.pt == 'E': return (dist, 0)
elif self.pt == 'W': return (-dist, 0)
else: raise ValueError('in CompassPt.move')
class Field(object):
def __init__(self, drunk, loc):
self.drunk = drunk
self.loc = loc
def move(self, cp, dist):
oldLoc = self.loc
xc, yc = cp.move(dist)
self.loc = oldLoc.move(xc, yc)
def getLoc(self):
return self.loc
def getDrunk(self):
return self.drunk
class Drunk(object):
def __init__(self, name):
self.name = name
def move(self, field, time = 1):
if field.getDrunk() != self:
raise ValueError('Drunk.move called with drunk not in field')
for i in range(time):
pt = CompassPt(random.choice(CompassPt.possibles))
field.move(pt, 1)
here is the part that i need to do and have tried to do. so far my graph does not move lol. i get a dot in the middle of the graph, unless its randomly walking in one location if that's possible lol.
# TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
def performTrial(time, f):
start = f.getLoc()
# TODO
distances = [0.0]
for t in range(1, time + 1):
# TODO
f.getDrunk().move(f)
newLoc = f.getLoc()
distance = newLoc.getDist(start)
distances.append(distance)
xcoords, ycoords = distances[::2], distances[1::2]
return xcoords,ycoords
# END OF TODOEND OF TODO END OF TODO END OF TODO END OF TODO
the rest here is also provided by the professor
drunk = Drunk('Homer Simpson')
for i in range(1):
f = Field(drunk, Location(0, 0))
coords = performTrial(500, f)
print(coords)
pylab.plot(coords[0],coords[1],marker='^',linestyle=':',color='b')
pylab.title('Homer\'s Random Walk')
pylab.xlabel('Time')
pylab.ylabel('Distance from Origin')
pylab.show()
update: fixed the coordinates but now i get an error:
in _xy_from_xy(self, x, y)
235 y = np.atleast_1d(y)
236 if x.shape[0] != y.shape[0]:
--> 237 raise ValueError("x and y must have same first dimension")
238 if x.ndim > 2 or y.ndim > 2:
239 raise ValueError("x and y can be no greater than 2-D")
ValueError: x and y must have same first dimension
def move(self, xc, yc):
return Location(self.x+float(xc), self.y+float(yc))
this does not move anything, it just returns new coordinates. Also casting xc and yc to a float should not be needed.
If this function is intended to move the Location, you have to add this:
def move(self, xc, yc):
self.x += xc
self.y += yc
return Location(self.x, self.y)
Related
I'm trying creating a 3D class Vector and I have prepared the following code:
class Vector:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
#return string 'Vector(x,y,z)'
def __repr__(self):
return ("Vector(x,y,z)")
# or alternatively
#def __str__(self):
#return str("Vector3({0.x},{0.y},{0.z})".format(self))
# v == w
def __eq__(self, other):
self.v = Vector(self.x,self.y,self.z)
other.w = Vector(other.x, other.y, other.z)
if self.v() == self.w():
return True
else:
return False
#def __eq__(self, other): # poly1 == poly2
# return (self - other).is_zero() # it works when the substraction is defined
# v != w
def __ne__(self, other):
self.v = Vector(self.x,self.y,self.z)
other.w = Vector(other.x, other.y, other.z)
if self.v() != self.w():
return True
else:
return False
#def __ne__(self, other): # poly1 != poly2
# return not self == other
# v + w
def __add__(self, other):
if other == 0:
return self
else:
return vector(self.x+other.x, self.y+other.y, self.z+other.z)
# v - w
def __sub__(self, other):
self.x -= other.x
self.y -= other.y
self.z -= other.z
# return the dot product (number)
def __mul__(self, other):
self.v = Vector(self.x + self.y + self.z)
self.w = Vector(other.x + other.y + other.z)
return Vector(self.x*other.x,self.y*other.y, self.z*other.z)
#cross product
def __pow__(self, other):
return Vector(self.y*other.z - self.z*other.y,
self.z*other.x - self.x*other.z,
self.z*other.y - self.y*other.x)
# the length of the vector
def length(self):
return len(self)
# we assume that vectors are immutable
def __hash__(self):
return hash((self.x, self.y, self.z))
However no one of the following assert tests seem to work:
import math
v = Vector(1, 2, 3)
w = Vector(2, -3, 2)
assert v != w
assert v + w == Vector(3, -1, 5)
assert v - w == Vector(-1, 5, 1)
assert v * w == 2
assert v.cross(w) == Vector(13, 4, -7)
If someone tries running the following assert code, some errors pop up but I am not able to figure out what the problem is. Moreover, if it is possible I would lie to ask for a possible way to return the hash, length and string representation. Thanks
I am attempting to create a program which simulates particles colliding in a 2D box, but each particle is labeled with a random 5 character string name and each collision is tracked in a list along each particle. So after the simulation, I would like a list from each particle listing which particles it has hit. I have forked this great simulation https://github.com/xnx/collision and added the name and history attributes to the particle class. However, whenever I attempt to access .name or .history, my kernel dies. The output says:
Kernel died, restarting
Restarting kernel...
The failure happens in the handle_collisions function (line 197), or whenever I try to access the history or the name, so there must be something wrong in my implementation of the name and history attributes. I have also tried to instantiate name and history in the init_particles function instead of place_particles but that had the same results. I'm not exactly sure how to correctly implement them. Thanks for your help.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from matplotlib import animation
from itertools import combinations
import random
import string
class Particle:
"""A class representing a two-dimensional particle."""
def __init__(self, x, y, vx, vy, name, history, radius=0.01, styles=None):
"""Initialize the particle's position, velocity, name, history and radius.
Any key-value pairs passed in the styles dictionary will be passed
as arguments to Matplotlib's Circle patch constructor.
"""
self.r = np.array((x, y))
self.v = np.array((vx, vy))
self.radius = radius
self.mass = self.radius**2
self.styles = styles
if not self.styles:
# Default circle styles
self.styles = {'edgecolor': 'b', 'fill': False}
# For convenience, map the components of the particle's position and
# velocity vector onto the attributes x, y, vx and vy.
#property
def x(self):
return self.r[0]
#x.setter
def x(self, value):
self.r[0] = value
#property
def y(self):
return self.r[1]
#y.setter
def y(self, value):
self.r[1] = value
#property
def vx(self):
return self.v[0]
#vx.setter
def vx(self, value):
self.v[0] = value
#property
def vy(self):
return self.v[1]
#vy.setter
def vy(self, value):
self.v[1] = value
#property
def history(self):
return self.history
#history.setter
def history(self,value):
self.history=value
#property
def name(self):
return self.name
#name.setter
def name(self,value):
self.name=value
def overlaps(self, other):
"""Does the circle of this Particle overlap that of other?"""
return np.hypot(*(self.r - other.r)) < self.radius + other.radius
def draw(self, ax):
"""Add this Particle's Circle patch to the Matplotlib Axes ax."""
circle = Circle(xy=self.r, radius=self.radius, **self.styles)
ax.add_patch(circle)
return circle
def advance(self, dt):
"""Advance the Particle's position forward in time by dt."""
self.r += self.v * dt
class Simulation:
"""A class for a simple hard-circle molecular dynamics simulation.
The simulation is carried out on a square domain: 0 <= x < 1, 0 <= y < 1.
"""
ParticleClass = Particle
def __init__(self, n, radius=0.01, styles=None):
"""Initialize the simulation with n Particles with radii radius.
Each particle is initialized with a 10 letter string name and an empty history.
radius can be a single value or a sequence with n values.
Any key-value pairs passed in the styles dictionary will be passed
as arguments to Matplotlib's Circle patch constructor when drawing
the Particles.
"""
self.init_particles(n, radius, styles)
self.dt = 0.01
def place_particle(self, rad, styles):
# Choose x, y so that the Particle is entirely inside the
# domain of the simulation.
x, y = rad + (1 - 2*rad) * np.random.random(2)
# Choose a random velocity (within some reasonable range of
# values) for the Particle.
vr = 0.1 * np.sqrt(np.random.random()) + 0.05
vphi = 2*np.pi * np.random.random()
vx, vy = vr * np.cos(vphi), vr * np.sin(vphi)
name = self.assignname
history = []
particle = self.ParticleClass(x, y, vx, vy, name, history, rad, styles)
# Check that the Particle doesn't overlap one that's already
# been placed.
for p2 in self.particles:
if p2.overlaps(particle):
break
else:
self.particles.append(particle)
return True
return False
def assignname(self):
letters = string.ascii_lowercase
name=''.join(random.choice(letters) for i in range(5))
return name
def init_particles(self, n, radius, styles=None):
"""Initialize the n Particles of the simulation.
Positions and velocities are chosen randomly; radius can be a single
value or a sequence with n values.
"""
try:
iterator = iter(radius)
assert n == len(radius)
except TypeError:
# r isn't iterable: turn it into a generator that returns the
# same value n times.
def r_gen(n, radius):
for i in range(n):
yield radius
radius = r_gen(n, radius)
self.n = n
self.particles = []
for i, rad in enumerate(radius):
# Try to find a random initial position for this particle.
while not self.place_particle(rad, styles):
pass
def change_velocities(self, p1, p2):
"""
Particles p1 and p2 have collided elastically: update their
velocities.
"""
m1, m2 = p1.mass, p2.mass
M = m1 + m2
r1, r2 = p1.r, p2.r
d = np.linalg.norm(r1 - r2)**2
v1, v2 = p1.v, p2.v
u1 = v1 - 2*m2 / M * np.dot(v1-v2, r1-r2) / d * (r1 - r2)
u2 = v2 - 2*m1 / M * np.dot(v2-v1, r2-r1) / d * (r2 - r1)
p1.v = u1
p2.v = u2
def handle_collisions(self):
"""Detect and handle any collisions between the Particles.
When two Particles collide, they do so elastically: their velocities
change such that both energy and momentum are conserved.
"""
# We're going to need a sequence of all of the pairs of particles when
# we are detecting collisions. combinations generates pairs of indexes
# into the self.particles list of Particles on the fly.
#particles share history when they collide
pairs = combinations(range(self.n), 2)
for i,j in pairs:
if self.particles[i].overlaps(self.particles[j]):
self.change_velocities(self.particles[i], self.particles[j])
#FAILS HERE
#self.particles[i].history.append(self.particles[j].name)
#self.particles[j].history.append(self.particles[i].name)
def handle_boundary_collisions(self, p):
"""Bounce the particles off the walls elastically."""
if p.x - p.radius < 0:
p.x = p.radius
p.vx = -p.vx
if p.x + p.radius > 1:
p.x = 1-p.radius
p.vx = -p.vx
if p.y - p.radius < 0:
p.y = p.radius
p.vy = -p.vy
if p.y + p.radius > 1:
p.y = 1-p.radius
p.vy = -p.vy
def apply_forces(self):
"""Override this method to accelerate the particles."""
pass
def advance_animation(self):
"""Advance the animation by dt, returning the updated Circles list."""
for i, p in enumerate(self.particles):
p.advance(self.dt)
self.handle_boundary_collisions(p)
self.circles[i].center = p.r
self.handle_collisions()
self.apply_forces()
return self.circles
def advance(self):
"""Advance the animation by dt."""
for i, p in enumerate(self.particles):
p.advance(self.dt)
self.handle_boundary_collisions(p)
self.handle_collisions()
self.apply_forces()
def init(self):
"""Initialize the Matplotlib animation."""
self.circles = []
for particle in self.particles:
self.circles.append(particle.draw(self.ax))
return self.circles
def animate(self, i):
"""The function passed to Matplotlib's FuncAnimation routine."""
self.advance_animation()
return self.circles
def setup_animation(self):
self.fig, self.ax = plt.subplots()
for s in ['top','bottom','left','right']:
self.ax.spines[s].set_linewidth(2)
self.ax.set_aspect('equal', 'box')
self.ax.set_xlim(0, 1)
self.ax.set_ylim(0, 1)
self.ax.xaxis.set_ticks([])
self.ax.yaxis.set_ticks([])
def save_or_show_animation(self, anim, save, filename='collision.mp4'):
if save:
Writer = animation.writers['ffmpeg']
writer = Writer(fps=10, bitrate=1800)
anim.save(filename, writer=writer)
else:
plt.show()
def do_animation(self, save=False, interval=1, filename='collision.mp4'):
"""Set up and carry out the animation of the molecular dynamics.
To save the animation as a MP4 movie, set save=True.
"""
self.setup_animation()
anim = animation.FuncAnimation(self.fig, self.animate,
init_func=self.init, frames=800, interval=interval, blit=True)
self.save_or_show_animation(anim, save, filename)
if __name__ == '__main__':
nparticles = 20
radii = .02
styles = {'edgecolor': 'C0', 'linewidth': 2, 'fill': None}
sim = Simulation(nparticles, radii, styles)
sim.do_animation(save=False)
I see two immediate problems in your code.
First: you did add history as a Particle.__init__ parameter but you never initialize the property itself.
Add something like this:
def __init__(self, x, y, vx, vy, name, history, radius=0.01, styles=None):
self._history = history
And bigger problem: you have an infinite recursion in your #property definition:
#property
def history(self):
return self.history
#history.setter
def history(self,value):
self.history=value
So in your getter you called history you call itself return self.history which will loop itself until program will crash.
Rename internal property to _history:
#property
def history(self):
return self._history
#history.setter
def history(self,value):
self._history=value
So i have here my main program (which i absolutely can't make any changes because this is how our instructor wants it to be run):
from class_point import Point
from class_polygon import Polygon
pt1 = Point(0,0)
pt2 = Point(0,4)
pt3 = Point(3,0)
polygon1 = Polygon([pt1,pt2,pt3]) #yes, the class Polygon will be initialized using a list
print(polygon1.get_perimeter())
So basically, i have two separate files containing the definitions of class Polygon and class Point.
This is my code for class Point which has the function for calculating the distance between two given points:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self, second):
x_d = self.x - second.x
y_d = self.y - second.y
return (x_d**2 + y_d**2) **0.5
And this is my code for class Polygon which will use the defined points and the distance function to calculate the perimeter of my polygon:
class Polygon():
def __init__(self, points):
self.points = points
def __len__(self):
len_points = len(self.points)
return len_points
def get_perimeter(self,points,len_points):
perimeter = 0
for i in range(0, len_points):
pt1 = self.points[i]
pt2 = self.points[i+1]
perimeter += pt1.distance(pt2)
if i + 1 == len_points:
perimeter += points[-1].distance(points[0])
else:
continue
return perimeter
But whenever i try to run the code, i get the error:
File "C:/Users/Dust/Desktop/polygon_trial.py", line 8, in <module>
print(polygon1.get_perimeter())
TypeError: get_perimeter() missing 2 required positional arguments: 'points' and 'len_points'
This should work
class Polygon():
def __init__(self, points):
self.points = points
def __len__(self):
return len(self.points)
def get_perimeter(self):
perimeter = 0
for i in range(0, len(self.points)):
pt1 = self.points[i]
pt2 = self.points[i+1]
perimeter += pt1.distance(pt2)
if i + 1 == len(self.points):
perimeter += self.points[-1].distance(self.points[0])
else:
continue
return perimeter
First of all, here is a quick graphical description of what I intend to do. I will use Python, but feel free to use pseudo code in your answers.
I have 2 collections of 2D segments, stored as the following: [ [start_point, end_point], [...] ].
For the first step, I have to detect each segment of the blue collection which is colliding with the black collection. For this I use LeMothe's line/line intersection algorithm.
Then comes my first problem: Having a segment AB which intersects with my line in C, I don't know how to determine using code if I have to trim my segment as AC or as CB , ie: I don't know which part of my segment I need to keep and which one I need to remove.
Then for the second step, I have really no ideas how to achieve this.
Any help would be greatly appreciated, so thank you in advance!
The second step is trivial once you figure what to keep and what not, you just need to keep track of the segments you clipped and see where they were originally joined (e.g. assume that the segments are in order and form a connected line).
On the other hand, given that your black line is in fact a line and not a polygon, in your first step, choosing what is "outside" and what is "inside" seems completely arbitrary; is it possible to close that into a polygon? Otherwise, you may need to artificially create two polygons (one for each side of the line) and then do clipping inside those polygons. You could use something like the Cyrus and Beck line clipping algorithm (see this tutorial for an overview: https://www.tutorialspoint.com/computer_graphics/viewing_and_clipping.htm)
Feel free to use any of the code below as a starting point (you have an intersect function and some useful classes). Implements Sutherland and Hodgman.
class Point2(object):
"""Structure for a 2D point"""
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __copy__(self):
return self.__class__(self.x, self.y)
copy = __copy__
def __repr__(self):
return 'Point2(%d, %d)' % (self.x, self.y)
def __getitem__(self, key):
return (self.x, self.y)[key]
def __setitem__(self, key, value):
l = [self.x, self.y]
l[key] = value
self.x, self.y = l
def __eq__(self, other):
if isinstance(other, Point2):
return self.x == other.x and \
self.y == other.y
else:
assert hasattr(other, '__len__') and len(other) == 2
return self.x == other[0] and \
self.y == other[1]
def __ne__(self, other):
return not self.__eq__(other)
def __nonzero__(self):
return self.x != 0 or self.y != 0
def __len__(self):
return 2
class Line2(object):
"""Structure for a 2D line"""
def __init__(self,pt1,pt2):
self.pt1,self.pt2=pt1,pt2
def __repr__(self):
return 'Line2(%s, %s)' % (self.pt1, self.pt2)
class Polygon2(object):
def __init__(self,points):
self.points = points
def __repr__(self):
return '[\n %s\n]' % '\n '.join([str(i) for i in self.points])
def lines(self):
lines = []
e = self.points[-1].copy()
for p in self.points:
lines.append(Line2(e,p))
e = p.copy()
return lines
#return [Line2(a,b) for a,b in zip(self.points,self.points[1:]+[self.points[0]])]
def __copy__(self):
return self.__class__(list(self.points))
copy = __copy__
class Renderer(object):
"""Rendering algorithm implementations"""
def __init__(self,world,img,color=1):
self.world,self.img,self.color=world,img,color
def transform(self,s,r,m,n):
"""Homogeneous transformation operations"""
for i in self.world.points():
j = Matrix3.new_translate(m, n)*Matrix3.new_rotate(r)*Matrix3.new_scale(s)*i
i.x,i.y = j.x,j.y
def clip(self,a,b,c,d):
"""Clipping for the world window defined by a,b,c,d"""
self.clip_lines(a, b, c, d)
self.clip_polygons(a, b, c, d)
def shift(self,a,b,c,d):
"""Shift the world window"""
for i in self.world.points():
i.x -= a
i.y -= b
def clip_lines(self,a,b,c,d):
"""Clipping for lines (i.e. open polygons)"""
clipped = []
for i in self.world.lines:
clipped += [self.clip_lines_cohen_sutherland(i.pt1, i.pt2, a, b, c, d)]
self.world.lines = [i for i in clipped if i]
def clip_polygons(self,a,b,c,d):
"""Clipping for polygons"""
polygons = []
for polygon in self.world.polygons:
new_polygon = self.clip_polygon_sutherland_hodgman(polygon, a, b, c, d)
polygons.append(new_polygon)
self.world.polygons = polygons
def clip_polygon_sutherland_hodgman(self,polygon,xmin,ymin,xmax,ymax):
edges = [Line2(Point2(xmax,ymax),Point2(xmin,ymax)), #top
Line2(Point2(xmin,ymax),Point2(xmin,ymin)), #left
Line2(Point2(xmin,ymin),Point2(xmax,ymin)), #bottom
Line2(Point2(xmax,ymin),Point2(xmax,ymax)), #right
]
def is_inside(pt,line):
# uses the determinant of the vectors (AB,AQ), Q(X,Y) is the query
# left is inside
det = (line.pt2.x-line.pt1.x)*(pt.y-line.pt1.y) - (line.pt2.y-line.pt1.y)*(pt.x-line.pt1.x)
return det>=0
def intersect(pt0,pt1,line):
x1,x2,x3,x4 = pt0.x,pt1.x,line.pt1.x,line.pt2.x
y1,y2,y3,y4 = pt0.y,pt1.y,line.pt1.y,line.pt2.y
x = ((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4)) / ((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4))
y = ((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4)) / ((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4))
return Point2(int(x),int(y))
polygon_new = polygon.copy()
for edge in edges:
polygon_copy = polygon_new.copy()
polygon_new = Polygon2([])
s = polygon_copy.points[-1]
for p in polygon_copy.points:
if is_inside(s,edge) and is_inside(p,edge):
polygon_new.points.append(p)
elif is_inside(s,edge) and not is_inside(p,edge):
polygon_new.points.append(intersect(s,p,edge))
elif not is_inside(s,edge) and not is_inside(p,edge):
pass
else:
polygon_new.points.append(intersect(s,p,edge))
polygon_new.points.append(p)
s = p
return polygon_new
def clip_lines_cohen_sutherland(self,pt0,pt1,xmin,ymin,xmax,ymax):
"""Cohen-Sutherland clipping algorithm for line pt0 to pt1 and clip rectangle with diagonal from (xmin,ymin) to (xmax,ymax)."""
TOP = 1
BOTTOM = 2
RIGHT = 4
LEFT = 8
def ComputeOutCode(pt):
code = 0
if pt.y > ymax: code += TOP
elif pt.y < ymin: code += BOTTOM
if pt.x > xmax: code += RIGHT
elif pt.x < xmin: code += LEFT
return code
accept = False
outcode0, outcode1 = ComputeOutCode(pt0), ComputeOutCode(pt1)
while True:
if outcode0==outcode1==0:
accept=True
break
elif outcode0&outcode1:
accept=False
break
else:
#Failed both tests, so calculate the line segment to clip from an outside point to an intersection with clip edge.
outcodeOut = outcode0 if not outcode0 == 0 else outcode1
if TOP & outcodeOut:
x = pt0.x + (pt1.x - pt0.x) * (ymax - pt0.y) / (pt1.y - pt0.y)
y = ymax
elif BOTTOM & outcodeOut:
x = pt0.x + (pt1.x - pt0.x) * (ymin - pt0.y) / (pt1.y - pt0.y)
y = ymin
elif RIGHT & outcodeOut:
y = pt0.y + (pt1.y - pt0.y) * (xmax - pt0.x) / (pt1.x - pt0.x);
x = xmax;
elif LEFT & outcodeOut:
y = pt0.y + (pt1.y - pt0.y) * (xmin - pt0.x) / (pt1.x - pt0.x);
x = xmin;
if outcodeOut == outcode0:
pt0 = Point2(x,y)
outcode0 = ComputeOutCode(pt0)
else:
pt1 = Point2(x,y)
outcode1 = ComputeOutCode(pt1);
if accept:
return Line2(pt0,pt1)
else:
return False
I think what you'll need to do is find a line from the center of the blue object to the line segment in question. If that new line from the center to the segment AB or BC hits a black line on its way to the blue line segment, then that segment is outside and is trimmed. You would want to check this at a point between A and B or between B and C, so that you don't hit the intersection point.
As for the python aspect, I would recommend defining a line object class with some midpoint attributes and a shape class that's made up of lines with a center attribute, (Actually come to think of it, then a line would count as a shape so you could make line a child class of the shape class and preserve code), that way you can make methods that compare two lines as part of each object.
line_a = Line((4,2),(6,9))
line_b = Line((8,1),(2,10))
line_a.intersects(line.b) #Could return Boolean, or the point of intersection
In my mind that just feels like a really comfortable way to go about this problem since it lets you keep track of what everything's doing.
I have 2 modules in my project:
1- Ant.py
from threading import Thread
from Ant_farm import Ant_farm
ant_farm = Ant_farm(20, 20)
class Ant(Thread):
def __init__(self, x, y):
global ant_farm
Thread.__init__(self)
self.x = x
self.y = y
ant_farm.matrix[self.x][self.y] = True # At this point the arguments has initialized?
def move(self, x, y):
ant_farm.matrix[self.x][self.y] = False
self.x = x
self.y = y
ant_farm.matrix[self.x][self.y] = True # At this point the value has changed?
def run(self):
while True:
ant_farm.move_ant(self)
t = Ant(0, 0)
print(ant_farm[0][0])
t.move(1, 0)
2- Ant_farm.py
from threading import Condition
def matrix(x, y):
return [[False for j in range(y)] for i in range(x)]
class Ant_farm():
def __init__(self, x, y):
self.c = Condition() # I don't know if I have to put "self" before
self.matrix = matrix(x, y)
def move_ant(self, ant):
new_pos = {0: tuple(x0, y0 - 1),
1: tuple(x0 + 1, y0),
2: tuple(x0, y0 + 1),
3: tuple(x0 - 1, y0)}
x0, y0 = ant.x, ant.y
x1, y1 = new_pos[random.randrange(0, 4)]
with self.c:
try:
while self.matrix[x1][y1]:
self.c.wait()
self.matrix[x0][y0] = False
ant.move(x1, y1)
# It's not end and I have to review
except Exception: # Wich exceptions can appear?
pass
def __str__(self):
pass
In both omit the comments.
When I execute the Ant module, raises this error:
AttributeError: Ant_farm instance has no attribute '__getitem__'
in the line 27 (print(ant_farm[0][0])). Why does this?
As the error message says, you did not define what ant_farm[i] is (the function __getitem__).
You probably want something like this in your Ant_farm class:
def __getitem__(i):
return self.matrix[i]