CSC111 Homework 6 Solution Programs 2011
--D. Thiebaut 15:33, 7 November 2011 (EST)
Moving Balls
Program 1
Program 2
- This version implements fully elastic collision and respects the laws of physics, even giving the two balls a mass proportional to their radii.
#hw6a.py
#111a-ar
#Gavi Levy Haskell
#
#This program is an adaptation of the hw6a Demo Program.
#Two balls, one turquoise and one blue, bounce off the
#walls, each other, and a white box, and stop if they
#completely enter one of three black boxes, or if the
#program goes through 1000 steps.
#
#
#NOTE: The circles bounce "realistically" assuming that:
#
#The speeds never exceed those which Newton's equations
#work for
#
#All collisions occur along the x-y axis (not true for
#virtually any collision, but a fair approximation for
#most blows, less good for glancing blows)
#
#The masses of the circles are relative to each other,
#imagining them to be 2D representations of 3D figures
#(spheres, to be precise)
#
#The world has no friction, either between objects or
#with the ground
#
#The collisions are perfectly elastic
from graphics import *
import random
def distance(P1, P2):
"""distance formula
"""
return (( (P1.getX() - P2.getX())**2 +
(P1.getY() - P2.getY())**2)**.5)
def velocity():
"""picks a random velocity
between -5 and 5, not 0
"""
v = 0
while True:
v = random.randrange(-5, 5)
if v!=0:
return v
def main():
#sets up graphics window
w = 600
h = 300
win = GraphWin("111a-ar: Ten to the Fifteenth", w, h)
win.setBackground("black")
#picks random radii
r1 = random.randrange(10, 20) #radius
r2 = random.randrange(10, 20) #radius
#calls velocity for all four velocities of the
#circle
vx1 = velocity()
vy1 = velocity()
vx2 = velocity()
vy2 = velocity()
#draws circles at random locations
c1 = Circle(Point(random.randrange(r1, w//2),
random.randrange(r1, h//2 - r1)),
r1)
c1.setWidth(0)
c1.setFill("turquoise")
c1.draw(win)
c2 = Circle(Point(random.randrange(r2, w//2),
random.randrange(h//2, h - r2)),
r2)
c2.setWidth(0)
c2.setFill("blue")
c2.draw(win)
#draws white box
rw = Rectangle(Point(400, 200),
Point(500, 250))
rw.setWidth(0)
rw.setFill("white")
rw.draw(win)
#draws three black boxes
boxes = [[10, 240, 80, 290],
[250, 80, 350, 130],
[520, 40, 570, 120]]
for i in range(3):
a, b, c, d = boxes[i]
rb = Rectangle(Point(a,b), Point(c,d))
rb.setOutline("white")
rb.setWidth(2)
rb.draw(win)
#loop to move circles
for i in range(1000):
#assigns locations of circles to variables
x1 = c1.getCenter().getX()
y1 = c1.getCenter().getY()
x2 = c2.getCenter().getX()
y2 = c2.getCenter().getY()
#variable to allow for turning off inter-
#action between circles when in black box
n = 0
#traps circles in black boxes
for j in range(3):
a,b,c,d = boxes[j]
#margin for circle 1
xl1 = a + r1
yu1 = b + r1
xr1 = c - r1
yb1 = d - r1
#if circle is inside box
if xl1 < x1 < xr1 and yu1 < y1 < yb1:
vx1 = 0 #set velocities
vy1 = 0 #to zero
n = 1 #indicates circle is in box
#margin for circle 2
xl2 = a + r2
yu2 = b + r2
xr2 = c - r2
yb2 = d - r2
#if circle is inside box
if xl2 < x2 < xr2 and yu2 < y2 < yb2:
vx2 = 0 #set velocities
vy2 = 0 #to zero
n = 1 #indicates circle is in box
#breaks if circles have been trapped
if vx1 == 0 and vy1 == 0 and vx2 == 0 and vy2 == 0:
break
#lets circles bounce off white box
#FIRST CIRCLE
lb1 = 400 - r1 #left bound for first circle
rb1 = 500 + r1 #right bound
ub1 = 200 - r1 #upper bound
bb1 = 250 + r1 #lower bound
if lb1 < x1 < rb1 and ub1 < y1 < bb1:
if 400 > x1: #on left side
vx1 = -abs(vx1) #bounce left
if 500 < x1: #on right side
vx1 = abs(vx1) #bounce right
if 200 > y1: #above
vy1 = -abs(vy1) #bounce up
if 250 < y1: #below
vy1 = abs(vy1) #bounce down
#SECOND CIRCLE
lb2 = 400 - r2 #left bound for second circle
rb2 = 500 + r2 #right bound
ub2 = 200 - r2 #upper bound
bb2 = 250 + r2 #lower bound
if lb2 < x2 < rb2 and ub2 < y2 < bb2:
if 400 > x2: #on left side
vx2 = -abs(vx2) #bounce left
if 500 < x2: #on right side
vx2 = abs(vx2) #bounce right
if 200 > y2: #above
vy2 = -abs(vy2) #bounce up
if 250 < y2: #below
vy2 = abs(vy2) #bounce down
#lets circles bounce off walls (w/o sticking)
#circle 1
if x1 < r1 + 5: #left side
vx1 = abs(vx1)
if x1 > w - r1: #right side
vx1 = -abs(vx1)
if y1 < r1 + 5: #top
vy1 = abs(vy1)
if y1 > h - r1: #bottom
vy1 = -abs(vy1)
#circle 2
if x2 < r2 + 5: #left side
vx2 = abs(vx2)
if x2 > w - r2: #right side
vx2 = -abs(vx2)
if y2 < r2 + 5: #top
vy2 = abs(vy2)
if y2 > h - r2: #bottom
vy2 = -abs(vy2)
#lets circles bounce off each other
#distance between circles
dc = distance(c1.getCenter(), c2.getCenter())
if dc <= (r1 + r2) and n == 0:
#"masses" of circles (relative, 3D)
m1 = r1*r1*r1
m2 = r2*r2*r2
#elastic collisions
a1 = (vx1*(m1 - m2) + 2*m2*vx2)/(m1 + m2)
a2 = (vx2*(m2 - m1) + 2*m1*vx1)/(m1 + m2)
b1 = (vy1*(m1 - m2) + 2*m2*vy2)/(m1 + m2)
b2 = (vy2*(m2 - m1) + 2*m1*vy1)/(m1 + m2)
vx1 = a1
vx2 = a2
vy1 = b1
vy2 = b2
#moves circles
c1.move(vx1, vy1)
c2.move(vx2, vy2)
text = Text(Point(w//2, h//2), "Click to quit")
text.setFill("white")
text.draw(win)
win.getMouse()
win.close()
main()