CSci 150: Foundations of computer science I
Home Syllabus Assignments Tests

Ghost pirates program

[Assignment description]

from graphics import *
import time
import math

# Goes through all shapes in the hierarchy referenced by the first parameter,
# telling each shape to move dx in the x-direction and dy in the y-direction

def move_all(shapes, dx, dy):
    pass # replace this with your implementation

# Goes through all shapes in the hierarchy referenced by the first parameter,
# calling mark_as_hit for any circles that contain the parameter point

def check_hit(shapes, point):
    pass # replace this with your implementation

#
# do not modify anything below this point!
#

win_width = 600
win_height = 450
hits = {}
cur_ship = None

# Returns True if the parameter is a list.
def is_list(query):
    return type(query) == list

# Returns True if the first parameter is a circle and if the parameter point
# lies within the circle.

def is_circle_containing(query, point):
    if isinstance(query, Circle):
        dx = query.getCenter().getX() - point.getX()
        dy = query.getCenter().getY() - point.getY()
        return (dx * dx + dy * dy) ** 0.5 < query.getRadius()
    else:
        return False

# Colors the parameter shape green and updates an internal structure
# to remember it has been hit, so that later the ship will sink.

def mark_as_hit(shape):
    if shape not in hits[cur_ship]:
        shape.setFill('green')
        shape.setOutline('green')
        hits[cur_ship].append(shape)

def run():
    global cur_ship

    window = GraphWin('Ghost Pirates', win_width, win_height)
    ships = build_scene(window)
    frames = 0.0
    while not window.isClosed():
        click = window.checkMouse()
        if click is not None:
            for ship in ships:
                cur_ship = ship[0]
                check_hit(ship, click)
        move_ship(ships[0], 0.7, frames / 30 - 2, hits[ships[0][0]])
        move_ship(ships[1], 1.0, frames / 30 - 1, hits[ships[1][0]])
        move_ship(ships[2], 1.5, frames / 30, hits[ships[2][0]])
        frames += 1.0
        time.sleep(0.02)

def move_ship(ship, scale, phase, hits):
    if len(hits) >= 3:
        move_all(ship, 0.5 * scale, 0.3 * scale)
    else:
        move_all(ship, 0.5 * scale, scale * 0.15 * math.sin(phase))
        if ship[0].getPoints()[0].getX() > win_width:
            move_all(ship, -ship[0].getPoints()[1].getX(), 0)

def build_scene(win):
    win.setBackground(color_rgb(960200));

    moon = Circle(Point(550100), 50)
    moon.setFill('white')
    moon.setOutline('white')
    moon.draw(win)

    add_sea(win, 130)
    return [create_ship(win, 4001500.8, 'black'),
        create_ship(win, 1002001.0, color_rgb(80500)),
        create_ship(win, 2002701.5, color_rgb(200200200))]

def create_ship(win, x, y, factor, color):
    ship = [
        Polygon(Point(x, y), Point(x + 200 * factor, y),    # hull
            Point(x + 190 * factor, y + 30 * factor),
            Point(x + 10 * factor, y + 30 * factor)),
    ]
    color_and_draw(ship, win, color)
    sail = [
        Rectangle(Point(x + 97 * factor, y - 100 * factor), # mast
            Point(x + 103 * factor, y)),
        Line(Point(x + 70 * factor, y - 90 * factor),       # yard
            Point(x + 130 * factor, y - 100 * factor)),
        Polygon(Point(x + 70 * factor, y - 87 * factor),    # sail
            Point(x + 130 * factor, y - 97 * factor),
            Point(x + 130 * factor, y - 37 * factor),
            Point(x + 70 * factor, y - 27 * factor)),
    ]
    color_and_draw(sail, win, color)
    sail.append(create_pirate(win, x + 82 * factor, y - 92 * factor, factor, color))
    ship.append(sail)
    ship.append(create_pirate(win, x + 30 * factor, y, factor, color))
    ship.append(create_pirate(win, x + 190 * factor, y, factor, color))
    add_sea(win, y + 0.9 * 30 * factor)
    hits[ship[0]] = []
    return ship
    
def add_sea(win, y):
    sea = Rectangle(Point(0, y), Point(win_width, win_height))
    sea.setFill('blue')
    sea.setOutline('blue')
    sea.draw(win)

def create_pirate(win, x, y, factor, color):
    legs = [Line(Point(x - 3 * factor, y), Point(x, y - 8 * factor)),
        Line(Point(x + 3 * factor, y), Point(x, y - 8 * factor))]
    hat = [Rectangle(Point(x - 2 * factor, y - 24 * factor),  # crown
                Point(x + 2 * factor, y - 20 * factor)),
        Rectangle(Point(x - 4 * factor, y - 20 * factor),     # brim
                Point(x + 4 * factor, y - 19 * factor))]

    person = [
        Line(Point(x, y - 8 * factor), Point(x, y - 12 * factor)),  # body
        Line(Point(x - 4 * factor, y - 10 * factor),                # arms
            Point(x + 4 * factor, y - 10 * factor)),
        Circle(Point(x, y - 16 * factor), 4 * factor), # head
    ]
    color_and_draw(legs, win, color)
    color_and_draw(person, win, color)
    color_and_draw(hat, win, color)
    person.insert(0, legs)
    person.append(hat)
    return person

def color_and_draw(shapes, win, color):
    for shape in shapes:
        shape.setFill(color)
        shape.setOutline(color)
        shape.draw(win)

run()