As with the previous and future tasks, there are two components to this task.
To reiterate, both the Problem Set and Game Features - Learning Objective portions of this document MUST be completed to achieve the Learning Objective points and pass the course. The Game Features - Comprehensive Understanding is not needed for the Learning Objective requirement, but completing/not completing it will directly impact your grade through CU points. Each Problem Set will carry 20 LO points, while each Game Engine Task will carry 30 LO points and 50 CU points.
You should complete the components below in the order they are listed; you will not be able to earn credit for the following component(s) until you complete the previous ones with all available points.
Coding Task 1 assesses Unit Testing and Classes. Both the Problem Set and Game Engine Task will focus on these topics.
    The content of the Learning Objective is primarily used in the Game Engine by the sample game. To play the sample
    game, during and after completing this Learning Objective, navigate to the class app.Configuration and
    change GAME to "sample game".
As with the previous task, one of our TAs has prepared a video which covers the requirements for this task. Again, this content is optional, but we strongly recommend watching the video to get started, especially if you're struggling with the game features. The video can be found at https://www.youtube.com/watch?v=XVykxZlLLHM.
Problem Set GitHub Repository link: https://github.com/CSE-116/ProblemSet-1
Once you have the project opened in IntelliJ, you'll see a src folder containing 2 Java packages named problem and tests.
    To submit your project, run problem.Zipper, which will create a zip file containing the problem set,
    and submit it to Autolab.
You should read through all the following sections before you begin to implement the methods from the specification. Note that you will not receive feedback on the correctness of these methods until you've completed the testing component of this task (see the "Autolab Feedback" section for more details). However, you must at least create every class/method from this specification to receive feedback. You can "stub out" these methods by having them always return a fixed value, but they must exist so the grading code, and your tests, can compile and run.
For this Problem Set, you will implement the following functionality. Note that all of the methods are non-static.
Location: Create a class in the problem package named Location. This
        class will represent a 2-dimensional point representing the location of a shape. This class should implement the
        following methods:
        doubles representing the x and y
                location, respectively.
            getX: create a method named getX which takes no arguments and returns a
                double. This method should return the x location.
            getY: create a method named getY which takes no arguments and returns a
                double. This method should return the y location.
            setX: create a method named setX which takes a single double and
                returns void. This method should set the x component of the location to the input amount.
            setY: create a method named setY which takes a single double and
                returns void. This method should set the y component of the location to the input amount.
            Circle: Create a class in the problem package named Circle. This class
        will represent a circle based on a 2-dimensional location and a radius. This class should implement the
        following methods:
        Location object and a
                double, in that order. These represent the location of the circle and its radius.
            getRadius: create a method named getRadius which takes no arguments and
                returns a double. This method should return the radius of the circle.
            setRadius: create a method named setRadius which takes a single
                double and returns void. This method should set the radius of the circle to
                the input value.
            getLocation: create a method named getLocation which takes no arguments and
                returns a (reference to a) Location object. This method should return the location of the
                circle.
            setLocation: create a method named setLocation which takes a single (reference
                to a) Location object and returns void. This method should set the location of
                the circle to the input value.
            getArea: create a method named getArea which takes no arguments and returns a
                double. This method should calculate and return the area of the circle.
            πr2, where
                    r is the radius of the circle.
                Math.PI as the value of π. Nothing needs to be imported to do so.
                CircleEngine: Create a class in the problem package named CircleEngine.
        This class will contain methods for using and manipulating Circles. This class should implement the
        following methods:
        detectCollision: create a method named detectCollision which takes two
                (references to) Circle objects and returns a boolean. It will return true if the circles
                are overlapping and false otherwise.
                √((x1-x2)2 + (y1-y2)2).
                    doubleRadius: create a method named doubleRadius which takes an
                ArrayList of Circles and returns void. This method should iterate
                over the input list and double the radius of each circle, using the appropriate setter.
            
    Write JUnit tests for the following methods from the specification in the tests.TestProblemSet1 class.
    These tests should be annotated with @Test.
Location
        Location object.
            Circle
        Circle object.
            getArea method, asserting that the calculating is correcly performed on
                circles of varying radii.
            CircleEngine
        TestProblemSet1 class. They are likely commented out, and must be uncommented for you to
                use
                them. You can uncomment multiple lines by selecting the lines and pressing ctrl+/ (command+/ on mac).
                You
                are encouraged to use these tests to help you write the methods they are testing.
            Implement the methods from the specification. You may wish to complete the Testing Requirements before you begin implementation, and it's suggested that you run these tests as you implement the methods.
