"""
Created on Sep 30, 2022

@author: Robert Duvall

This module represents a template for making Turtle games.
"""
import random
import turtle


# Choose a name for your game to appear in the title bar of the game window
gameName = 'TO BE DETERMINED'
# Choose the size of your game window
screenWidth = 1000
screenHeight = 1000
# Choose how fast player moves
speedIncrement = 0.25
speedMax = 5
# NO NEED TO CHANGE - create the game window based on the choices above
theScreen = turtle.Screen()
theScreen.title(gameName)
theScreen.setup(screenWidth, screenHeight)
# move turtles as fast as possible
theScreen.tracer(False)


#
# Functions for interacting with the keyboard or mouse
# Since these are called by the turtle module (not you directly), you must accept these exact parameters (or none)
#
def move_up_on_key():
    theMover.dy = min(theMover.dy + speedIncrement, speedMax)
    theScreen.update()
    print(theMover.dx, theMover.dy)

def move_down_on_key():
    theMover.dy = max(theMover.dy - speedIncrement, -speedMax)
    theScreen.update()
    print(theMover.dx, theMover.dy)

def move_left_on_key():
    theMover.dx = max(theMover.dx - speedIncrement, -speedMax)
    theScreen.update()
    print(theMover.dx, theMover.dy)

def move_right_on_key():
    theMover.dx = min(theMover.dx + speedIncrement, speedMax)
    theScreen.update()
    print(theMover.dx, theMover.dy)

def reset_on_click(x, y):
    reset_mover(theMover, x, y)
    theScreen.update()


def setup_interaction(screen):
    """
    Sets up the keyboard and/or mouse interaction in the game

    Note, the function NAME is the parameter, not the result of calling it
    """
    # listen for interaction from user
    screen.listen()
    screen.onkeypress(move_up_on_key, 'w')
    screen.onkeypress(move_down_on_key, 's')
    screen.onkeypress(move_left_on_key, 'a')
    screen.onkeypress(move_right_on_key, 'd')
    screen.onclick(reset_on_click)


#
# Functions for drawing or positioning the game objects
#
def draw_scene():
    """
    Draw the game's setting and its objects.
    """
    theScreen.bgcolor('lightblue')

    draw_mover(theMover, 'orchid')
    draw_target(theTarget)

    reset_mover(theMover, 0, 0)
    reset_target(theTarget, 40, 40)


def draw_mover(yurtle, color):
    """
    Draw the interactive game object.
    """
    yurtle.speed(0)
    yurtle.shape('circle')
    yurtle.color(color)


def draw_target(yurtle):
    """
    Draw the game obstacle.
    """
    yurtle.speed(0)
    yurtle.penup()
    yurtle.shape('square')
    yurtle.shapesize(2)


def reset_mover(yurtle, x, y):
    """
    Reset player to given XY coordinate and randomize its velocity.
    """
    mover_goto(yurtle, x, y)
    yurtle.dx = random.randint(-2, 2)
    yurtle.dy = random.randint(-2, 2)


def reset_target(yurtle, width, height):
    """
    Reset the game obstacle to a random location and change to a random color.
    """
    yurtle.color(random.random(), random.random(), random.random())
    yurtle.goto(random.randint(-screenWidth // 2 + width // 2, screenWidth // 2 - width // 2),
                random.randint(-screenHeight // 2 + height // 2, screenHeight // 2 - height // 2))


#
# Helper functions to make the code more readable
#
def mover_goto(yurtle, x, y):
    """
    Wrap player to other side of the screen without leaving a trail.
    """
    yurtle.penup()
    yurtle.goto(x, y)
    yurtle.pendown()


def is_a_hit(yurtle1, yurtle2, width, height):
    """
    Return true if the given objects are close enough to intersect.
    """
    x1 = yurtle1.xcor()
    y1 = yurtle1.ycor()
    x2 = yurtle2.xcor()
    y2 = yurtle2.ycor()
    return (x1 - width // 2 < x2 < x1 + width // 2) and (y1 - height // 2 < y2 < y1 + height // 2)


#
# The main game "loop"
#
def game_step():
    """
    Handle game "rules" for every step (i.e., frame or "moment"):
     - movement: move the game objects each step
     - collisions: check if the game objects collided with each other or the sides and respond appropriately
    """
    gameIsOver = False

    # move game object based on its speed
    theMover.goto(theMover.xcor() + theMover.dx, theMover.ycor() + theMover.dy)

    # check if mover hits left or right side, wrap it to the other side
    if theMover.xcor() < -screenWidth // 2:
        mover_goto(theMover, screenWidth // 2, theMover.ycor())
    elif theMover.xcor() > screenWidth // 2:
        mover_goto(theMover, -screenWidth // 2, theMover.ycor())

    # check if mover hits top or bottom side, wrap it to the other side
    if theMover.ycor() < -screenHeight // 2:
        mover_goto(theMover, theMover.xcor(), screenHeight // 2)
    elif theMover.ycor() > screenHeight // 2:
        mover_goto(theMover, theMover.xcor(), -screenHeight // 2)

    # check if mover hits target, move target to new random location and "bounce" mover
    if is_a_hit(theMover, theTarget, 60, 60):
        reset_mover(theMover, theMover.xcor(), theMover.ycor())
        reset_target(theTarget, 40, 40)

    # NO NEED TO CHANGE - required to see the changes made to the turtles and keep the game running
    theScreen.update()
    if not gameIsOver:
        theScreen.ontimer(game_step, 10)


#
# Call the functions defined above
#

# Create the game objects
theMover = turtle.Turtle()
theTarget = turtle.Turtle()
# Draw the game objects
draw_scene()

# NO NEED TO CHANGE - typical code to get the game started
# Make the game interactive
setup_interaction(theScreen)
# Show the results
theScreen.update()
# Start game's mainloop
theScreen.ontimer(game_step, 10)
# Play the game forever
theScreen.mainloop()
