Difference between revisions of "CSC111 Homework 6 Solution Programs 2011"
(→Program 3) |
|||
(2 intermediate revisions by the same user not shown) | |||
Line 489: | Line 489: | ||
<br /> | <br /> | ||
+ | ==Program 3== | ||
+ | * This version uses a list for the boxes as well as for the circles | ||
+ | <br /> | ||
+ | <br /> | ||
+ | <source lang="python"> | ||
+ | # CSC 111 Thiebaut | ||
+ | # hw6a.py | ||
+ | # 111a-be | ||
+ | # Naomi Long | ||
+ | # Edited by D. Thiebaut | ||
+ | # | ||
+ | # This program shows two balls moving in the graphics window with three randomly | ||
+ | # placed black rectangles that they can get trapped inside. One white rectangle | ||
+ | # is generated that the balls reflect off of. Balls reverse direction when | ||
+ | # colliding with the window. Both balls are given random colors and | ||
+ | # random sizes. | ||
+ | # | ||
+ | # The initial location and speed of the balls are random, but such | ||
+ | # that the balls appear in the window and are visible. It is possible | ||
+ | # for a ball to have a Y speed of 0, so it only moves horizontally. | ||
+ | # | ||
+ | # If the balls end up inside of the black boxes or the range function runs for | ||
+ | # 1000 cycles, the program ends. | ||
+ | # | ||
+ | # If the balls collide, they reverse motion in the x and y direction. If the | ||
+ | # balls don't collide head-on, the collision looks fake. The balls can also | ||
+ | # get stuck in collision loops where they travel the same path for the rest | ||
+ | # of the program between two collisions, though this is unlikely because of the | ||
+ | # black boxes and the white box. | ||
+ | # | ||
+ | # If a ball starts with 0 speed in the Y axis, when collided with it will | ||
+ | # still keep 0 speed in that axis. | ||
+ | # | ||
+ | # If ball generates inside a box, it will be hidden for the rest of the program. | ||
+ | # A ball can collide with another ball even if theother ball is trapped in a | ||
+ | # box. | ||
+ | |||
+ | from graphics import * | ||
+ | import random | ||
+ | from math import * | ||
+ | |||
+ | def distance( P1, P2 ): | ||
+ | """ computes distance for ball-on-ball collisions """ | ||
+ | x = sqrt(pow(P1.getX() - P2.getX(), 2) + pow(P1.getY() - P2.getY(), 2)) | ||
+ | return x | ||
+ | |||
+ | def isInside(c, r, offset ): | ||
+ | """ calculates whether a ball is inside a black box """ | ||
+ | xc = c.getCenter().getX() | ||
+ | yc = c.getCenter().getY() | ||
+ | x1 = r.getP1().getX() | ||
+ | y1 = r.getP1().getY() | ||
+ | x2 = r.getP2().getX() | ||
+ | y2 = r.getP2().getY() | ||
+ | x1, x2 = min( x1, x2), max( x1, x2 ) | ||
+ | y1, y2 = min( y1, y2), max( y1, y2 ) | ||
+ | if ( ( x1 + offset <= xc <= x2 - offset ) | ||
+ | and ( y1 + offset <= yc <= y2 - offset ) ): | ||
+ | return 1 | ||
+ | return 0 | ||
+ | |||
+ | def getNewBall( i, W, H ): | ||
+ | # defines colors balls can be | ||
+ | colors = ["red", "blue", "green", "yellow", "black", "white"] | ||
+ | |||
+ | # draw 1st ball at random place with random velocity and random color | ||
+ | c1r = random.randrange(10, 20) | ||
+ | c1 = Circle(Point(random.randrange( c1r+1, W-c1r-1 ), # random X | ||
+ | random.randrange( c1r+1, H-c1r-1 ) ), # random Y | ||
+ | c1r) # random radius | ||
+ | c1color = random.choice( colors ) | ||
+ | c1.setFill(c1color) | ||
+ | c1.setOutline(c1color) | ||
+ | dirX1 = random.randrange( 1, 5 ) # random X speed | ||
+ | if ( random.randrange( 0, 100 ) ) < 50: | ||
+ | dirX1 = -dirX1 | ||
+ | dirY1 = random.randrange( 1, 5 ) # random Y speed | ||
+ | if ( random.randrange( 0, 100 ) ) < 50: | ||
+ | dirY1 = -dirY1 | ||
+ | return c1, dirX1, dirY1 | ||
+ | |||
+ | |||
+ | def main(): | ||
+ | """ opens a graphics window """ | ||
+ | W = 600 | ||
+ | H = 400 | ||
+ | win = GraphWin("111a-be's billiard program", W, H) | ||
+ | win.setBackground(color_rgb(25, 25, 112)) | ||
+ | noBoxes = 3 | ||
+ | noCircles = 5 | ||
+ | |||
+ | # define random coordinates for black boxes | ||
+ | boxes = [] | ||
+ | for i in range( noBoxes ): | ||
+ | x1 = 10 + i * W // noBoxes | ||
+ | x2 = x1 + W // (noBoxes * 2 ) | ||
+ | y1 = 10 + i * H // noBoxes | ||
+ | y2 = x1 + H // (noBoxes * 2 ) | ||
+ | boxes.append( Rectangle( Point( x1, y1), Point( x2, y2 ) ) ) | ||
+ | boxes[i].setFill("black") | ||
+ | boxes[i].draw(win) | ||
+ | |||
+ | |||
+ | # define size of white box | ||
+ | ws1 = 50 | ||
+ | |||
+ | # define random coordinates for white box | ||
+ | wp1a = random.randrange(10, W//3 - (ws1 + 20)) | ||
+ | wp1b = random.randrange(H//2 + 40, H - 40) | ||
+ | WP1 = Point(wp1a, wp1b) | ||
+ | WP2 = Point(wp1a + ws1, wp1b + ws1) | ||
+ | |||
+ | # draw white box | ||
+ | wr = Rectangle( Point( 10, H-10 ), Point( 10+W/(noBoxes*2), H-10-H//(noBoxes*2) ) ) | ||
+ | wr.setFill("white") | ||
+ | wr.setWidth(3) | ||
+ | wr.draw(win) | ||
+ | |||
+ | # create circles | ||
+ | circles = [] | ||
+ | for i in range( noCircles ): | ||
+ | c1, dirX1, dirY1 = getNewBall( i, W, H ) | ||
+ | c1.draw( win ) | ||
+ | circles.append( [c1, dirX1, dirY1 ] ) | ||
+ | |||
+ | # moving balls and collisions | ||
+ | for i in range(1000): | ||
+ | |||
+ | # moves balls at velocities given | ||
+ | for i in range( noCircles ): | ||
+ | c1, dirX1, dirY1 = circles[ i ] | ||
+ | c1.move( dirX1, dirY1 ) | ||
+ | |||
+ | # make c1 bounce off of walls | ||
+ | for i in range( len( circles ) ): | ||
+ | c1, dirX1, dirY1 = circles[ i ] | ||
+ | if c1.getCenter().getX() < c1.getRadius() + 4 or c1.getCenter().getX() > W - c1.getRadius(): | ||
+ | dirX1 = -dirX1 | ||
+ | #print( "1" ) | ||
+ | if c1.getCenter().getY() < c1.getRadius() + 4 or c1.getCenter().getY() > H - c1.getRadius(): | ||
+ | dirY1 = -dirY1 | ||
+ | #print( "2" ) | ||
+ | circles[ i ] = [ c1, dirX1, dirY1 ] | ||
+ | |||
+ | |||
+ | # make balls reverse direction when they collide | ||
+ | for i in range( len( circles ) ): | ||
+ | for j in range( i+1, len( circles ) ): | ||
+ | c1, dirX1, dirY1 = circles[ i ] | ||
+ | c2, dirX2, dirY2 = circles[ j ] | ||
+ | dist = distance( c1.getCenter(), c2.getCenter()) | ||
+ | if dist <= (c1.getRadius() + c2.getRadius() ): | ||
+ | dirX1 = -dirX1 | ||
+ | dirY1 = -dirY1 | ||
+ | dirX2 = -dirX2 | ||
+ | dirY2 = -dirY2 | ||
+ | circles[ i ] = [ c1, dirX1, dirY1 ] | ||
+ | circles[ j ] = [ c2, dirX2, dirY2 ] | ||
+ | #print( "3", dist ) | ||
+ | |||
+ | # make ball 1 bounce off of white box | ||
+ | for i in range( len( circles ) ): | ||
+ | c1, dirX1, dirY1 = circles[ i ] | ||
+ | if isInside(c1, wr, -c1.getRadius() ) == 1: | ||
+ | dirX1 = -dirX1 | ||
+ | dirY1 = -dirY1 | ||
+ | circles[ i ] = [ c1, dirX1, dirY1 ] | ||
+ | #print( "4" ) | ||
+ | |||
+ | |||
+ | # make ball 1 catch in black boxes | ||
+ | for i in range( len( circles ) ): | ||
+ | c1, dirX1, dirY1 = circles[ i ] | ||
+ | for r in boxes: | ||
+ | if isInside(c1, r, c1.getRadius() ) == 1: | ||
+ | dirX1 = 0 | ||
+ | dirY1 = 0 | ||
+ | circles[ i ] = [ c1, dirX1, dirY1 ] | ||
+ | #print( "5" ) | ||
+ | break | ||
+ | |||
+ | # end program if both balls are stuck in black boxes | ||
+ | count = 0 | ||
+ | for c1, dirX1, dirY1 in circles: | ||
+ | if (dirX1 == 0 and dirY1 == 0): | ||
+ | count = count + 1 | ||
+ | |||
+ | # wait for one more click and close up window | ||
+ | if count == len( circles ): | ||
+ | t1 = Text(Point(W//2, H//2), "Click me to quit") | ||
+ | t1.setFill("white") | ||
+ | t1.draw(win) | ||
+ | win.getMouse() | ||
+ | win.close() | ||
+ | return | ||
+ | |||
+ | main() | ||
+ | |||
+ | </source> | ||
+ | <br /> | ||
+ | <br /> | ||
+ | |||
=Statitics= | =Statitics= | ||
Latest revision as of 20:26, 7 November 2011
--D. Thiebaut 15:33, 7 November 2011 (EST)
Moving Balls
Program 1
# CSC 111 Thiebaut
# hw6a.py
# 111a-be
# Naomi Long
#
# This program shows two balls moving in the graphics window with three randomly
# placed black rectangles that they can get trapped inside. One white rectangle
# is generated that the balls reflect off of. Balls reverse direction when
# colliding with the window. Both balls are given random colors and
# random sizes.
#
# The initial location and speed of the balls are random, but such
# that the balls appear in the window and are visible. It is possible
# for a ball to have a Y speed of 0, so it only moves horizontally.
#
# If the balls end up inside of the black boxes or the range function runs for
# 1000 cycles, the program ends.
#
# If the balls collide, they reverse motion in the x and y direction. If the
# balls don't collide head-on, the collision looks fake. The balls can also
# get stuck in collision loops where they travel the same path for the rest
# of the program between two collisions, though this is unlikely because of the
# black boxes and the white box.
#
# If a ball starts with 0 speed in the Y axis, when collided with it will
# still keep 0 speed in that axis.
#
# If ball generates inside a box, it will be hidden for the rest of the program.
# A ball can collide with another ball even if theother ball is trapped in a
# box.
from graphics import *
import random
from math import *
def distance( P1, P2 ):
# computes distance for ball-on-ball collisions
x = sqrt(pow(P1.getX() - P2.getX(), 2) + pow(P1.getY() - P2.getY(), 2))
return x
def isInside(c, r, P1, P2, cr):
# calculates whether a ball is inside a black box
xc = c.getCenter().getX()
yc = c.getCenter().getY()
x1 = P1.getX()
y1 = P1.getY()
x2 = P2.getX()
y2 = P2.getY()
if (x1 + cr <= xc <= x2 - cr) and (y1 + cr <= yc <= y2 - cr):
return 0
def bounce(c, r, P1, P2, cr):
# calculates if outside edges of ball are touching white box
xc = c.getCenter().getX()
yc = c.getCenter().getY()
x1 = P1.getX()
y1 = P1.getY()
x2 = P2.getX()
y2 = P2.getY()
if (x1 - cr <= xc <= x2 + cr) and (y1 - cr <= yc <= y2 + cr):
return 0
def main():
# opens a graphics window
W = 600
H = 400
win = GraphWin("111a-be's billiard program", W, H)
win.setBackground(color_rgb(25, 25, 112))
# defines colors balls can be
colors = ["red", "blue", "green", "yellow", "black", "white"]
# draw 1st ball at random place with random velocity and random color
c1r = random.randrange(10, 20)
c1 = Circle(Point(random.randrange(50, W//2 - 50), # random X
random.randrange(50, H//2 - 50)), # random Y
c1r) # random radius
c1color = colors[random.randrange(5)] # random color
c1.setFill(c1color)
c1.setOutline(c1color)
dirX1 = random.randrange(-5, 5) # random X speed
if dirX1 == 0: # X can't be 0
dirX1 = dirX1 + 1
dirY1 = random.randrange(-5, 5) # random Y speed
c1.draw(win)
# draw 2nd ball at random place with random velocity and random color
c2r = random.randrange(10, 20)
c2 = Circle(Point(random.randrange(W//2, W-50), # random X
random.randrange(H//2, H-50)), # random Y
c2r) # random radius
c2color = colors[random.randrange(5)] # random color
c2.setFill(c2color)
c2.setOutline(c2color)
dirX2 = random.randrange(-5, 5) # random X speed
if dirX2 == 0: # X can't be 0
dirX2 = dirX2 + 1
dirY2 = random.randrange(-5, 5) # random Y speed
c2.draw(win)
# define sizes for boxes
s1 = 70
s2 = 80
s3 = 60
# define random coordinates for black boxes
p1a = random.randrange(10, W//3 - (s1 + 20))
p1b = random.randrange(10, H//2 - (s1 + 20))
P1 = Point(p1a, p1b)
P2 = Point(p1a + s1, p1b + s1)
p3a = random.randrange(W//3 + 10, (2 * W // 3) - (s2 + 20))
p3b = random.randrange(H//3 + 10, (2 * H // 3) - (s2 + 20))
P3 = Point(p3a, p3b)
P4 = Point(p3a + s2, p3b + s2)
p5a = random.randrange((2 * W // 3) + 20, W - (s3 + 20))
p5b = random.randrange((2 * H // 3) + 20, H - (s3 + 20))
P5 = Point(p5a, p5b)
P6 = Point(p5a + s3, p5b + s3)
# arranges points in rectangles
boxes = []
r = Rectangle( P1, P2 )
boxes.append(r)
r = Rectangle( P3, P4 )
boxes.append(r)
r = Rectangle( P5, P6 )
boxes.append(r)
# draws black boxes
for i in range(len(boxes)):
boxes[i].setFill("black")
boxes[i].draw(win)
# define size of white box
ws1 = 50
# define random coordinates for white box
wp1a = random.randrange(10, W//3 - (ws1 + 20))
wp1b = random.randrange(H//2 + 40, H - 40)
WP1 = Point(wp1a, wp1b)
WP2 = Point(wp1a + ws1, wp1b + ws1)
# draw white box
wr = Rectangle(WP1, WP2)
wr.setFill("white")
wr.setWidth(3)
wr.draw(win)
# moving balls and collisions
for i in range(1000):
stuck = 0
# moves balls at velocities given
c1.move(dirX1, dirY1)
c2.move(dirX2, dirY2)
# make c1 bounce off of walls
if c1.getCenter().getX() < c1r + 4 or c1.getCenter().getX() > W - c1r:
dirX1 = -dirX1
if c1.getCenter().getY() < c1r + 4 or c1.getCenter().getY() > H - c1r:
dirY1 = -dirY1
# make c2 bounce off of walls
if c2.getCenter().getX() < c2r + 4 or c2.getCenter().getX() > W - c2r:
dirX2 = -dirX2
if c2.getCenter().getY() < c2r + 4 or c2.getCenter().getY() > H - c2r:
dirY2 = -dirY2
# make balls reverse direction when they collide
if distance(c1.getCenter(), c2.getCenter()) <= (c1r + c2r):
dirX1 = -dirX1
dirY1 = -dirY1
dirX2 = -dirX2
dirY2 = -dirY2
# make ball 1 bounce off of white box
if bounce(c1, wr, WP1, WP2, c1r) == 0:
dirX1 = -dirX1
dirY1 = -dirY1
# make ball 2 bounce off of white box
if bounce(c2, wr, WP1, WP2, c2r) == 0:
dirX2 = -dirX2
dirY2 = -dirY2
# make ball 1 catch in black boxes
if isInside(c1, r, P1, P2, c1r) == 0:
dirX1 = 0
dirY1 = 0
if isInside(c1, r, P3, P4, c1r) == 0:
dirX1 = 0
dirY1 = 0
if isInside(c1, r, P5, P6, c1r) == 0:
dirX1 = 0
dirY1 = 0
# make ball 2 catch in black boxes
if isInside(c2, r, P1, P2, c2r) == 0:
dirX2 = 0
dirY2 = 0
if isInside(c2, r, P3, P4, c2r) == 0:
dirX2 = 0
dirY2 = 0
if isInside(c2, r, P5, P6, c2r) == 0:
dirX2 = 0
dirY2 = 0
# end program if both balls are stuck in black boxes
if (dirX1 == 0 and dirY1 == 0) and (dirX2 == 0 and dirY2 == 0):
t = Text(Point(W//2, H//2), "Click me to quit")
t.setFill("white")
t.draw(win)
win.getMouse()
win.close()
stuck = 1
break
# wait for one more click and close up window
if stuck != 1:
t1 = Text(Point(W//2, H//2), "Click me to quit")
t1.setFill("white")
t1.draw(win)
win.getMouse()
win.close()
main()
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()
Program 3
- This version uses a list for the boxes as well as for the circles
# CSC 111 Thiebaut
# hw6a.py
# 111a-be
# Naomi Long
# Edited by D. Thiebaut
#
# This program shows two balls moving in the graphics window with three randomly
# placed black rectangles that they can get trapped inside. One white rectangle
# is generated that the balls reflect off of. Balls reverse direction when
# colliding with the window. Both balls are given random colors and
# random sizes.
#
# The initial location and speed of the balls are random, but such
# that the balls appear in the window and are visible. It is possible
# for a ball to have a Y speed of 0, so it only moves horizontally.
#
# If the balls end up inside of the black boxes or the range function runs for
# 1000 cycles, the program ends.
#
# If the balls collide, they reverse motion in the x and y direction. If the
# balls don't collide head-on, the collision looks fake. The balls can also
# get stuck in collision loops where they travel the same path for the rest
# of the program between two collisions, though this is unlikely because of the
# black boxes and the white box.
#
# If a ball starts with 0 speed in the Y axis, when collided with it will
# still keep 0 speed in that axis.
#
# If ball generates inside a box, it will be hidden for the rest of the program.
# A ball can collide with another ball even if theother ball is trapped in a
# box.
from graphics import *
import random
from math import *
def distance( P1, P2 ):
""" computes distance for ball-on-ball collisions """
x = sqrt(pow(P1.getX() - P2.getX(), 2) + pow(P1.getY() - P2.getY(), 2))
return x
def isInside(c, r, offset ):
""" calculates whether a ball is inside a black box """
xc = c.getCenter().getX()
yc = c.getCenter().getY()
x1 = r.getP1().getX()
y1 = r.getP1().getY()
x2 = r.getP2().getX()
y2 = r.getP2().getY()
x1, x2 = min( x1, x2), max( x1, x2 )
y1, y2 = min( y1, y2), max( y1, y2 )
if ( ( x1 + offset <= xc <= x2 - offset )
and ( y1 + offset <= yc <= y2 - offset ) ):
return 1
return 0
def getNewBall( i, W, H ):
# defines colors balls can be
colors = ["red", "blue", "green", "yellow", "black", "white"]
# draw 1st ball at random place with random velocity and random color
c1r = random.randrange(10, 20)
c1 = Circle(Point(random.randrange( c1r+1, W-c1r-1 ), # random X
random.randrange( c1r+1, H-c1r-1 ) ), # random Y
c1r) # random radius
c1color = random.choice( colors )
c1.setFill(c1color)
c1.setOutline(c1color)
dirX1 = random.randrange( 1, 5 ) # random X speed
if ( random.randrange( 0, 100 ) ) < 50:
dirX1 = -dirX1
dirY1 = random.randrange( 1, 5 ) # random Y speed
if ( random.randrange( 0, 100 ) ) < 50:
dirY1 = -dirY1
return c1, dirX1, dirY1
def main():
""" opens a graphics window """
W = 600
H = 400
win = GraphWin("111a-be's billiard program", W, H)
win.setBackground(color_rgb(25, 25, 112))
noBoxes = 3
noCircles = 5
# define random coordinates for black boxes
boxes = []
for i in range( noBoxes ):
x1 = 10 + i * W // noBoxes
x2 = x1 + W // (noBoxes * 2 )
y1 = 10 + i * H // noBoxes
y2 = x1 + H // (noBoxes * 2 )
boxes.append( Rectangle( Point( x1, y1), Point( x2, y2 ) ) )
boxes[i].setFill("black")
boxes[i].draw(win)
# define size of white box
ws1 = 50
# define random coordinates for white box
wp1a = random.randrange(10, W//3 - (ws1 + 20))
wp1b = random.randrange(H//2 + 40, H - 40)
WP1 = Point(wp1a, wp1b)
WP2 = Point(wp1a + ws1, wp1b + ws1)
# draw white box
wr = Rectangle( Point( 10, H-10 ), Point( 10+W/(noBoxes*2), H-10-H//(noBoxes*2) ) )
wr.setFill("white")
wr.setWidth(3)
wr.draw(win)
# create circles
circles = []
for i in range( noCircles ):
c1, dirX1, dirY1 = getNewBall( i, W, H )
c1.draw( win )
circles.append( [c1, dirX1, dirY1 ] )
# moving balls and collisions
for i in range(1000):
# moves balls at velocities given
for i in range( noCircles ):
c1, dirX1, dirY1 = circles[ i ]
c1.move( dirX1, dirY1 )
# make c1 bounce off of walls
for i in range( len( circles ) ):
c1, dirX1, dirY1 = circles[ i ]
if c1.getCenter().getX() < c1.getRadius() + 4 or c1.getCenter().getX() > W - c1.getRadius():
dirX1 = -dirX1
#print( "1" )
if c1.getCenter().getY() < c1.getRadius() + 4 or c1.getCenter().getY() > H - c1.getRadius():
dirY1 = -dirY1
#print( "2" )
circles[ i ] = [ c1, dirX1, dirY1 ]
# make balls reverse direction when they collide
for i in range( len( circles ) ):
for j in range( i+1, len( circles ) ):
c1, dirX1, dirY1 = circles[ i ]
c2, dirX2, dirY2 = circles[ j ]
dist = distance( c1.getCenter(), c2.getCenter())
if dist <= (c1.getRadius() + c2.getRadius() ):
dirX1 = -dirX1
dirY1 = -dirY1
dirX2 = -dirX2
dirY2 = -dirY2
circles[ i ] = [ c1, dirX1, dirY1 ]
circles[ j ] = [ c2, dirX2, dirY2 ]
#print( "3", dist )
# make ball 1 bounce off of white box
for i in range( len( circles ) ):
c1, dirX1, dirY1 = circles[ i ]
if isInside(c1, wr, -c1.getRadius() ) == 1:
dirX1 = -dirX1
dirY1 = -dirY1
circles[ i ] = [ c1, dirX1, dirY1 ]
#print( "4" )
# make ball 1 catch in black boxes
for i in range( len( circles ) ):
c1, dirX1, dirY1 = circles[ i ]
for r in boxes:
if isInside(c1, r, c1.getRadius() ) == 1:
dirX1 = 0
dirY1 = 0
circles[ i ] = [ c1, dirX1, dirY1 ]
#print( "5" )
break
# end program if both balls are stuck in black boxes
count = 0
for c1, dirX1, dirY1 in circles:
if (dirX1 == 0 and dirY1 == 0):
count = count + 1
# wait for one more click and close up window
if count == len( circles ):
t1 = Text(Point(W//2, H//2), "Click me to quit")
t1.setFill("white")
t1.draw(win)
win.getMouse()
win.close()
return
main()
Statitics
#hw6b.py
#111a-ar
#Gavi Levy Haskell
#
#Prints formatted top ten lists by population, internet
#users, ratio of active users to population, and some
#global statistics based on a list of countries and
#their attributes.
#list of statistics about internet usage in countries
statistics = [['Afghanistan', 28710000, -1, -1, 1],
['Albania', 3580000, 12000, -1, 10],
['Algeria', 32810000, 180000, -1, 2],
['Andorra', 69150, 24500, -1, 1],
['Angola', 10760000, 60000, -1, 1],
['Anguilla', 12738, 919, -1, 16],
['Antigua_and_Barbuda', 67897, 5000, -1, 16],
['Argentina', 38740000, 4650000, -1, 33],
['Armenia', 3320000, 30000, -1, 9],
['Aruba', 70844, 24000, -1, -1],
['Australia', 19730000, 13010000, 9020000, 571],
['Austria', 8180000, 4650000, 1300000, 37],
['Azerbaijan', 7830000, 25000, -1, 2],
['Bahrain', 667238, 140200, -1, 1],
['Bangladesh', 138440000, 150000, -1, 10],
['Barbados', 277264, 6000, -1, 19],
['Belarus', 10330000, 422000, -1, 23],
['Belgium', 10280000, 4870000, 1600000, 61],
['Belize', 266440, 18000, -1, 2],
['Benin', 7040000, 25000, -1, 4],
['Bhutan', 2130000, 2500, -1, -1],
['Bolivia', 8580000, 78000, -1, 9],
['Bosnia_and_Herzegovian', 3980000, 45000, -1, 3],
['Botswana', 1570000, 33000, -1, 11],
['Brazil', 182030000, 22320000, 10860000, 50],
['Brunei', 358098, 35000, -1, 2],
['Bulgaria', 7530000, 1610000, -1, 200],
['Burkina_Faso', 13220000, 25000, -1, 1],
['Burma', 42510000, 10000, -1, 1],
['Burundi', 6090000, 6000, -1, 1],
['Cambodia', 13120000, 10000, -1, 2],
['Cameroon', 15740000, 45000, -1, 1],
['Canada', 32200000, 20450000, 8800000, 760],
['Cape_Verde', 412137, 12000, -1, 1],
['Cayman_Islands', 41934, -1, -1, 16],
['Central_African_Republic', 3680000, 2000, -1, 1],
['Chad', 9250000, 4000, -1, 1],
['Chile', 15660000, 5040000, -1, 7],
['China', 1280000000, 99800000, -1, 3],
['Colombia', 41660000, 1870000, -1, 18],
['Comoros', 632948, 2500, -1, 1],
['Republic_of_the_Congo_Democratic', 56620000, 6000, -1, 1],
['Congo_Republic', 2950000, 500, -1, 1],
['Cook_Islands', 21008, -1, -1, 3],
['Costa_Rica', 3890000, 384000, -1, 3],
['Cote_d_Ivoire', 16960000, 70000, -1, 5],
['Croatia', 4420000, 480000, -1, 9],
['Cuba', 11260000, 120000, -1, 5],
['Cyprus', 771657, 150000, -1, 6],
['Czech_Republic', 10240000, 3530000, -1, 300],
['Denmark', 5380000, 3720000, -1, 13],
['Djibouti', 457130, 3300, -1, 1],
['Dominica', 69655, 2000, -1, 16],
['Dominican_Republic', 8710000, 186000, -1, 24],
['East_Timor', 977853, -1, -1, -1],
['Ecuador', 13710000, 328000, -1, 31],
['Egypt', 74710000, 2420000, -1, 50],
['El_Salvador', 6470000, 40000, -1, 4],
['Equatorial_Guinea', 510473, 900, -1, 1],
['Eritrea', 4360000, 10000, -1, 5],
['Estonia', 1400000, 620000, -1, 38],
['Ethiopia', 66550000, 20000, -1, 1],
['Faroe_Islands', 46345, 3000, -1, 2],
['Fiji', 856300, 15000, -1, 2],
['Finland', 5190000, 3270000, -1, 3],
['France', 60180000, 25470000, 15530000, 62],
['French_Guiana', 182917, 2000, -1, 2],
['French_Polynesia', 262125, 16000, -1, 2],
['Gabon', 1320000, 18000, -1, 1],
['Gambia', 1500000, 5000, -1, 2],
['Georgia', 4930000, 25000, -1, 6],
['Germany', 82390000, 41880000, 29520000, 200],
['Ghana', 20460000, 200000, -1, 12],
['Gilbraltar', 27776, -1, -1, 2],
['Greece', 10660000, 2710000, -1, 27],
['Greenland', 56385, 20000, -1, 1],
['Grenada', 89258, 5200, -1, 14],
['Guadeloupe', 440189, 4000, -1, 3],
['Guam', 163941, 5000, -1, 20],
['Guatemala', 13900000, 200000, -1, 5],
['Guernsey', 64818, -1, -1, -1],
['Guinea', 9030000, 15000, -1, 4],
['Guinea-Bissau', 1360000, 4000, -1, 2],
['Guyana', 702100, 95000, -1, 3],
['Haiti', 7520000, 30000, -1, 3],
['Honduras', 6660000, 40000, -1, 8],
['Hong_Kong', 7390000, 4580000, 2630000, 17],
['Hungary', 10040000, 2940000, -1, 16],
['Iceland', 200000, 198000, -1, 20],
['India', 1040000000, 36970000, -1, 43],
['Indonesia', 234890000, 12860000, -1, 24],
['Iran', 68270000, 420000, -1, 8],
['Iraq', 24680000, 12500, -1, 1],
['Ireland', 3920000, 1810000, -1, 22],
['Islas_Malvinas_(Falkland_Islands)', 2967, -1, -1, 2],
['Isle_of_Man', 74261, -1, -1, -1],
['Israel', 6110000, 3130000, 976000, 21],
['Italy', 57990000, 25530000, 15700000, 93],
['Jamaica', 2690000, 100000, -1, 21],
['Japan', 127210000, 78050000, 36580000, 73],
['Jersey', 90156, -1, -1, -1],
['Jordan', 5460000, 212000, -1, 5],
['Kazakhstan', 16760000, 100000, -1, 10],
['Kenya', 31630000, 500000, -1, 65],
['Kiribati', 98549, 1000, -1, 1],
['Kuwait', 2180000, 200000, -1, 3],
['Kyrgyzstan', 4890000, 51600, -1, -1],
['Laos', 5920000, 10000, -1, 1],
['Latvia', 2340000, 455000, -1, 41],
['Lebanon', 3720000, 300000, -1, 22],
['Lesotho', 1860000, 5000, -1, 1],
['Liberia', 3310000, 500, -1, 2],
['Libya', 5490000, 20000, -1, 1],
['Liechtenstein', 3314, -1, -1, -1],
['Lithuania', 3590000, 480000, -1, 32],
['Luxembourg', 454157, 100000, -1, 8],
['Macau', 469903, 101000, -1, 1],
['Macedonia', 2060000, 100000, -1, 6],
['Madagascar', 16970000, 35000, -1, 2],
['Malawi', 11650000, 35000, -1, 7],
['Malaysia', 23090000, 10040000, -1, 7],
['Maldives', 329684, 6000, -1, 1],
['Mali', 11620000, 30000, -1, 13],
['Malta', 400420, 59000, -1, 6],
['Marshall_Islands', 56429, 900, -1, 1],
['Martinique', 425966, 5000, -1, 2],
['Mauritania', 2910000, 7500, -1, 5],
['Mauritius', 1210000, 158000, -1, 2],
['Mexico', 104900000, 13880000, -1, 51],
['Micronesia', 108143, 2000, -1, 1],
['Moldova', 4430000, 15000, -1, 2],
['Monaco', 32130, -1, -1, 2],
['Mongolia', 2710000, 40000, -1, 5],
['Montserrat', 8995, -1, -1, 17],
['Morocco', 31680000, 400000, -1, 8],
['Mozambique', 17470000, 22500, -1, 11],
['Namibia', 1920000, 45000, -1, 2],
['Nauru', 12570, -1, -1, 1],
['Nepal', 26460000, 60000, -1, 6],
['Netherlands_Antilles', 216226, 2000, -1, 6],
['New_Caledonia', 210798, 24000, -1, 1],
['New_Zealand', 3950000, 2340000, -1, 36],
['Nicaragua', 5120000, 20000, -1, 3],
['Niger', 10050000, 12000, -1, 1],
['Nigeria', 133880000, 100000, -1, 11],
['Niue', 2145, -1, -1, 1],
['Norfolk_Island', 1853, -1, -1, 2],
['North_Korea', 22460000, -1, -1, 1],
['Northern_Mariana_Islar', 80006, -1, -1, 1],
['Norway', 4540000, 3030000, -1, 13],
['Oman', 2800000, 120000, -1, 1],
['Pakistan', 150690000, 1200000, -1, 30],
['Palau', 19717, -1, -1, 1],
['Panama', 2960000, 45000, -1, 6],
['Papua_New_Guinea', 5290000, 135000, -1, 3],
['Paraguay', 6030000, 20000, -1, 4],
['Peru', 28400000, 4570000, -1, 10],
['Philippines', 84610000, 5960000, -1, 33],
['Pitcairn_Islands', 47, -1, -1, -1],
['Poland', 38620000, 10400000, -1, 19],
['Portugal', 10100000, 6090000, -1, 16],
['Puerto_Rico', 3880000, 600000, -1, 76],
['Qatar', 817052, 75000, -1, 1],
['Reunion', 755171, 10000, -1, 1],
['Romania', 22270000, 4940000, -1, 38],
['Russia', 144520000, 21230000, -1, 35],
['Rwanda', 7810000, 20000, -1, 2],
['Samoa', 178173, 3000, -1, 2],
['San_Marino', 28119, -1, -1, 2],
['Sao_Tome_and_Principe', 175883, 9000, -1, 2],
['Saudi_Arabia', 24290000, 2540000, -1, 42],
['Senegal', 10580000, 100000, -1, 1],
['Seychelles', 80469, 9000, -1, 1],
['Sierra_Leone', 5730000, 20000, -1, 1],
['Singapore', 4600000, 2750000, 956000, 9],
['Slovakia', 5430000, 1610000, -1, 6],
['Slovenia', 1930000, 930000, -1, 11],
['Solomon_Islands', 509190, 8400, -1, 1],
['Somalia', 8020000, 200, -1, 3],
['South_Africa', 43600000, 4780000, -1, 150],
['South_Korea', 42760000, 31670000, -1, 11],
['Spain', 40210000, 13440000, 8210000, 56],
['Sri_Lanka', 19740000, 121500, -1, 5],
['St._Kitts_and_Nevis', 38763, 2000, -1, 16],
['St._Lucia', 162157, 3000, -1, 15],
['St._Vincent_and_the_Grenadines', 116812, 3500, -1, 15],
['Sudan', 38110000, 56000, -1, 2],
['Suriname', 435449, 14500, -1, 2],
['Svalbard', 2811, -1, -1, -1],
['Swaziland', 1160000, 14000, -1, 6],
['Sweden', 8870000, 6120000, 4640000, 29],
['Switzerland', 7310000, 4600000, 3310000, 44],
['Syria', 17580000, 60000, -1, 1],
['Taiwan', 22600000, 9520000, 5000000, 8],
['Tajilistan', 6860000, 5000, -1, 4],
['Tanzania', 35920000, 300000, -1, 6],
['Thailand', 64260000, 7570000, -1, 15],
['The_Bahamas', 297477, 16900, -1, 19],
['The_Netherlands', 16149999, 9790000, 7780000, 52],
['Togo', 5420000, 50000, -1, 3],
['Tokelau', 1418, -1, -1, 1],
['Tonga', 108141, 1000, -1, 2],
['Trinidad_and_Tobago', 1100000, 120000, -1, 17],
['Tunisia', 9920000, 400000, -1, 1],
['Turkey', 68100000, 7270000, -1, 50],
['Turkmenistan', 4770000, 2000, -1, -1],
['Turks_and_Caicos', 19350, -1, -1, 14],
['Tuvalu', 11305, -1, -1, 1],
['Uganda', 25630000, 60000, -1, 2],
['Ukraine', 48050000, 5278100, -1, 260],
['United_Arab_Emirates', 2480000, 900000, -1, 1],
['United_Kingdom', 60090000, 33110000, 22550000, 400],
['United_States', 290340000, 185550000, 139520000, 7000],
['Uruguay', 3410000, 600000, -1, 14],
['Uzbekistan', 25980000, 100000, -1, 42],
['Vanuatu', 199414, 3000, -1, 1],
['Venezuela', 24650000, 2310000, -1, 16],
['Vietnam', 81620000, 400000, -1, 5],
['Virgin_Islands', 124778, 12000, -1, 50],
['Wallis_and_Futuna', 15734, -1, -1, 1],
['Western_Sahara', 261794, -1, -1, 1],
['Yemen', 19340000, 17000, -1, 1],
['Zambia', 10300000, 25000, -1, 5],
['Zimbabwe', 12570000, 100000, -1, 6]]
def listPrint(stats, title):
"""Prints each of the top ten lists, formatted
"""
#sorts by first variable
stats.sort()
#prints title, column names
print(title.upper())
#prints divider
print("-"*78)
print("%-3s %-30s %10s %10s %10s %10s" %
(" ", " ", " ", " ", "Active", " "))
print("%-3s %-30s %10s %10s %10s %10s" %
(" ", "Country", "Population",
"Users", "Users", "ISPs" ))
#prints divider
print("-"*78)
#prints top ten list
for i in range(10):
#picks last ten items
sort, c, p, users, aUsers, ISPs = stats[-(i + 1)]
#replaces underscore with space in name
c = c.replace("_", " ")
#prints, adding counter and removing sort
print("%-3d %-30s %10d %10d %10d %10d" %
(i + 1, c, p, users, aUsers, ISPs))
#prints divider
print("-"*78)
print("\n")
def population():
"""Creates a list sorted by population
"""
title = "Top Ten Countries by Population"
stats = []
#adds value to sort by to beginning of line
for c, p, users, aUsers, ISPs in statistics:
stats.append([p, c, p, users, aUsers, ISPs])
#gives new list to other function to print
listPrint(stats, title)
def users():
"""Creates a list sorted by users (added)
"""
title = "Top Ten Countries by Users"
stats = []
#adds users, active users together and adds
#them to start of line, skipping n/a
for c, p, users, aUsers, ISPs in statistics:
if users == -1: #if internet users n/a
stats.append([0, c, p, users, aUsers, ISPs])
elif aUsers == -1: #if active users n/a
stats.append([users, c, p, users, aUsers, ISPs])
else:
stats.append([users + aUsers, c, p, users,
aUsers, ISPs])
#gives new list to other function to print
listPrint(stats, title)
def ratio():
"""Creates a list sorted by ratio of
active users to population
"""
title = "Top Ten Countries by Ratio \
of Active Users to Population"
stats = []
#finds ratio of active users to population
#and adds them to start of line, skipping n/a
for c, p, users, aUsers, ISPs in statistics:
if aUsers == -1: #if active users n/a
stats.append([0, c, p, users, aUsers, ISPs])
else:
stats.append([aUsers/p, c, p, users,
aUsers, ISPs])
#gives new list to other function to print
listPrint(stats, title)
def overall():
"""Calculates and prints global
statistics
"""
print("GLOBAL STATISTICS:\n")
#variables to recieve statistics
totPop = 0
totUsers = 0
totAct = 0
totISP = 0
for c, p, users, aUsers, ISPs in statistics:
#adds population to total
totPop = totPop + p
#adds if not n/a
if users != -1:
totUsers = totUsers + users
if aUsers != -1:
totAct = totAct + aUsers
if ISPs != -1:
totISP = totISP + ISPs
#finds percentages
perAct = (totAct/totUsers)*100
perUse = (totUsers/totPop)*100
#print statistics
print("%-40s %10d" %
("Total world population:", totPop))
print("%-40s %10d" %
("Total internet users:", totUsers))
print("%-40s %10d" %
("Total active users:", totAct))
print("%-40s %10d" %
("Total number of ISPs:", totISP))
print("%-40s %10.2f%%" %
("Active internet users worldwide:",
perAct))
print("%-40s %10.2f%%" %
("Internet users worldwide:",
perUse))
def main():
"""Calls top ten functions
"""
population()
users()
ratio()
overall()
main()