Feedback from Autolab will be given in several phases. If you don't complete a phase, then feedback for the following phase(s) will not be given. You must complete all phases to earn the required score of 20 LOs. For the problem set, the phases will be as follows:
Once you have successfully completed all three phases, you will have completed this Problem Set and Autolab will confirm this with a score of 20 LOs.
You will continue to build functionality for the Game Engine in this component of the task. This will be done on top of the code written for the previous task; you should not reclone or remove said code for this task or any future Game Features components.
As with the previous task, there are two parts to the Game Features component: the Learning Objective and Comprehensive Understanding. The Learning Objective portion must be completed with a score of 30 LOs before the Comprehensive Understanding unlocks. Both portions of the Game Features will be submitted to the same assignment on Autolab.
For this Learning Objective portion, you will be writing code in the following classes which already exist:
PhysicsEngine, located in the app.gameengine.model.physics package.
    Wall, located in the app.games.commonobjects package.
    TestTask1, located in the app.tests package.
    
    If you do not have the TestTask1 class in your app.tests package, you should create it. We
    have provided some tests for the Wall class for you, which can be accessed at this link:
    TestTask1.java.
    If you already have the TestTask1 class, you already have these tests and do not need to add them to
    the file.
    Additionally, in the app.tests package, create a new class called TestUtils.
In this task, you will continue to add feature to the game engine project that you started in the previous task.
The coordinate system use for computer graphics might be different than you're used to. We'll use the standard coordinate system that is typically used in video games (and anything involving rendering to a screen).
The origin of the system is at the top-left of the screen/window/level with positive x going right and positive y going down. This image shows the same information as the one above, but with the coordinate system labeling all the tiles in the game. You can see that "G" (The goal) is at location (6, 2).
    Each object within the game has several important properties to consider, namely a location and a hitbox, which has its own location and dimensions. These quantities are each represented as 2-dimensional vectors (x, y). All objects and hitboxes are rectangles, and their location is the location of their upper left corner. Their dimensions are the width and height of the rectangle. For example, the goal (G on the grid above) has a location of (6, 2), since that's the location of its upper-left corner, and it has dimensions (1, 1) since it's exactly 1 tile in size. Locations and dimensions do not have to be whole numbers.
Object locations and dimensions also do not necessarily have to be aligned with the visuals of that object. In the image above, the green dot represents the location of that object, the blue outline represents the size of the sprite image that is being rendered for that object, and the red outline represents the size of its hitbox. Having a hitbox smaller than the graphical sprite allows for more precise physics and collision, but means that extra care has to be taken when dealing with those properties. Pressing F4 in game shows overlays of each object's hitbox, which can be helpful for debugging.
You should read through all the following sections before you begin to implement the methods from the specification. Note that you will not receive feedback on the correctness of these methods until you've completed the testing component of this task (see the "Autolab Feedback" section for more details). However, you must at least create every class/method from this specification to receive feedback. You can "stub out" these methods by having them always return a fixed value, but they must exist so the grading code, and your tests, can compile and run.
For the Learning Objective portion of the Game Features component for this task, you will implement the following functionality:
    Note: It is suggested that you follow this specification in order for your implementation. However, you may
        find it easier to complete the detectCollision method before the getOverlap
        method.
    
