CSC111 Homework 6 Solution Programs 2011

From dftwiki3
Revision as of 15:44, 7 November 2011 by Thiebaut (talk | contribs) (Program 1)
Jump to: navigation, search

--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()