{"id":"object-interaction-review","slug":"end-of-part-5","title":"Putting it all together","text":"This module's tools often turn up together, even in a single class. Here they are side by side:\n\n| Tool | Example |\n| --- | --- |\n| An object as a parameter | `printer.print(document)` |\n| An object as an instance variable | `private Address address;` |\n| A parameter of the class's own type | `big.isHeavierThan(small)` |\n| Equal contents, not the same object | `mine.equals(yours)` |\n| List methods that use `equals` | `booked.contains(new Seat(\"B\", 7))` |\n| A method that returns a new object | `photo.rotated()` |\n\nA position on a grid of squares uses three of them. A position can make the position next to it, tell how many steps away another position is, and tell whether it's equal to another:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Position start = new Position(0, 0);\n        Position shop = new Position(3, -2);\n        Position next = start.moved(1, 0);\n        System.out.println(next);\n        System.out.println(start.stepsTo(shop));\n        System.out.println(next.moved(2, -2).equals(shop));\n        System.out.println(start);\n    }\n}\n// ==== Position.java ====\npublic class Position {\n    private int x;\n    private int y;\n\n    public Position(int x, int y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    public Position moved(int dx, int dy) {\n        return new Position(this.x + dx, this.y + dy);\n    }\n\n    public int stepsTo(Position other) {\n        return Math.abs(this.x - other.x) + Math.abs(this.y - other.y);\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Position)) {\n            return false;\n        }\n        Position other = (Position) compared;\n        return this.x == other.x && this.y == other.y;\n    }\n\n    public String toString() {\n        return \"(\" + this.x + \", \" + this.y + \")\";\n    }\n}\n```\n\n```output\n(1, 0)\n5\ntrue\n(0, 0)\n```\n\n- `moved` returns a new Position, so `start` stays at (0, 0), as the last line shows.\n- `stepsTo` takes another Position and reads its private `x` and `y`. It counts the steps from square to square along the rows and columns, without going diagonally: 3 steps across and 2 steps down make 5.\n- `next.moved(2, -2)` is a new object, never the one in `shop`, but its contents are the same, so `equals` says they're equal. With the `equals` every class gets, it would say false.\n\nThis step's challenges build on the class: a robot that moves around the grid, and a treasure hunt with a list of positions.\n\n### The end of part 5\n\nThis step ends the material of the MOOC's fifth part. Part 5 went deeper into object-oriented programming. You planned classes and gave methods and constructors several versions by overloading them. You saw that a variable of a primitive type, such as an `int`, holds its value, while a variable of a class type holds a reference to an object. Two variables can refer to the same object, and a reference can be `null`, which means no object at all. In this module, objects started working together: as parameters, as instance variables of other objects, compared with `equals`, found in lists and returned from methods. Next, part 6 puts lists inside objects. Part 5 closes with [the MOOC's conclusion page](https://java-programming.mooc.fi/part-5/5-conclusion) on its own site, for reading only.\n","task":"A robot moves on the grid, and `Position.java` is the class from above. `Robot.java` has the robot's name and position. Write two methods in it:\n\n- `move(String direction)` moves the robot one square: `up` adds 1 to y, `down` takes 1 from y, `right` adds 1 to x and `left` takes 1 from x. Any other direction does nothing. Use the position's `moved` method, and keep the new position it returns.\n- `isAt(Position place)` returns `true` when the robot is at that place. Compare the positions with `equals`.\n\nThe check runs:\n\n```java\nRobot robo = new Robot(\"Robo\", new Position(0, 0));\nrobo.move(\"up\");\nrobo.move(\"up\");\nrobo.move(\"right\");\nSystem.out.println(robo);\nSystem.out.println(robo.isAt(new Position(1, 2)));\nSystem.out.println(robo.isAt(new Position(2, 1)));\n```\n\nand expects:\n\n```\nRobo at (1, 2)\ntrue\nfalse\n```\n","kind":"code","seed":"// ==== Robot.java ====\npublic class Robot {\n    private String name;\n    private Position position;\n\n    public Robot(String name, Position start) {\n        this.name = name;\n        this.position = start;\n    }\n\n    // Write the methods move and isAt here.\n\n    public String toString() {\n        return this.name + \" at \" + this.position;\n    }\n}\n\n// ==== Position.java ====\npublic class Position {\n    private int x;\n    private int y;\n\n    public Position(int x, int y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    public Position moved(int dx, int dy) {\n        return new Position(this.x + dx, this.y + dy);\n    }\n\n    public int stepsTo(Position other) {\n        return Math.abs(this.x - other.x) + Math.abs(this.y - other.y);\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Position)) {\n            return false;\n        }\n        Position other = (Position) compared;\n        return this.x == other.x && this.y == other.y;\n    }\n\n    public String toString() {\n        return \"(\" + this.x + \", \" + this.y + \")\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Robot robo = new Robot(\"Robo\", new Position(0, 0));\n        robo.move(\"up\");\n        robo.move(\"up\");\n        robo.move(\"right\");\n        System.out.println(robo);\n        System.out.println(robo.isAt(new Position(1, 2)));\n        System.out.println(robo.isAt(new Position(2, 1)));\n    }\n}\n","solution":"// ==== Robot.java ====\npublic class Robot {\n    private String name;\n    private Position position;\n\n    public Robot(String name, Position start) {\n        this.name = name;\n        this.position = start;\n    }\n\n    public void move(String direction) {\n        if (direction.equals(\"up\")) {\n            this.position = this.position.moved(0, 1);\n        } else if (direction.equals(\"down\")) {\n            this.position = this.position.moved(0, -1);\n        } else if (direction.equals(\"right\")) {\n            this.position = this.position.moved(1, 0);\n        } else if (direction.equals(\"left\")) {\n            this.position = this.position.moved(-1, 0);\n        }\n    }\n\n    public boolean isAt(Position place) {\n        return this.position.equals(place);\n    }\n\n    public String toString() {\n        return this.name + \" at \" + this.position;\n    }\n}\n\n// ==== Position.java ====\npublic class Position {\n    private int x;\n    private int y;\n\n    public Position(int x, int y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    public Position moved(int dx, int dy) {\n        return new Position(this.x + dx, this.y + dy);\n    }\n\n    public int stepsTo(Position other) {\n        return Math.abs(this.x - other.x) + Math.abs(this.y - other.y);\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Position)) {\n            return false;\n        }\n        Position other = (Position) compared;\n        return this.x == other.x && this.y == other.y;\n    }\n\n    public String toString() {\n        return \"(\" + this.x + \", \" + this.y + \")\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Robot robo = new Robot(\"Robo\", new Position(0, 0));\n        robo.move(\"up\");\n        robo.move(\"up\");\n        robo.move(\"right\");\n        System.out.println(robo);\n        System.out.println(robo.isAt(new Position(1, 2)));\n        System.out.println(robo.isAt(new Position(2, 1)));\n    }\n}\n","hints":["`moved` doesn't change the position: it returns a new one. Keep it in the robot's instance variable: `this.position = this.position.moved(0, 1);` for `up`, and the same with other numbers for the other directions.","`isAt` compares the robot's position with the one it's given: `return this.position.equals(place);`. With `==` it would be false, because the check's `new Position(1, 2)` is a different object."],"tests":[{"name":"Test 1","stdin":"","call":"Robot robo = new Robot(\"Robo\", new Position(0, 0));\nrobo.move(\"up\");\nrobo.move(\"up\");\nrobo.move(\"right\");\nSystem.out.println(robo);\nSystem.out.println(robo.isAt(new Position(1, 2)));\nSystem.out.println(robo.isAt(new Position(2, 1)));\n","expect":"Robo at (1, 2)\ntrue\nfalse","hidden":false},{"name":"Test 2","stdin":"","call":"Position home = new Position(5, 5);\nRobot bolt = new Robot(\"Bolt\", home);\nbolt.move(\"left\");\nbolt.move(\"down\");\nbolt.move(\"down\");\nbolt.move(\"jump\");\nSystem.out.println(bolt);\nSystem.out.println(home);\nSystem.out.println(bolt.isAt(new Position(4, 3)) + \" \" + bolt.isAt(home));\n","expect":"Bolt at (4, 3)\n(5, 5)\ntrue false","hidden":true},{"name":"Test 3","stdin":"","call":"Robot rover = new Robot(\"Rover\", new Position(-1, 2));\nSystem.out.println(rover.isAt(new Position(-1, 2)));\nrover.move(\"right\");\nrover.move(\"left\");\nrover.move(\"left\");\nSystem.out.println(rover);\n","expect":"true\nRover at (-2, 2)","hidden":true}],"require":[{"pattern":"\\.moved\\s*\\(","message":"Move the robot with the position's `moved` method, and keep the Position it returns."},{"pattern":"\\bposition\\s*\\.\\s*equals\\s*\\(|\\.equals\\s*\\(\\s*(this\\s*\\.\\s*)?position\\s*\\)","message":"In `isAt`, compare the positions with `equals`."}],"forbid":[],"more":[{"task":"What does this program print? It uses the `Position` class from the lesson, and a list of the places visited so far.\n","kind":"predict","seed":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Position> visited = new ArrayList<>();\n        Position here = new Position(0, 0);\n        visited.add(here);\n        here = here.moved(1, 0);\n        visited.add(here);\n        here = here.moved(-1, 0);\n        System.out.println(here);\n        System.out.println(visited.contains(here));\n        System.out.println(here == visited.get(0));\n        System.out.println(visited.indexOf(new Position(1, 0)));\n    }\n}\n// ==== Position.java ====\npublic class Position {\n    private int x;\n    private int y;\n\n    public Position(int x, int y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    public Position moved(int dx, int dy) {\n        return new Position(this.x + dx, this.y + dy);\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Position)) {\n            return false;\n        }\n        Position other = (Position) compared;\n        return this.x == other.x && this.y == other.y;\n    }\n\n    public String toString() {\n        return \"(\" + this.x + \", \" + this.y + \")\";\n    }\n}\n","solution":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Position> visited = new ArrayList<>();\n        Position here = new Position(0, 0);\n        visited.add(here);\n        here = here.moved(1, 0);\n        visited.add(here);\n        here = here.moved(-1, 0);\n        System.out.println(here);\n        System.out.println(visited.contains(here));\n        System.out.println(here == visited.get(0));\n        System.out.println(visited.indexOf(new Position(1, 0)));\n    }\n}\n// ==== Position.java ====\npublic class Position {\n    private int x;\n    private int y;\n\n    public Position(int x, int y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    public Position moved(int dx, int dy) {\n        return new Position(this.x + dx, this.y + dy);\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Position)) {\n            return false;\n        }\n        Position other = (Position) compared;\n        return this.x == other.x && this.y == other.y;\n    }\n\n    public String toString() {\n        return \"(\" + this.x + \", \" + this.y + \")\";\n    }\n}\n","hints":["Each `moved` call makes a new Position, and `here` is set to refer to it. After moving right and back left, `here` is at (0, 0) again, but it's a third object, not the first one.","`contains` and `indexOf` use `equals`, so they find equal positions. `==` asks about the very same object."],"tests":[{"name":"Output","stdin":"","expect":"(0, 0)\ntrue\nfalse\n1","hidden":false}],"require":[],"forbid":[],"lines":["(0, 0)","true","false","1"]},{"task":"A treasure hunt. The list `treasures` in `Main.java` holds the positions of three hidden coins, and `Position.java` is the class from the lesson. The player starts at (0, 0). Read moves, `up`, `down`, `left` or `right`, one per line, until an empty line, and move the player one square each time, with `moved`. After each move, if a coin is at the new position, remove it from the list and print `Found a coin at ` and the position. At the end, print how many coins are left. Let `contains` and `remove` do the searching, without a loop over the list. For the input shown below, the program prints:\n\n```\nFound a coin at (1, 0)\nFound a coin at (2, 2)\nCoins left: 1\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Position> treasures = new ArrayList<>();\n        treasures.add(new Position(1, 0));\n        treasures.add(new Position(2, 2));\n        treasures.add(new Position(-1, 3));\n\n        Scanner scanner = new Scanner(System.in);\n        Position here = new Position(0, 0);\n\n    }\n}\n\n// ==== Position.java ====\npublic class Position {\n    private int x;\n    private int y;\n\n    public Position(int x, int y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    public Position moved(int dx, int dy) {\n        return new Position(this.x + dx, this.y + dy);\n    }\n\n    public int stepsTo(Position other) {\n        return Math.abs(this.x - other.x) + Math.abs(this.y - other.y);\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Position)) {\n            return false;\n        }\n        Position other = (Position) compared;\n        return this.x == other.x && this.y == other.y;\n    }\n\n    public String toString() {\n        return \"(\" + this.x + \", \" + this.y + \")\";\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Position> treasures = new ArrayList<>();\n        treasures.add(new Position(1, 0));\n        treasures.add(new Position(2, 2));\n        treasures.add(new Position(-1, 3));\n\n        Scanner scanner = new Scanner(System.in);\n        Position here = new Position(0, 0);\n        while (true) {\n            String move = scanner.nextLine();\n            if (move.isEmpty()) {\n                break;\n            }\n            if (move.equals(\"up\")) {\n                here = here.moved(0, 1);\n            } else if (move.equals(\"down\")) {\n                here = here.moved(0, -1);\n            } else if (move.equals(\"right\")) {\n                here = here.moved(1, 0);\n            } else if (move.equals(\"left\")) {\n                here = here.moved(-1, 0);\n            }\n            if (treasures.contains(here)) {\n                treasures.remove(here);\n                System.out.println(\"Found a coin at \" + here);\n            }\n        }\n        System.out.println(\"Coins left: \" + treasures.size());\n    }\n}\n\n// ==== Position.java ====\npublic class Position {\n    private int x;\n    private int y;\n\n    public Position(int x, int y) {\n        this.x = x;\n        this.y = y;\n    }\n\n    public Position moved(int dx, int dy) {\n        return new Position(this.x + dx, this.y + dy);\n    }\n\n    public int stepsTo(Position other) {\n        return Math.abs(this.x - other.x) + Math.abs(this.y - other.y);\n    }\n\n    public boolean equals(Object compared) {\n        if (this == compared) {\n            return true;\n        }\n        if (!(compared instanceof Position)) {\n            return false;\n        }\n        Position other = (Position) compared;\n        return this.x == other.x && this.y == other.y;\n    }\n\n    public String toString() {\n        return \"(\" + this.x + \", \" + this.y + \")\";\n    }\n}\n","hints":["In the loop, read a move and `break` at the empty line. Then move with, for example, `here = here.moved(1, 0);` for `right`: `moved` returns the new position, and `here` must be set to it.","After the move: `if (treasures.contains(here)) { treasures.remove(here); ... }`. The list's positions are other objects than `here`, but `equals` finds the equal one. At the end, `treasures.size()` is the number of coins left."],"tests":[{"name":"Test 1","stdin":"right\nup\nright\nup\nleft\n\n","expect":"Found a coin at (1, 0)\nFound a coin at (2, 2)\nCoins left: 1","hidden":false},{"name":"Test 2","stdin":"right\nleft\nright\n\n","expect":"Found a coin at (1, 0)\nCoins left: 2","hidden":true},{"name":"Test 3","stdin":"\n","expect":"Coins left: 3","hidden":true},{"name":"Test 4","stdin":"left\nup\nup\nup\ndown\nright\nright\nright\ndown\ndown\n\n","expect":"Found a coin at (-1, 3)\nFound a coin at (2, 2)\nCoins left: 1","hidden":true}],"require":[{"pattern":"\\.moved\\s*\\(","message":"Move the player with the position's `moved` method."},{"pattern":"\\.remove\\s*\\(","message":"Take a found coin out of the list with `remove`."}],"forbid":[{"pattern":"\\bfor\\s*\\(","message":"Let `contains` and `remove` find the coin, without a loop over the list."}]}]}