PhysicsEngine class:
        updateObject
                updateObject method. This method should update the location of
                        the DynamicGameObject based on the velocity and amount of elapsed time.
                    DynamicGameObject class to
                        achieve this functionality, namely getVelocity, getLocation, and
                        setLocation. These methods are already provided for you.
                    getX and getY methods on the
                        Vector2D object returned by getVelocity.
                    getOverlap
                getOverlap method. This method should return a
                        double representing the minimum overlapping distance of the two
                        Hitbox objects from the parameters.
                    Wall.collideWithDynamicObject method, so referring to those
                        descriptions and images may be helpful.
                    Hitbox, note the following:
                        Hitbox using the getLocation method, which returns a
                                Vector2D
                                containing the x and y coordinate of said location.
                            Hitbox using the
                                getDimensions method, which returns a Vector2D containing the
                                width (in the x-component) and height (in the y-component) of the Hitbox.
                            Hitbox
                        objects. This means you must calculate the amount the two hitboxes are overlapping in both the x
                        and y direction, then return the smaller of the two.
                    
                        getOverlap
                        on these Walls' hitboxes would return 0.25.
                    detectCollision
                detectCollision method. This method should return a
                        boolean
                        that is true if the two Hitboxes are colliding and false otherwise.
                    getOverlap applies here as well. In the same
                        example, calling detectCollision on those two Walls would return true, as they are
                        colliding by 0.25 which is greater than 0.
                    Wall class:
        collideWithDynamicObject
                collideWithDynamicObject method. This method should adjust the
                        location of the DynamicGameObject passed in the parameter to ensure that they are
                        no longer overlapping, and zero the velocity in that direction.
                    
                        DynamicGameObject. All state in the Wall should stay the same.
                    PhysicsEngine.getOverlap method. Thus, you should calculate the overlap based on
                        the Wall's and DynamicGameObject's hitboxes, which can be obtained
                        with the getHitbox method. You should be able to reuse much of the same logic for
                        this method.
                    setLocation with
                        otherObject.getLocation().getX() - 0.5 rather than
                        otherObject.getHitbox().getLocation().getX() - 0.5. Note that this is only for the
                        position update, and you should still use the hitbox's position to calculate the amount to
                        move).
                    When working with more complex structures such as classes and data structures, it can be tedious to constantly compare two such instances as is often necessary in testing. Thus, the Learning Objective component will typically begin with writing a Testing Utility method relevant to the task. Writing this method is required to pass the Learning Objective, and it is strongly encouraged that you use this method in your testing.
    In the app.tests.TestUtils class, create a static method named
    comparePlayers
    that takes in (references to) two Players and returns void. This method should contain JUnit asserts
    that verify the two Players passed in have identical state, failing if they do not.
    Specifically, you must assert that the location and velocity vectors of both objects are equal. You should use the
    respective getters to access these instance variables. However, you will not find these getters in the
    Player class, rather they will be contained in the
    DynamicGameObject
    class in the app.gameengine.model.gameobjects package. This is because Player
    extends DynamicGameObject and thus has access to all of these methods. This is called
    inheritance, and more details on inheritance will come later in this course.
    Note that this method is not a test, and thus should not have the @Test annotation. Rather, this is a
    static method intended to be used in your testing.
    Write JUnit tests for the following methods from the specification in the TestTask1 class. These tests
    should be annotated with @Test:
PhysicsEngine
        updateObject
                Player objects, one whose location and
                        velocity you manually update, and one that is updated by the updateObject method.
                        This way, you can make use of the comparePlayers method.
                    detectCollision
                getOverlap
                getOverlap method. Tests are provided for you in the
                        TestTask1 class, which you may use to help you write the method itself.
                    Wall
        collideWithDynamicObject method. Tests are provided for you in
                the TestTask1 class, which you may use to help you write the method itself.
            Implement the methods from the specification. You may wish to complete the Testing Requirements before you begin implementation, and it's suggested that you run these tests as you implement the methods.
Feedback for the Learning Objective component of the Game Features will be given in several phases. If you don't complete a phase, then feedback for the following phase(s) will not be given. You must complete all the following phases to earn the required score of 30 LOs to complete this task. The phases for the Learning Objective are as follows:
Once you have successfully passed all four phases, you will have completed the Learning Objective component of the Game Features, and Autolab will confirm this with a score of 30 LOs.
    For the Comprehensive Understanding portion of this task, you will be implementing functionality in the
    SnakeLevel class (from the app.games.snake package) such that the Snake game is fully
    functional. You can access the Snake game by changing the GAME constant in
    app.Configuration to "Snake".
