""" Practice Test 2, problem 1. Authors: David Mutchler, Valerie Galluzzi, Mark Hays, Amanda Stouder, their colleagues and PUT_YOUR_NAME_HERE. October 2015. """ # TODO: 1. PUT YOUR NAME IN THE ABOVE LINE. import rosegraphics as rg import juggler_tests as jt def main(): """Calls the TEST functions in this module""" test_init() # test_move_circles() # test_draw_circles() # test_hand_off() # test_juggle() # test_line_up() # test_performance() # test_rainbow() # Uncomment after you finished all of your TODOs for a fun surprise :) # just_for_fun() class Juggler(object): def __init__(self, c_tuple): """ INPUTS: A tuple of rg.Circle objects. OUTPUT: None. SIDE EFFECTS: The instance variable self.circles is set to the given tuple of rg.Circle objects. DESCRIPTION: Initializes instance variables as needed in a new instance of the Juggler class. PRECONDITIONS: :type c_tuple: tuple(rg.Circle) """ def move_circles(self, dx, dy): """ INPUTS: integers dx and dy. OUTPUT: None. SIDE EFFECTS: For each circle in this Juggler's tuple of circles, moves the circle by dx and dy. """ def draw_circles(self, window): """ INPUTS: An rg.RoseWindow. OUTPUT: A number. See DESCRIPTION. SIDE EFFECTS: Draws, onto the given rg.RoseWindow, the circles in this Juggler's tuple of circles. See DESCRIPTION for details. DESCRIPTION: The first time that this method is called, it: 1. attaches each circle in this Juggler's tuple of circles to the given rg.RoseWindow, and then 2. does a render with a 0.5 second delay, as in: window.render(0.5) Subsequent calls to this method will do the same, except step 2 above (the rendering) is: -- Render with a 0.25 second delay if the previous rendering by this method was with a 0.5 second delay. -- Render with a 0.5 second delay otherwise. RETURNS the amount of the delay in the render that this call draw_circles did. That is, the number BLAH in this call's window.render(BLAH) PRECONDITIONS: :type window: rg.RoseWindow """ def hand_off(self, index, jester2): """ INPUTS: A nonnegative integer and a Juggler. OUTPUT: None. SIDE EFFECTS: The radius and color of a circle in the circles tuple of both Juggler objects is changed. See DESCRIPTION for details. DESCRIPTION: The hand_off method swaps the radius and color of the circle in the specified index of this Juggler's tuple of circles with the radius and color of the circle in the specified index of the given Juggler (jester2). This makes it look like the Jugglers swapped a ball. EXAMPLE: Suppose jester1 has a: -- YELLOW ball (i.e. circle) with radius 3 at position (0,0) at index 4 of jester1's tuple of circles. And suppose that jester2 has a: -- GREEN ball (i.e., circle) with radius 10 at position (5,5) at index 4 of jester2's tuple of circles. Then after calling jester1.hand_off(4, jester2) jester1's ball (circle) in index 4 of its tuple of circles should be GREEN with radius 10 but still at position (0,0), while jester2's ball (circle) in index 4 of its tuple of circles should be YELLOW with radius 3 but still at position (5,5). PRECONDITIONS: :type index: int :type jester2: Juggler and -- The given index is valid for this Juggler, that is, is at least 0 and less than the length of this Juggler's tuple of circles. -- The given index is valid for the given Juggler, that is, is at least 0 and less than the length of that Juggler's tuple of circles. """ def juggle(self): """ INPUTS: None OUTPUT: None SIDE EFFECTS: Each circle in this Juggler's tuple of circles changes its position. See DESCRIPTION. DESCRIPTION: The juggle method moves each circle in this Juggler's tuple of circles to the position of the next circle in the tuple. The last circle in the tuple is moved to the position the first circle in the tuple was in before it was moved by this method. EXAMPLE: Consider a Juggler instance jester1 and suppose that jester1's circle of tuples has the following 3 circles: -- The first circle is at position (1,1). -- The second circle is at position (2,2). -- The third circle is at position (3,3). After the execution of: jester1.juggle() jester1's tuple of circles should contain the same circles except now: -- The first circle is at position (2,2). -- The second circle is at position (3,3). -- The third circle is at position (1,1). """ def line_up(self, p1, p2): """ INPUTS: Two rg.Point instances that are far enough apart that all circles in this Juggler's tuple of circles can fall between them without overlap. OUTPUT: None SIDE EFFECTS: The circles in this Juggler's tuple of circles change position. See DESCRIPTION. DESCRIPTION: The line_up method takes two points and lines up the the circles in this Juggler's tuple of circles between those points. The first input point specifies where the center of the first circle in the tuple should be placed, and the second input point specifies where the center of the last circle in the tuple should be placed. The centers of all other circles in the tuple should be evenly distributed between the first and last circles in the order that they appear in the tuple. PRECONDITIONS: :type p1: rg.Point :type p2: rg.Point HINT: Test using a horizontal or vertical line first, then extend to any arbitrary line. """ def performance(self, seconds, window): """ INPUTS: A positive number and an rg.RoseWindow. OUTPUT: None. SIDE EFFECTS: An amazing juggling show. DESCRIPTION: The performance method juggles for the number of seconds specified by the input. Each time the circles are juggled they should be displayed, resulting in an amazing show of juggling prowess on the computer screen. PRECONDITIONS: :type seconds: (float, int) that is positive :type window: rg.RoseWindow """ def rainbow(self): """ INPUTS: None OUTPUT: None SIDE EFFECTS: Circles change color. See DESCRIPTION. DESCRIPTION: The rainbow method changes the color of all of the circles in this Juggler's tuple of circles to the next color in the rainbow, where the colors of the rainbow are ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']. If the colors of the circles have reached the end of the rainbow ('violet') by calls to this method, this method returns them to the first color ('red'). The first time that this method is called, it should change all the circles in this Juggler's circle of tuples to have the first color, 'red'. """ def make_test_circles(center_x=120, center_y=80, size=1, n=6): """ INPUTS: Two positive integers (for center_x and center_y), a positive float (for size), and a nonnegative integer n <= 7. All are optional. OUTPUT: A tuple of n rg.Circle objects. The set of circles is centered at the given x and y. The circles have various sizes, with size being a size multiplier. SIDE EFFECTS: None. PRECONDITIONS: :type center_x: int and is positive :type center_y: int and is positive :type size: (float, int) and is positive. :type n: int and is at least 1 and at most 7. """ # ------------------------------------------------------------------ # Students: There is NO NEED TO EDIT THIS FUNCTION. # -- If you wish, you can use this function to generate # tuples of circles that you can use for your testing. # -- See test_init for an example of how to use this function. # ------------------------------------------------------------------ offset = 0 if n % 2 == 0 else 15 c_A = rg.Circle(rg.Point(center_x - size * (offset + 60), center_y + size * 10), 10 * size) c_A.fill_color = 'yellow' c_B = rg.Circle(rg.Point(center_x - size * (offset + 40), center_y - size * 20), 9 * size) c_B.fill_color = 'red' c_C = rg.Circle(rg.Point(center_x - size * (offset + 15), center_y - size * 35), 15 * size) c_C.fill_color = 'blue' c_D = rg.Circle(rg.Point(center_x, center_y - size * 45), 11 * size) c_D.fill_color = 'deep pink' c_E = rg.Circle(rg.Point(center_x + size * (offset + 15), center_y - size * 35), 5 * size) c_E.fill_color = 'green' c_F = rg.Circle(rg.Point(center_x + size * (offset + 40), center_y - size * 20), 12 * size) c_F.fill_color = 'orange' c_G = rg.Circle(rg.Point(center_x + size * (offset + 60), center_y + size * 10), 8 * size) c_G.fill_color = 'purple' all_circles = [c_A, c_B, c_C, c_D, c_E, c_F, c_G] start = (len(all_circles) - n) // 2 middle = len(all_circles) // 2 end = (len(all_circles) + n + 1) // 2 if n % 2 == 1: return tuple(all_circles[start:end]) else: return tuple(all_circles[start:middle] + all_circles[middle + 1:end]) def more_tests(s): """ Runs more tests on the method whose name is the argument s. """ jt.more_tests(s) def test_init(): """ Tests the __init__ method of the Juggler class. """ # ------------------------------------------------------------------ # TODO: 2. # a. Read the specification of the __init__ method. # (The spec is in the Juggler class definition, above.) # b. Add ** 1 ** test to this TEST function for __init__. # c. Implement and test the __init__ method. # We have supplied MORE tests for you. # d. COMMIT your code and make main test only the next function. # ------------------------------------------------------------------ print() print('-----------------------------------------------------------') print('Testing the __init__ method of the Juggler class.') print('-----------------------------------------------------------') # ------------------------------------------------------------------ # An example of a test: # ------------------------------------------------------------------ # Make a tuple with make_test_circles. It has optional arguments. # Make a clone (copy) of it too, by calling make_test_circles again. circle_tuple = make_test_circles() tuple_clone = make_test_circles() # Make a Juggler. jester = Juggler(circle_tuple) # See if the Juggler has the right circle at index 2: index = 2 expected = tuple_clone[index] actual = jester.circles[index] print('Expected is: ', expected) print('Actual is: ', actual) # ------------------------------------------------------------------ # Add your additional test below here: # ------------------------------------------------------------------ # ------------------------------------------------------------------ # The following line runs more tests. Keep it here! # ------------------------------------------------------------------ more_tests('init') def test_move_circles(): """ Tests the move_circles method of the Juggler class. """ # ------------------------------------------------------------------ # TODO: 3. # a. Read the specification of the move_circles method. # (The spec is in the Juggler class definition, above.) # b. Add ** 1 ** test to this TEST function for move_circles. # c. Implement and test the move_circles method. # We have supplied MORE tests for you. # d. COMMIT your code and make main test only the next function. # ------------------------------------------------------------------ print() print('-----------------------------------------------------------') print('Testing the move_circles method of the Juggler class.') print('-----------------------------------------------------------') # ------------------------------------------------------------------ # Add your additional test below here: # ------------------------------------------------------------------ # ------------------------------------------------------------------ # The following line runs more tests. Keep it here! # ------------------------------------------------------------------ more_tests('move_circles') def test_draw_circles(): """ Tests the draw_circles method of the Juggler class. """ # ------------------------------------------------------------------ # TODO: 4. # a. Read the specification of the draw_circles method. # (The spec is in the Juggler class definition, above.) # b. Add ** 1 ** test to this TEST function for draw_circles. # c. Implement and test the draw_circles method. # We have supplied MORE tests for you. # d. COMMIT your code and make main test only the next function. # ------------------------------------------------------------------ print() print('-----------------------------------------------------------') print('Testing the draw_circles method of the Juggler class.') print('-----------------------------------------------------------') # ------------------------------------------------------------------ # Add your additional test below here: # ------------------------------------------------------------------ # ------------------------------------------------------------------ # The following line runs more tests. Keep it here! # ------------------------------------------------------------------ more_tests('draw_circles') def test_hand_off(): """ Tests the hand_off method of the Juggler class. """ # ------------------------------------------------------------------ # TODO: 5. # a. Read the specification of the hand_off method. # (The spec is in the Juggler class definition, above.) # b. Add ** 1 ** test to this TEST function for hand_off. # c. Implement and test the hand_off method. # We have supplied MORE tests for you. # d. COMMIT your code and make main test only the next function. # ------------------------------------------------------------------ print() print('-----------------------------------------------------------') print('Testing the hand_off method of the Juggler class.') print('-----------------------------------------------------------') # ------------------------------------------------------------------ # Add your additional test below here: # ------------------------------------------------------------------ # ------------------------------------------------------------------ # The following line runs more tests. Keep it here! # ------------------------------------------------------------------ more_tests('hand_off') def test_juggle(): """ Tests the juggle method of the Juggler class. """ # ------------------------------------------------------------------ # TODO: 6. # a. Read the specification of the juggle method. # (The spec is in the Juggler class definition, above.) # b. Add ** 1 ** test to this TEST function for hand_off. # c. Implement and test the juggle method. # We have supplied MORE tests for you. # d. COMMIT your code and make main test only the next function. # ------------------------------------------------------------------ print() print('-----------------------------------------------------------') print('Testing the juggle method of the Juggler class.') print('-----------------------------------------------------------') # ------------------------------------------------------------------ # Add your additional test below here: # ------------------------------------------------------------------ # ------------------------------------------------------------------ # The following line runs more tests. Keep it here! # ------------------------------------------------------------------ more_tests('juggle') def test_line_up(): """ Tests the line_up method of the Juggler class. """ # ------------------------------------------------------------------ # TODO: 7. # a. Read the specification of the line_up method. # (The spec is in the Juggler class definition, above.) # b. Add ** 1 ** test to this TEST function for line_up. # c. Implement and test the line_up method. # We have supplied MORE tests for you. # d. COMMIT your code and make main test only the next function. # # NOTE: When you read the specification for the line_up method, # you will see that the only side effect listed is that the # Juggler's circles change position. That means that the # points given as input should not be changed. # Does your method fulfill that test? # Un-comment the commented-out test below to find out. # ------------------------------------------------------------------ print() print('-----------------------------------------------------------') print('Testing the line_up method of the Juggler class.') print('-----------------------------------------------------------') # Tests whether the line_up method leaves the input points unmodified: # p1 = rg.Point(30, 30) # p2 = rg.Point(300, 30) # expected1 = p1.clone() # expected2 = p2.clone() # jester = Juggler(make_test_circles()) # jester.line_up(p1, p2) # print ("Expected and actual are:", expected1, p1) # print ("Expected and actual are:", expected2, p2) # ------------------------------------------------------------------ # Add your additional test below here: # ------------------------------------------------------------------ # ------------------------------------------------------------------ # The following line runs more tests. Keep it here! # ------------------------------------------------------------------ more_tests('line_up') def test_performance(): """ Tests the performance method of the Juggler class. """ # ------------------------------------------------------------------ # TODO: 8. # a. Read the specification of the performance method. # (The spec is in the Juggler class definition, above.) # b. Add ** 1 ** test to this TEST function for performance. # c. Implement and test the performance method. # We have supplied MORE tests for you. # d. COMMIT your code and make main test only the next function. # ------------------------------------------------------------------ print() print('-----------------------------------------------------------') print('Testing the performance method of the Juggler class.') print('-----------------------------------------------------------') # ------------------------------------------------------------------ # Add your additional test below here: # ------------------------------------------------------------------ # ------------------------------------------------------------------ # The following line runs more tests. Keep it here! # ------------------------------------------------------------------ more_tests('performance') def test_rainbow(): """ Tests the rainbow method of the Juggler class. """ # ------------------------------------------------------------------ # TODO: 9. # a. Read the specification of the rainbow method. # (The spec is in the Juggler class definition, above.) # b. Add ** 1 ** test to this TEST function for rainbow. # c. Implement and test the rainbow method. # We have supplied MORE tests for you. # d. COMMIT your code and make main test only the next function. # ------------------------------------------------------------------ print() print('-----------------------------------------------------------') print('Testing the rainbow method of the Juggler class.') print('-----------------------------------------------------------') # ------------------------------------------------------------------ # Add your additional test below here: # ------------------------------------------------------------------ # ------------------------------------------------------------------ # The following line runs more tests. Keep it here! # ------------------------------------------------------------------ more_tests('rainbow') def just_for_fun(): # No need to understand this code or look through it--just run for fun # once you have implemented everything else :) window = rg.RoseWindow(750, 500) stands = rg.Rectangle(rg.Point(0, 0), rg.Point(750, 350)) stands.fill_color = 'brown' stands.attach_to(window) stage = rg.Rectangle(rg.Point(0, 350), rg.Point(750, 500)) stage.fill_color = 'Deepskyblue1' stage.attach_to(window) x = 0 y = 0 for _ in range(200): y = 10 + 30 * (x // 725) x = 10 + (x + 30) audience = rg.Circle(rg.Point(x % 725, y), 15) audience.fill_color = "gray" audience.attach_to(window) window.render(.1) j1 = rg.Circle(rg.Point(200, 400), 20) j1.fill_color = 'black' j1.attach_to(window) j2 = rg.Circle(rg.Point(550, 400), 20) j2.fill_color = 'black' j2.attach_to(window) window.render() j1_circles = make_test_circles(j1.center.x, j1.center.y, 1) j2_circles = make_test_circles(j2.center.x, j2.center.y, 1) for i in range(len(j1_circles)): j1_circles[i].radius = 8 + (2 * (i % 2)) j2_circles[i].radius = 8 + (2 * (i % 2)) jester1 = Juggler(j1_circles) jester2 = Juggler(j2_circles) jester1.rainbow() jester2.rainbow() jester1.draw_circles(window) jester2.draw_circles(window) for i in range(len(jester1.circles) - 1): jester2.rainbow() jester1.juggle() jester1.hand_off(i, jester2) jester1.draw_circles(window) jester2.rainbow() for _ in range(30): jester1.juggle() jester1.draw_circles(window) jester1.line_up(rg.Point(200, 350), rg.Point(200, 200)) jester2.line_up(rg.Point(550, 350), rg.Point(550, 200)) jester1.performance(2, window) jester2.performance(2, window) j1.radius = 10 j2.radius = 10 window.render(.5) j1.radius = 20 j2.radius = 20 window.render(.1) window.close_on_mouse_click() # ---------------------------------------------------------------------- # If this module is running at the top level (as opposed to being # imported by another module), then call the 'main' function. # ---------------------------------------------------------------------- if __name__ == '__main__': main()