Each of the methods you implement will have an associated CU count that you will earn upon passing our tests for that method. Partially implemented methods may result in some partial credit being earned, depending on the method.
You don't need to understand all of the internal Snake code; however, you should expect to read and understand some of the internal Javadoc comments while completing this task. Not all background information will be provided in this document.
SnakeLevel class, implement the following methods:
wallOffBoundary (10 CUs)
        SnakeWall objects.
            SnakeWalls. Adding a
                SnakeWall
                to the level can be done by accessing and modifying the ArrayList containing the level's
                StaticGameObjects, just as it is done in the LevelParser class.
            spawnFood (10 CUs)
        SnakeFood should be added to the level's
                StaticGameObjects ArrayList, as well as the ArrayList named food in the
                SnakeLevel class.
            SnakeFood should be at a random tile-aligned coordinate, with the
                following restrictions:
                SnakeBody object from the tail
                        ArrayList is currently occupying.
                    SnakeFood object from the food
                        ArrayList is currently occupying.
                    Randomizer class from the app.gameengine.utils package.
                randomIntVector2D
                        method that takes in two parameters.
                    advanceLevel method on the Game object stored internally in this class (this
                object can be accessed with this.game) and return immediately, doing nothing else.
            lengthenSnake (10 CUs)
        SnakeBody objects will be added to the tail
                ArrayList, as well as the level's StaticGameObject ArrayList. The number of
                SnakeBodys to be added to the list will be dependent on the value of the
                lengthIncrease instance variable.
            SnakeBody object, the location of this object should be decided as follows:
                tail ArrayList is empty, the new SnakeBody object should be
                        positioned such that it is directly behind the head (which is returned by
                        this.getPlayer()). This can be determined by looking at the head's location and
                        orientation vectors.
                    tail ArrayList is not empty, the new SnakeBody object should be
                        positioned such that it shares the location with the first SnakeBody object in the
                        tail ArrayList (the object at index 0).
                    SnakeBody is added to the tail ArrayList in this
                method, it should be added to the front of the ArrayList (prepended) rather than the end. Recall that
                calling add() with only one parameter defaults to adding to the end of the list
                (appending).
            spawnSnake (10 CUs)
        SnakeBody objects to the level in the same manner as
                lengthenSnake, but the number to be added should be based off of the value of the
                startingLength instance variable instead. Note that you should add new
                SnakeBody objects to both the tail ArrayList and to the level's list of
                StaticGameObjects.
            startingLength is based off of the total length of the snake including the
                head, rather than just the length of the tail. Adding startingLength new
                SnakeBody elements will result in an incorrect length.
            tail ArrayList is empty initially when this method is
                called.
            update (10 CUs)
        processInput with a dt of 0 on the keyboardControls
                instance variable, to trigger any keyboard inputs since the last update.
            SnakeBody object at index 0 is now at the location that the
                SnakeBody object at index 1 previously occupied and so on. The SnakeBody at
                the last index of the tail ArrayList should have what was previously the location of the
                Player.
            setLocation on SnakeBody objects. However,
                    this will currently not have any effect. In order for it to take effect, you must remove a method
                    from the StaticGameObject class. This method is unnecessary, and its inclusion or
                    deletion should not affect any of your other coding tasks.
                app.gameengine.model.gameobjects.StaticGameObject class, and delete or
                    comment out the setLocation method within that class. This will allow you to freely
                    change the location of SnakeBody objects.
                SnakeBody object stays in place except for the
                last. If you choose, you can only modify the location of that final segment to the proper place directly
                behind the player.
            tail ArrayList, the Player's location should then be
                incremented by the Player's orientation. Remember that the Player can be accessed with
                this.getPlayer().
            tail contains
                SnakeBodys with locations [(0,0), (1, 0), (2, 0), (3, 0)], the Player's location would be
                set to (4, 1) and tail will contain SnakeBodys with locations [(1, 0), (2, 0),
                (3, 0), (4, 0)]. Repeating this (assuming orientation is unchanged) would result in the Player's
                location being set to (4, 2) and
                tail
                containing SnakeBodys with locations [(2, 0), (3, 0), (4, 0), (4, 1)].
            SnakeBody, ensure
                that added objects are added to the level's StaticGameObjects ArrayList as well as the
                tail ArrayList. Removed objects must be removed from the tail ArrayList and
                have the destroy() method called on them. This method can (and probably should) be
                implemented without adding or removing SnakeBody objects.
            The Comprehensive Understanding tests will unlock once you have earned 30 LOs on the assignment. These will be run in a single phase for correctness. For each test you successfully pass, you will earn a varying amount of CUs with a total maximum score of 50 CUs.
There is no required testing component for the Comprehensive Understanding; however, you are expected to test your code nonetheless as the Autolab feedback is unlikely to be sufficient for debugging.