{"id":"asteroids-points","slug":"points-and-the-end","title":"Points, new jellyfish and the end of the dive","text":"The last step makes it a game: points for every jellyfish popped, new jellyfish drifting in from the surface, and a proper end when the submarine bumps into one.\n\n### The score in a Text\n\nA **Text** (from `javafx.scene.text`) is a shape that shows a line of text: `new Text(12, 24, \"Score: 0\")` puts it with its baseline starting at (12, 24), near the top left corner. Like the other shapes, it's filled black unless told otherwise, so on the dark sea it gets `setFill(Color.WHITE)`. `setText` changes what it says:\n\n```java\nText score = new Text(12, 24, \"Score: 0\");\nscore.setFill(Color.WHITE);\npane.getChildren().add(score);\n```\n\nThe points themselves are a field, `points`, which the timer's code can change (a local variable of `start` couldn't be changed there, which is why the MOOC's version uses an `AtomicInteger` instead). Each popped jellyfish is worth 10 points. One detail matters now: two bubbles can hit the same jellyfish in the same frame, and that jellyfish should count once. So a hit counts only when the bubble and the jellyfish are **both still alive**:\n\n```java\nif (b.isAlive() && j.isAlive() && b.collides(j)) {\n    b.setAlive(false);\n    j.setAlive(false);\n    points += 10;\n    score.setText(\"Score: \" + points);\n    System.out.println(\"Score: \" + points);\n}\n```\n\nIn the window as text, a Text's line is `Text \"Score: 20\" at (12, 24), fill #ffffff`.\n\n### New jellyfish\n\nA sea that only empties isn't much of a game. So in each frame, a new jellyfish appears with a small **chance**: `random.nextDouble()` is a double from 0.0 up to (not including) 1.0, and it's below 0.02 in about 2% of the frames, so a new jellyfish comes about every 50 frames, a little more than once a second at 60 frames a second. It starts at a random x on the top edge, heading in a random direction. But a jellyfish that appears right on the submarine would end the game unfairly, so it's added only if it doesn't collide with the submarine:\n\n```java\nif (random.nextDouble() < 0.02) {\n    Jellyfish newcomer = new Jellyfish(random.nextInt(WIDTH), 0, random.nextInt(360));\n    if (!newcomer.collides(sub)) {\n        jellyfish.add(newcomer);\n        pane.getChildren().add(newcomer.getShape());\n    }\n}\n```\n\nThe Random is the same seeded one that placed the first jellyfish, so this is the same on every run too. Note that `random.nextDouble()` is called in **every** frame: the numbers that come after it depend on how many frames ran.\n\n### Game over\n\nWhen the submarine bumps into a jellyfish, the game is over: the timer stops, the Text says `Game over! Score: 20`, and the keys do nothing any more. A field `over` remembers it, and the pressed handler returns at once when it's `true`, so Space can't fire bubbles from a sunken submarine.\n\n### The whole game\n\n```java\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.stream.Collectors;\nimport javafx.animation.AnimationTimer;\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.input.KeyCode;\nimport javafx.scene.layout.Pane;\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Rectangle;\nimport javafx.scene.text.Text;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    public static final int WIDTH = 360;\n    public static final int HEIGHT = 240;\n\n    private Map<KeyCode, Boolean> held = new HashMap<>();\n    private Random random = new Random(16);\n    private List<Jellyfish> jellyfish = new ArrayList<>();\n    private List<Bubble> bubbles = new ArrayList<>();\n    private int points = 0;\n    private boolean over = false;\n\n    @Override\n    public void start(Stage stage) {\n        Pane pane = new Pane();\n        pane.setPrefSize(WIDTH, HEIGHT);\n        pane.getChildren().add(new Rectangle(WIDTH, HEIGHT, Color.MIDNIGHTBLUE));\n        Text score = new Text(12, 24, \"Score: 0\");\n        score.setFill(Color.WHITE);\n        pane.getChildren().add(score);\n\n        Sub sub = new Sub(WIDTH / 2, HEIGHT / 2);\n        pane.getChildren().add(sub.getShape());\n        for (int i = 0; i < 4; i++) {\n            Jellyfish j = new Jellyfish(random.nextInt(WIDTH), random.nextInt(60), random.nextInt(360));\n            jellyfish.add(j);\n            pane.getChildren().add(j.getShape());\n        }\n\n        Scene scene = new Scene(pane);\n        scene.setOnKeyPressed(event -> {\n            if (over) {\n                return;\n            }\n            held.put(event.getCode(), true);\n            if (event.getCode() == KeyCode.SPACE && bubbles.size() < 4) {\n                Bubble bubble = new Bubble(sub.getShape().getTranslateX(), sub.getShape().getTranslateY(), sub.getShape().getRotate());\n                bubbles.add(bubble);\n                pane.getChildren().add(bubble.getShape());\n            }\n        });\n        scene.setOnKeyReleased(event -> held.put(event.getCode(), false));\n\n        new AnimationTimer() {\n            @Override\n            public void handle(long now) {\n                if (held.getOrDefault(KeyCode.LEFT, false)) {\n                    sub.turn(-4);\n                }\n                if (held.getOrDefault(KeyCode.RIGHT, false)) {\n                    sub.turn(4);\n                }\n                if (held.getOrDefault(KeyCode.UP, false)) {\n                    sub.accelerate(0.125);\n                }\n                sub.move();\n                jellyfish.forEach(j -> j.move());\n                bubbles.forEach(b -> b.move());\n\n                for (Bubble b : bubbles) {\n                    for (Jellyfish j : jellyfish) {\n                        if (b.isAlive() && j.isAlive() && b.collides(j)) {\n                            b.setAlive(false);\n                            j.setAlive(false);\n                            points += 10;\n                            score.setText(\"Score: \" + points);\n                            System.out.println(\"Score: \" + points);\n                        }\n                    }\n                }\n                bubbles.stream()\n                        .filter(b -> !b.isAlive())\n                        .forEach(b -> pane.getChildren().remove(b.getShape()));\n                jellyfish.stream()\n                        .filter(j -> !j.isAlive())\n                        .forEach(j -> pane.getChildren().remove(j.getShape()));\n                bubbles = bubbles.stream()\n                        .filter(b -> b.isAlive())\n                        .collect(Collectors.toList());\n                jellyfish = jellyfish.stream()\n                        .filter(j -> j.isAlive())\n                        .collect(Collectors.toList());\n\n                if (random.nextDouble() < 0.02) {\n                    Jellyfish newcomer = new Jellyfish(random.nextInt(WIDTH), 0, random.nextInt(360));\n                    if (!newcomer.collides(sub)) {\n                        jellyfish.add(newcomer);\n                        pane.getChildren().add(newcomer.getShape());\n                    }\n                }\n\n                for (Jellyfish j : jellyfish) {\n                    if (sub.collides(j)) {\n                        over = true;\n                        sub.getShape().setFill(Color.RED);\n                        score.setText(\"Game over! Score: \" + points);\n                        System.out.println(\"Game over! Score: \" + points);\n                        stop();\n                        break;\n                    }\n                }\n            }\n        }.start();\n\n        stage.setScene(scene);\n        stage.setTitle(\"Deep dive\");\n        stage.show();\n    }\n\n    public static double wrap(double value, double size) {\n        double result = value % size;\n        if (result < 0) {\n            result = result + size;\n        }\n        return result;\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n// ==== Mover.java ====\nimport javafx.geometry.Point2D;\nimport javafx.scene.shape.Shape;\n\npublic abstract class Mover {\n    private Shape shape;\n    private Point2D velocity;\n    private boolean alive;\n\n    public Mover(Shape shape, double x, double y) {\n        this.shape = shape;\n        this.shape.setTranslateX(x);\n        this.shape.setTranslateY(y);\n        this.velocity = new Point2D(0, 0);\n        this.alive = true;\n    }\n\n    public Shape getShape() {\n        return shape;\n    }\n\n    public boolean isAlive() {\n        return alive;\n    }\n\n    public void setAlive(boolean alive) {\n        this.alive = alive;\n    }\n\n    public void turn(double degrees) {\n        shape.setRotate(shape.getRotate() + degrees);\n    }\n\n    public void accelerate(double amount) {\n        double angle = Math.toRadians(shape.getRotate());\n        velocity = velocity.add(Math.cos(angle) * amount, Math.sin(angle) * amount);\n    }\n\n    public void move() {\n        shape.setTranslateX(Main.wrap(shape.getTranslateX() + velocity.getX(), Main.WIDTH));\n        shape.setTranslateY(Main.wrap(shape.getTranslateY() + velocity.getY(), Main.HEIGHT));\n    }\n\n    public boolean collides(Mover other) {\n        Shape overlap = Shape.intersect(shape, other.getShape());\n        return overlap.getBoundsInLocal().getWidth() != -1;\n    }\n}\n\n// ==== Sub.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Sub extends Mover {\n\n    public Sub(double x, double y) {\n        super(new Polygon(-15, -6, 9, -6, 15, 0, 9, 6, -15, 6), x, y);\n        getShape().setFill(Color.GOLD);\n    }\n}\n\n// ==== Jellyfish.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Jellyfish extends Mover {\n\n    public Jellyfish(double x, double y, double heading) {\n        super(new Polygon(-10, 0, -6, -8, 0, -10, 6, -8, 10, 0, 7, 10, 3, 2, 0, 10, -3, 2, -7, 10), x, y);\n        getShape().setFill(Color.ORCHID);\n        turn(heading);\n        accelerate(0.5);\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        turn(1);\n    }\n}\n\n// ==== Bubble.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Circle;\n\npublic class Bubble extends Mover {\n    private int age;\n\n    public Bubble(double x, double y, double heading) {\n        super(new Circle(3, Color.LIGHTCYAN), x, y);\n        turn(heading);\n        accelerate(2.5);\n        age = 0;\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        age++;\n        if (age == 50) {\n            setAlive(false);\n        }\n    }\n}\n```\n\n```window\n{\"events\":[\"press key LEFT\",\"frames 20\",\"release key LEFT\",\"key SPACE\",\"frames 10\",\"key SPACE\",\"frames 10\",\"key SPACE\",\"frames 30\",\"press key RIGHT\",\"frames 25\",\"release key RIGHT\",\"key SPACE\",\"frames 20\",\"press key UP\",\"frames 10\",\"release key UP\",\"frames 140\",\"key SPACE\",\"frames 5\"],\"window\":{\"windows\":[{\"title\":\"Deep dive\",\"scene\":{\"width\":360,\"height\":240,\"onKeyPressed\":true,\"onKeyReleased\":true,\"root\":{\"n\":1,\"type\":\"Pane\",\"f\":1,\"prefWidth\":360,\"prefHeight\":240,\"children\":[{\"n\":2,\"type\":\"Rectangle\",\"f\":2,\"x\":0,\"y\":0,\"width\":360,\"height\":240,\"fill\":\"#191970\"},{\"n\":3,\"type\":\"Text\",\"f\":3,\"text\":\"Game over! Score: 20\",\"x\":12,\"y\":24,\"fill\":\"#ffffff\"},{\"n\":4,\"type\":\"Polygon\",\"f\":4,\"translateX\":233.4450178071981,\"translateY\":139.45239565164704,\"rotate\":20,\"points\":[-15,-6,9,-6,15,0,9,6,-15,6],\"fill\":\"#ff0000\"},{\"n\":5,\"type\":\"Polygon\",\"f\":5,\"translateX\":252.35257122095965,\"translateY\":131.68888066884804,\"rotate\":240,\"points\":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],\"fill\":\"#da70d6\"},{\"n\":6,\"type\":\"Polygon\",\"f\":7,\"translateX\":239.9700222008575,\"translateY\":113.19866655731516,\"rotate\":295,\"points\":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],\"fill\":\"#da70d6\"},{\"n\":7,\"type\":\"Polygon\",\"f\":9,\"translateX\":331.43975010271294,\"translateY\":50.66029147951172,\"rotate\":302,\"points\":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],\"fill\":\"#da70d6\"}]}}}],\"problems\":[],\"frames\":{\"count\":270,\"list\":[[{\"roots\":[1]},{\"k\":1,\"type\":\"Pane\",\"children\":[2,3,4,5,6,7,8]},{\"k\":2,\"type\":\"Rectangle\",\"width\":360,\"height\":240,\"fill\":\"#191970\"},{\"k\":3,\"type\":\"Text\",\"x\":12,\"y\":24,\"fill\":\"#ffffff\",\"text\":\"Score: 0\",\"font\":{\"family\":\"System\",\"size\":13}},{\"k\":4,\"type\":\"Polygon\",\"tx\":180,\"ty\":120,\"r\":-4,\"points\":[-15,-6,9,-6,15,0,9,6,-15,6],\"fill\":\"#ffd700\"},{\"k\":5,\"type\":\"Polygon\",\"tx\":231.13,\"ty\":52.48,\"r\":76,\"points\":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],\"fill\":\"#da70d6\"},{\"k\":6,\"type\":\"Polygon\",\"tx\":249.54,\"ty\":12.81,\"r\":203,\"points\":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],\"fill\":\"#da70d6\"},{\"k\":7,\"type\":\"Polygon\",\"tx\":292.68,\"ty\":50.38,\"r\":131,\"points\":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],\"fill\":\"#da70d6\"},{\"k\":8,\"type\":\"Polygon\",\"tx\":155.47,\"ty\":11.17,\"r\":21,\"points\":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],\"fill\":\"#da70d6\"}],[{\"k\":4,\"r\":-8},{\"k\":5,\"tx\":231.26,\"ty\":52.97,\"r\":77},{\"k\":6,\"tx\":249.07,\"ty\":12.63,\"r\":204},{\"k\":7,\"tx\":292.36,\"ty\":50.77,\"r\":132},{\"k\":8,\"tx\":155.94,\"ty\":11.34,\"r\":22}],[{\"k\":4,\"r\":-12},{\"k\":5,\"tx\":231.39,\"ty\":53.45,\"r\":78},{\"k\":6,\"tx\":248.61,\"ty\":12.44,\"r\":205},{\"k\":7,\"tx\":292.04,\"ty\":51.15,\"r\":133},{\"k\":8,\"tx\":156.41,\"ty\":11.51,\"r\":23}],[{\"k\":1,\"children\":[2,3,4,5,6,7,8,9]},{\"k\":4,\"r\":-16},{\"k\":5,\"tx\":231.52,\"ty\":53.93,\"r\":79},{\"k\":6,\"tx\":248.15,\"ty\":12.25,\"r\":206},{\"k\":7,\"tx\":291.71,\"ty\":51.53,\"r\":134},{\"k\":8,\"tx\":156.88,\"ty\":11.68,\"r\":24},{\"k\":9,\"type\":\"Polygon\",\"tx\":34,\"r\":141,\"points\":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],\"fill\":\"#da70d6\"}],[{\"k\":4,\"r\":-20},{\"k\":5,\"tx\":231.65,\"ty\":54.41,\"r\":80},{\"k\":6,\"tx\":247.68,\"ty\":12.06,\"r\":207},{\"k\":7,\"tx\":291.39,\"ty\":51.92,\"r\":135},{\"k\":8,\"tx\":157.35,\"ty\":11.86,\"r\":25},{\"k\":9,\"tx\":33.61,\"ty\":0.31,\"r\":142}],[{\"k\":4,\"r\":-24},{\"k\":5,\"tx\":231.78,\"ty\":54.9,\"r\":81},{\"k\":6,\"tx\":247.22,\"ty\":11.88,\"r\":208},{\"k\":7,\"tx\":291.07,\"ty\":52.3,\"r\":136},{\"k\":8,\"tx\":157.82,\"ty\":12.03,\"r\":26},{\"k\":9,\"tx\":33.22,\"ty\":0.63,\"r\":143}],[{\"k\":4,\"r\":-28},{\"k\":5,\"tx\":231.91,\"ty\":55.38,\"r\":82},{\"k\":6,\"tx\":246.75,\"ty\":11.69,\"r\":209},{\"k\":7,\"tx\":290.75,\"ty\":52.68,\"r\":137},{\"k\":8,\"tx\":158.29,\"ty\":12.2,\"r\":27},{\"k\":9,\"tx\":32.83,\"ty\":0.94,\"r\":144}],[{\"k\":4,\"r\":-32},{\"k\":5,\"tx\":232.04,\"ty\":55.86,\"r\":83},{\"k\":6,\"tx\":246.29,\"ty\":11.5,\"r\":210},{\"k\":7,\"tx\":290.43,\"ty\":53.06,\"r\":138},{\"k\":8,\"tx\":158.76,\"ty\":12.37,\"r\":28},{\"k\":9,\"tx\":32.45,\"ty\":1.26,\"r\":145}],[{\"k\":4,\"r\":-36},{\"k\":5,\"tx\":232.16,\"ty\":56.35,\"r\":84},{\"k\":6,\"tx\":245.83,\"ty\":11.31,\"r\":211},{\"k\":7,\"tx\":290.11,\"ty\":53.45,\"r\":139},{\"k\":8,\"tx\":159.23,\"ty\":12.54,\"r\":29},{\"k\":9,\"tx\":32.06,\"ty\":1.57,\"r\":146}],[{\"k\":4,\"r\":-40},{\"k\":5,\"tx\":232.29,\"ty\":56.83,\"r\":85},{\"k\":6,\"tx\":245.36,\"ty\":11.13,\"r\":212},{\"k\":7,\"tx\":289.79,\"ty\":53.83,\"r\":140},{\"k\":8,\"tx\":159.7,\"ty\":12.71,\"r\":30},{\"k\":9,\"tx\":31.67,\"ty\":1.89,\"r\":147}],[{\"k\":4,\"r\":-44},{\"k\":5,\"tx\":232.42,\"ty\":57.31,\"r\":86},{\"k\":6,\"tx\":244.9,\"ty\":10.94,\"r\":213},{\"k\":7,\"tx\":289.46,\"ty\":54.21,\"r\":141},{\"k\":8,\"tx\":160.17,\"ty\":12.88,\"r\":31},{\"k\":9,\"tx\":31.28,\"ty\":2.2,\"r\":148}],[{\"k\":4,\"r\":-48},{\"k\":5,\"tx\":232.55,\"ty\":57.8,\"r\":87},{\"k\":6,\"tx\":244.44,\"ty\":10.75,\"r\":214},{\"k\":7,\"tx\":289.14,\"ty\":54.6,\"r\":142},{\"k\":8,\"tx\":160.64,\"ty\":13.05,\"r\":32},{\"k\":9,\"tx\":30.89,\"ty\":2.52,\"r\":149}],[{\"k\":4,\"r\":-52},{\"k\":5,\"tx\":232.68,\"ty\":58.28,\"r\":88},{\"k\":6,\"tx\":243.97,\"ty\":10.57,\"r\":215},{\"k\":7,\"tx\":288.82,\"ty\":54.98,\"r\":143},{\"k\":8,\"tx\":161.11,\"ty\":13.22,\"r\":33},{\"k\":9,\"tx\":30.5,\"ty\":2.83,\"r\":150}],[{\"k\":4,\"r\":-56},{\"k\":5,\"tx\":232.81,\"ty\":58.76,\"r\":89},{\"k\":6,\"tx\":243.51,\"ty\":10.38,\"r\":216},{\"k\":7,\"tx\":288.5,\"ty\":55.36,\"r\":144},{\"k\":8,\"tx\":161.58,\"ty\":13.39,\"r\":34},{\"k\":9,\"tx\":30.11,\"ty\":3.15,\"r\":151}],[{\"k\":4,\"r\":-60},{\"k\":5,\"tx\":232.94,\"ty\":59.24,\"r\":90},{\"k\":6,\"tx\":243.05,\"ty\":10.19,\"r\":217},{\"k\":7,\"tx\":288.18,\"ty\":55.75,\"r\":145},{\"k\":8,\"tx\":162.05,\"ty\":13.57,\"r\":35},{\"k\":9,\"tx\":29.73,\"ty\":3.46,\"r\":152}],[{\"k\":4,\"r\":-64},{\"k\":5,\"tx\":233.07,\"ty\":59.73,\"r\":91},{\"k\":6,\"tx\":242.58,\"ty\":10,\"r\":218},{\"k\":7,\"tx\":287.86,\"ty\":56.13,\"r\":146},{\"k\":8,\"tx\":162.52,\"ty\":13.74,\"r\":36},{\"k\":9,\"tx\":29.34,\"ty\":3.78,\"r\":153}],[{\"k\":4,\"r\":-68},{\"k\":5,\"tx\":233.2,\"ty\":60.21,\"r\":92},{\"k\":6,\"tx\":242.12,\"ty\":9.82,\"r\":219},{\"k\":7,\"tx\":287.54,\"ty\":56.51,\"r\":147},{\"k\":8,\"tx\":162.99,\"ty\":13.91,\"r\":37},{\"k\":9,\"tx\":28.95,\"ty\":4.09,\"r\":154}],[{\"k\":4,\"r\":-72},{\"k\":5,\"tx\":233.33,\"ty\":60.69,\"r\":93},{\"k\":6,\"tx\":241.66,\"ty\":9.63,\"r\":220},{\"k\":7,\"tx\":287.21,\"ty\":56.89,\"r\":148},{\"k\":8,\"tx\":163.46,\"ty\":14.08,\"r\":38},{\"k\":9,\"tx\":28.56,\"ty\":4.41,\"r\":155}],[{\"k\":4,\"r\":-76},{\"k\":5,\"tx\":233.46,\"ty\":61.18,\"r\":94},{\"k\":6,\"tx\":241.19,\"ty\":9.44,\"r\":221},{\"k\":7,\"tx\":286.89,\"ty\":57.28,\"r\":149},{\"k\":8,\"tx\":163.93,\"ty\":14.25,\"r\":39},{\"k\":9,\"tx\":28.17,\"ty\":4.72,\"r\":156}],[{\"k\":4,\"r\":-80},{\"k\":5,\"tx\":233.59,\"ty\":61.66,\"r\":95},{\"k\":6,\"tx\":240.73,\"ty\":9.25,\"r\":222},{\"k\":7,\"tx\":286.57,\"ty\":57.66,\"r\":150},{\"k\":8,\"tx\":164.4,\"ty\":14.42,\"r\":40},{\"k\":9,\"tx\":27.78,\"ty\":5.03,\"r\":157}],[{\"k\":1,\"children\":[2,3,4,5,6,7,8,9,10]},{\"k\":5,\"tx\":233.72,\"ty\":62.14,\"r\":96},{\"k\":6,\"tx\":240.26,\"ty\":9.07,\"r\":223},{\"k\":7,\"tx\":286.25,\"ty\":58.04,\"r\":151},{\"k\":8,\"tx\":164.87,\"ty\":14.59,\"r\":41},{\"k\":9,\"tx\":27.39,\"ty\":5.35,\"r\":158},{\"k\":10,\"type\":\"Circle\",\"tx\":180.43,\"ty\":117.54,\"r\":-80,\"radius\":3,\"fill\":\"#e0ffff\"}],[{\"k\":5,\"tx\":233.85,\"ty\":62.63,\"r\":97},{\"k\":6,\"tx\":239.8,\"ty\":8.88,\"r\":224},{\"k\":7,\"tx\":285.93,\"ty\":58.43,\"r\":152},{\"k\":8,\"tx\":165.34,\"ty\":14.76,\"r\":42},{\"k\":9,\"tx\":27.01,\"ty\":5.66,\"r\":159},{\"k\":10,\"tx\":180.87,\"ty\":115.08}],[{\"k\":5,\"tx\":233.98,\"ty\":63.11,\"r\":98},{\"k\":6,\"tx\":239.34,\"ty\":8.69,\"r\":225},{\"k\":7,\"tx\":285.61,\"ty\":58.81,\"r\":153},{\"k\":8,\"tx\":165.81,\"ty\":14.93,\"r\":43},{\"k\":9,\"tx\":26.62,\"ty\":5.98,\"r\":160},{\"k\":10,\"tx\":181.3,\"ty\":112.61}],[{\"k\":5,\"tx\":234.11,\"ty\":63.59,\"r\":99},{\"k\":6,\"tx\":238.87,\"ty\":8.5,\"r\":226},{\"k\":7,\"tx\":285.29,\"ty\":59.19,\"r\":154},{\"k\":8,\"tx\":166.28,\"ty\":15.1,\"r\":44},{\"k\":9,\"tx\":26.23,\"ty\":6.29,\"r\":161},{\"k\":10,\"tx\":181.74,\"ty\":110.15}],[{\"k\":5,\"tx\":234.24,\"ty\":64.07,\"r\":100},{\"k\":6,\"tx\":238.41,\"ty\":8.32,\"r\":227},{\"k\":7,\"tx\":284.97,\"ty\":59.58,\"r\":155},{\"k\":8,\"tx\":166.75,\"ty\":15.28,\"r\":45},{\"k\":9,\"tx\":25.84,\"ty\":6.61,\"r\":162},{\"k\":10,\"tx\":182.17,\"ty\":107.69}],[{\"k\":5,\"tx\":234.36,\"ty\":64.56,\"r\":101},{\"k\":6,\"tx\":237.95,\"ty\":8.13,\"r\":228},{\"k\":7,\"tx\":284.64,\"ty\":59.96,\"r\":156},{\"k\":8,\"tx\":167.22,\"ty\":15.45,\"r\":46},{\"k\":9,\"tx\":25.45,\"ty\":6.92,\"r\":163},{\"k\":10,\"tx\":182.6,\"ty\":105.23}],[{\"k\":5,\"tx\":234.49,\"ty\":65.04,\"r\":102},{\"k\":6,\"tx\":237.48,\"ty\":7.94,\"r\":229},{\"k\":7,\"tx\":284.32,\"ty\":60.34,\"r\":157},{\"k\":8,\"tx\":167.69,\"ty\":15.62,\"r\":47},{\"k\":9,\"tx\":25.06,\"ty\":7.24,\"r\":164},{\"k\":10,\"tx\":183.04,\"ty\":102.77}],[{\"k\":5,\"tx\":234.62,\"ty\":65.52,\"r\":103},{\"k\":6,\"tx\":237.02,\"ty\":7.76,\"r\":230},{\"k\":7,\"tx\":284,\"ty\":60.72,\"r\":158},{\"k\":8,\"tx\":168.16,\"ty\":15.79,\"r\":48},{\"k\":9,\"tx\":24.67,\"ty\":7.55,\"r\":165},{\"k\":10,\"tx\":183.47,\"ty\":100.3}],[{\"k\":5,\"tx\":234.75,\"ty\":66.01,\"r\":104},{\"k\":6,\"tx\":236.56,\"ty\":7.57,\"r\":231},{\"k\":7,\"tx\":283.68,\"ty\":61.11,\"r\":159},{\"k\":8,\"tx\":168.63,\"ty\":15.96,\"r\":49},{\"k\":9,\"tx\":24.29,\"ty\":7.87,\"r\":166},{\"k\":10,\"tx\":183.91,\"ty\":97.84}],[{\"k\":5,\"tx\":234.88,\"ty\":66.49,\"r\":105},{\"k\":6,\"tx\":236.09,\"ty\":7.38,\"r\":232},{\"k\":7,\"tx\":283.36,\"ty\":61.49,\"r\":160},{\"k\":8,\"tx\":169.1,\"ty\":16.13,\"r\":50},{\"k\":9,\"tx\":23.9,\"ty\":8.18,\"r\":167},{\"k\":10,\"tx\":184.34,\"ty\":95.38}],[{\"k\":1,\"children\":[2,3,4,5,6,7,8,9,10,11]},{\"k\":5,\"tx\":235.01,\"ty\":66.97,\"r\":106},{\"k\":6,\"tx\":235.63,\"ty\":7.19,\"r\":233},{\"k\":7,\"tx\":283.04,\"ty\":61.87,\"r\":161},{\"k\":8,\"tx\":169.57,\"ty\":16.3,\"r\":51},{\"k\":9,\"tx\":23.51,\"ty\":8.5,\"r\":168},{\"k\":10,\"tx\":184.78,\"ty\":92.92},{\"k\":11,\"type\":\"Circle\",\"tx\":180.43,\"ty\":117.54,\"r\":-80,\"radius\":3,\"fill\":\"#e0ffff\"}],[{\"k\":5,\"tx\":235.14,\"ty\":67.45,\"r\":107},{\"k\":6,\"tx\":235.17,\"ty\":7.01,\"r\":234},{\"k\":7,\"tx\":282.72,\"ty\":62.26,\"r\":162},{\"k\":8,\"tx\":170.04,\"ty\":16.47,\"r\":52},{\"k\":9,\"tx\":23.12,\"ty\":8.81,\"r\":169},{\"k\":10,\"tx\":185.21,\"ty\":90.46},{\"k\":11,\"tx\":180.87,\"ty\":115.08}],[{\"k\":5,\"tx\":235.27,\"ty\":67.94,\"r\":108},{\"k\":6,\"tx\":234.7,\"ty\":6.82,\"r\":235},{\"k\":7,\"tx\":282.39,\"ty\":62.64,\"r\":163},{\"k\":8,\"tx\":170.5,\"ty\":16.64,\"r\":53},{\"k\":9,\"tx\":22.73,\"ty\":9.13,\"r\":170},{\"k\":10,\"tx\":185.64,\"ty\":87.99},{\"k\":11,\"tx\":181.3,\"ty\":112.61}],[{\"k\":5,\"tx\":235.4,\"ty\":68.42,\"r\":109},{\"k\":6,\"tx\":234.24,\"ty\":6.63,\"r\":236},{\"k\":7,\"tx\":282.07,\"ty\":63.02,\"r\":164},{\"k\":8,\"tx\":170.97,\"ty\":16.81,\"r\":54},{\"k\":9,\"tx\":22.34,\"ty\":9.44,\"r\":171},{\"k\":10,\"tx\":186.08,\"ty\":85.53},{\"k\":11,\"tx\":181.74,\"ty\":110.15}],[{\"k\":5,\"tx\":235.53,\"ty\":68.9,\"r\":110},{\"k\":6,\"tx\":233.77,\"ty\":6.44,\"r\":237},{\"k\":7,\"tx\":281.75,\"ty\":63.41,\"r\":165},{\"k\":8,\"tx\":171.44,\"ty\":16.99,\"r\":55},{\"k\":9,\"tx\":21.95,\"ty\":9.75,\"r\":172},{\"k\":10,\"tx\":186.51,\"ty\":83.07},{\"k\":11,\"tx\":182.17,\"ty\":107.69}],[{\"k\":5,\"tx\":235.66,\"ty\":69.39,\"r\":111},{\"k\":6,\"tx\":233.31,\"ty\":6.26,\"r\":238},{\"k\":7,\"tx\":281.43,\"ty\":63.79,\"r\":166},{\"k\":8,\"tx\":171.91,\"ty\":17.16,\"r\":56},{\"k\":9,\"tx\":21.57,\"ty\":10.07,\"r\":173},{\"k\":10,\"tx\":186.95,\"ty\":80.61},{\"k\":11,\"tx\":182.6,\"ty\":105.23}],[{\"k\":5,\"tx\":235.79,\"ty\":69.87,\"r\":112},{\"k\":6,\"tx\":232.85,\"ty\":6.07,\"r\":239},{\"k\":7,\"tx\":281.11,\"ty\":64.17,\"r\":167},{\"k\":8,\"tx\":172.38,\"ty\":17.33,\"r\":57},{\"k\":9,\"tx\":21.18,\"ty\":10.38,\"r\":174},{\"k\":10,\"tx\":187.38,\"ty\":78.15},{\"k\":11,\"tx\":183.04,\"ty\":102.77}],[{\"k\":5,\"tx\":235.92,\"ty\":70.35,\"r\":113},{\"k\":6,\"tx\":232.38,\"ty\":5.88,\"r\":240},{\"k\":7,\"tx\":280.79,\"ty\":64.55,\"r\":168},{\"k\":8,\"tx\":172.85,\"ty\":17.5,\"r\":58},{\"k\":9,\"tx\":20.79,\"ty\":10.7,\"r\":175},{\"k\":10,\"tx\":187.81,\"ty\":75.68},{\"k\":11,\"tx\":183.47,\"ty\":100.3}],[{\"k\":5,\"tx\":236.05,\"ty\":70.84,\"r\":114},{\"k\":6,\"tx\":231.92,\"ty\":5.7,\"r\":241},{\"k\":7,\"tx\":280.47,\"ty\":64.94,\"r\":169},{\"k\":8,\"tx\":173.32,\"ty\":17.67,\"r\":59},{\"k\":9,\"tx\":20.4,\"ty\":11.01,\"r\":176},{\"k\":10,\"tx\":188.25,\"ty\":73.22},{\"k\":11,\"tx\":183.91,\"ty\":97.84}],[{\"k\":5,\"tx\":236.18,\"ty\":71.32,\"r\":115},{\"k\":6,\"tx\":231.46,\"ty\":5.51,\"r\":242},{\"k\":7,\"tx\":280.14,\"ty\":65.32,\"r\":170},{\"k\":8,\"tx\":173.79,\"ty\":17.84,\"r\":60},{\"k\":9,\"tx\":20.01,\"ty\":11.33,\"r\":177},{\"k\":10,\"tx\":188.68,\"ty\":70.76},{\"k\":11,\"tx\":184.34,\"ty\":95.38}],[{\"k\":1,\"children\":[2,3,4,5,6,7,8,9,10,11,12]},{\"k\":5,\"tx\":236.31,\"ty\":71.8,\"r\":116},{\"k\":6,\"tx\":230.99,\"ty\":5.32,\"r\":243},{\"k\":7,\"tx\":279.82,\"ty\":65.7,\"r\":171},{\"k\":8,\"tx\":174.26,\"ty\":18.01,\"r\":61},{\"k\":9,\"tx\":19.62,\"ty\":11.64,\"r\":178},{\"k\":10,\"tx\":189.12,\"ty\":68.3},{\"k\":11,\"tx\":184.78,\"ty\":92.92},{\"k\":12,\"type\":\"Circle\",\"tx\":180.43,\"ty\":117.54,\"r\":-80,\"radius\":3,\"fill\":\"#e0ffff\"}],[{\"k\":5,\"tx\":236.44,\"ty\":72.28,\"r\":117},{\"k\":6,\"tx\":230.53,\"ty\":5.13,\"r\":244},{\"k\":7,\"tx\":279.5,\"ty\":66.09,\"r\":172},{\"k\":8,\"tx\":174.73,\"ty\":18.18,\"r\":62},{\"k\":9,\"tx\":19.23,\"ty\":11.96,\"r\":179},{\"k\":10,\"tx\":189.55,\"ty\":65.84},{\"k\":11,\"tx\":185.21,\"ty\":90.46},{\"k\":12,\"tx\":180.87,\"ty\":115.08}],[{\"k\":5,\"tx\":236.56,\"ty\":72.77,\"r\":118},{\"k\":6,\"tx\":230.07,\"ty\":4.95,\"r\":245},{\"k\":7,\"tx\":279.18,\"ty\":66.47,\"r\":173},{\"k\":8,\"tx\":175.2,\"ty\":18.35,\"r\":63},{\"k\":9,\"tx\":18.85,\"ty\":12.27,\"r\":180},{\"k\":10,\"tx\":189.98,\"ty\":63.37},{\"k\":11,\"tx\":185.64,\"ty\":87.99},{\"k\":12,\"tx\":181.3,\"ty\":112.61}],[{\"k\":5,\"tx\":236.69,\"ty\":73.25,\"r\":119},{\"k\":6,\"tx\":229.6,\"ty\":4.76,\"r\":246},{\"k\":7,\"tx\":278.86,\"ty\":66.85,\"r\":174},{\"k\":8,\"tx\":175.67,\"ty\":18.52,\"r\":64},{\"k\":9,\"tx\":18.46,\"ty\":12.59,\"r\":181},{\"k\":10,\"tx\":190.42,\"ty\":60.91},{\"k\":11,\"tx\":186.08,\"ty\":85.53},{\"k\":12,\"tx\":181.74,\"ty\":110.15}],[{\"k\":5,\"tx\":236.82,\"ty\":73.73,\"r\":120},{\"k\":6,\"tx\":229.14,\"ty\":4.57,\"r\":247},{\"k\":7,\"tx\":278.54,\"ty\":67.24,\"r\":175},{\"k\":8,\"tx\":176.14,\"ty\":18.7,\"r\":65},{\"k\":9,\"tx\":18.07,\"ty\":12.9,\"r\":182},{\"k\":10,\"tx\":190.85,\"ty\":58.45},{\"k\":11,\"tx\":186.51,\"ty\":83.07},{\"k\":12,\"tx\":182.17,\"ty\":107.69}],[{\"k\":5,\"tx\":236.95,\"ty\":74.22,\"r\":121},{\"k\":6,\"tx\":228.67,\"ty\":4.38,\"r\":248},{\"k\":7,\"tx\":278.22,\"ty\":67.62,\"r\":176},{\"k\":8,\"tx\":176.61,\"ty\":18.87,\"r\":66},{\"k\":9,\"tx\":17.68,\"ty\":13.22,\"r\":183},{\"k\":10,\"tx\":191.29,\"ty\":55.99},{\"k\":11,\"tx\":186.95,\"ty\":80.61},{\"k\":12,\"tx\":182.6,\"ty\":105.23}],[{\"k\":5,\"tx\":237.08,\"ty\":74.7,\"r\":122},{\"k\":6,\"tx\":228.21,\"ty\":4.2,\"r\":249},{\"k\":7,\"tx\":277.89,\"ty\":68,\"r\":177},{\"k\":8,\"tx\":177.08,\"ty\":19.04,\"r\":67},{\"k\":9,\"tx\":17.29,\"ty\":13.53,\"r\":184},{\"k\":10,\"tx\":191.72,\"ty\":53.53},{\"k\":11,\"tx\":187.38,\"ty\":78.15},{\"k\":12,\"tx\":183.04,\"ty\":102.77}],[{\"k\":5,\"tx\":237.21,\"ty\":75.18,\"r\":123},{\"k\":6,\"tx\":227.75,\"ty\":4.01,\"r\":250},{\"k\":7,\"tx\":277.57,\"ty\":68.39,\"r\":178},{\"k\":8,\"tx\":177.55,\"ty\":19.21,\"r\":68},{\"k\":9,\"tx\":16.9,\"ty\":13.85,\"r\":185},{\"k\":10,\"tx\":192.16,\"ty\":51.06},{\"k\":11,\"tx\":187.81,\"ty\":75.68},{\"k\":12,\"tx\":183.47,\"ty\":100.3}],[{\"k\":5,\"tx\":237.34,\"ty\":75.67,\"r\":124},{\"k\":6,\"tx\":227.28,\"ty\":3.82,\"r\":251},{\"k\":7,\"tx\":277.25,\"ty\":68.77,\"r\":179},{\"k\":8,\"tx\":178.02,\"ty\":19.38,\"r\":69},{\"k\":9,\"tx\":16.51,\"ty\":14.16,\"r\":186},{\"k\":10,\"tx\":192.59,\"ty\":48.6},{\"k\":11,\"tx\":188.25,\"ty\":73.22},{\"k\":12,\"tx\":183.91,\"ty\":97.84}],[{\"k\":5,\"tx\":237.47,\"ty\":76.15,\"r\":125},{\"k\":6,\"tx\":226.82,\"ty\":3.63,\"r\":252},{\"k\":7,\"tx\":276.93,\"ty\":69.15,\"r\":180},{\"k\":8,\"tx\":178.49,\"ty\":19.55,\"r\":70},{\"k\":9,\"tx\":16.13,\"ty\":14.47,\"r\":187},{\"k\":10,\"tx\":193.02,\"ty\":46.14},{\"k\":11,\"tx\":188.68,\"ty\":70.76},{\"k\":12,\"tx\":184.34,\"ty\":95.38}],[{\"k\":5,\"tx\":237.6,\"ty\":76.63,\"r\":126},{\"k\":6,\"tx\":226.36,\"ty\":3.45,\"r\":253},{\"k\":7,\"tx\":276.61,\"ty\":69.53,\"r\":181},{\"k\":8,\"tx\":178.96,\"ty\":19.72,\"r\":71},{\"k\":9,\"tx\":15.74,\"ty\":14.79,\"r\":188},{\"k\":10,\"tx\":193.46,\"ty\":43.68},{\"k\":11,\"tx\":189.12,\"ty\":68.3},{\"k\":12,\"tx\":184.78,\"ty\":92.92}],[{\"k\":5,\"tx\":237.73,\"ty\":77.11,\"r\":127},{\"k\":6,\"tx\":225.89,\"ty\":3.26,\"r\":254},{\"k\":7,\"tx\":276.29,\"ty\":69.92,\"r\":182},{\"k\":8,\"tx\":179.43,\"ty\":19.89,\"r\":72},{\"k\":9,\"tx\":15.35,\"ty\":15.1,\"r\":189},{\"k\":10,\"tx\":193.89,\"ty\":41.22},{\"k\":11,\"tx\":189.55,\"ty\":65.84},{\"k\":12,\"tx\":185.21,\"ty\":90.46}],[{\"k\":5,\"tx\":237.86,\"ty\":77.6,\"r\":128},{\"k\":6,\"tx\":225.43,\"ty\":3.07,\"r\":255},{\"k\":7,\"tx\":275.97,\"ty\":70.3,\"r\":183},{\"k\":8,\"tx\":179.9,\"ty\":20.06,\"r\":73},{\"k\":9,\"tx\":14.96,\"ty\":15.42,\"r\":190},{\"k\":10,\"tx\":194.33,\"ty\":38.75},{\"k\":11,\"tx\":189.98,\"ty\":63.37},{\"k\":12,\"tx\":185.64,\"ty\":87.99}],[{\"k\":5,\"tx\":237.99,\"ty\":78.08,\"r\":129},{\"k\":6,\"tx\":224.97,\"ty\":2.89,\"r\":256},{\"k\":7,\"tx\":275.64,\"ty\":70.68,\"r\":184},{\"k\":8,\"tx\":180.37,\"ty\":20.23,\"r\":74},{\"k\":9,\"tx\":14.57,\"ty\":15.73,\"r\":191},{\"k\":10,\"tx\":194.76,\"ty\":36.29},{\"k\":11,\"tx\":190.42,\"ty\":60.91},{\"k\":12,\"tx\":186.08,\"ty\":85.53}],[{\"k\":5,\"tx\":238.12,\"ty\":78.56,\"r\":130},{\"k\":6,\"tx\":224.5,\"ty\":2.7,\"r\":257},{\"k\":7,\"tx\":275.32,\"ty\":71.07,\"r\":185},{\"k\":8,\"tx\":180.84,\"ty\":20.41,\"r\":75},{\"k\":9,\"tx\":14.18,\"ty\":16.05,\"r\":192},{\"k\":10,\"tx\":195.19,\"ty\":33.83},{\"k\":11,\"tx\":190.85,\"ty\":58.45},{\"k\":12,\"tx\":186.51,\"ty\":83.07}],[{\"k\":5,\"tx\":238.25,\"ty\":79.05,\"r\":131},{\"k\":6,\"tx\":224.04,\"ty\":2.51,\"r\":258},{\"k\":7,\"tx\":275,\"ty\":71.45,\"r\":186},{\"k\":8,\"tx\":181.31,\"ty\":20.58,\"r\":76},{\"k\":9,\"tx\":13.79,\"ty\":16.36,\"r\":193},{\"k\":10,\"tx\":195.63,\"ty\":31.37},{\"k\":11,\"tx\":191.29,\"ty\":55.99},{\"k\":12,\"tx\":186.95,\"ty\":80.61}],[{\"k\":5,\"tx\":238.38,\"ty\":79.53,\"r\":132},{\"k\":6,\"tx\":223.58,\"ty\":2.32,\"r\":259},{\"k\":7,\"tx\":274.68,\"ty\":71.83,\"r\":187},{\"k\":8,\"tx\":181.78,\"ty\":20.75,\"r\":77},{\"k\":9,\"tx\":13.41,\"ty\":16.68,\"r\":194},{\"k\":10,\"tx\":196.06,\"ty\":28.91},{\"k\":11,\"tx\":191.72,\"ty\":53.53},{\"k\":12,\"tx\":187.38,\"ty\":78.15}],[{\"k\":5,\"tx\":238.51,\"ty\":80.01,\"r\":133},{\"k\":6,\"tx\":223.11,\"ty\":2.14,\"r\":260},{\"k\":7,\"tx\":274.36,\"ty\":72.22,\"r\":188},{\"k\":8,\"tx\":182.25,\"ty\":20.92,\"r\":78},{\"k\":9,\"tx\":13.02,\"ty\":16.99,\"r\":195},{\"k\":10,\"tx\":196.5,\"ty\":26.44},{\"k\":11,\"tx\":192.16,\"ty\":51.06},{\"k\":12,\"tx\":187.81,\"ty\":75.68}],[{\"k\":5,\"tx\":238.64,\"ty\":80.49,\"r\":134},{\"k\":6,\"tx\":222.65,\"ty\":1.95,\"r\":261},{\"k\":7,\"tx\":274.04,\"ty\":72.6,\"r\":189},{\"k\":8,\"tx\":182.72,\"ty\":21.09,\"r\":79},{\"k\":9,\"tx\":12.63,\"ty\":17.31,\"r\":196},{\"k\":10,\"tx\":196.93,\"ty\":23.98},{\"k\":11,\"tx\":192.59,\"ty\":48.6},{\"k\":12,\"tx\":188.25,\"ty\":73.22}],[{\"k\":5,\"tx\":238.76,\"ty\":80.98,\"r\":135},{\"k\":6,\"tx\":222.18,\"ty\":1.76,\"r\":262},{\"k\":7,\"tx\":273.72,\"ty\":72.98,\"r\":190},{\"k\":8,\"tx\":183.19,\"ty\":21.26,\"r\":80},{\"k\":9,\"tx\":12.24,\"ty\":17.62,\"r\":197},{\"k\":10,\"tx\":197.36,\"ty\":21.52},{\"k\":11,\"tx\":193.02,\"ty\":46.14},{\"k\":12,\"tx\":188.68,\"ty\":70.76}],[{\"k\":5,\"tx\":238.89,\"ty\":81.46,\"r\":136},{\"k\":6,\"tx\":221.72,\"ty\":1.57,\"r\":263},{\"k\":7,\"tx\":273.39,\"ty\":73.36,\"r\":191},{\"k\":8,\"tx\":183.66,\"ty\":21.43,\"r\":81},{\"k\":9,\"tx\":11.85,\"ty\":17.94,\"r\":198},{\"k\":10,\"tx\":197.8,\"ty\":19.06},{\"k\":11,\"tx\":193.46,\"ty\":43.68},{\"k\":12,\"tx\":189.12,\"ty\":68.3}],[{\"k\":5,\"tx\":239.02,\"ty\":81.94,\"r\":137},{\"k\":6,\"tx\":221.26,\"ty\":1.39,\"r\":264},{\"k\":7,\"tx\":273.07,\"ty\":73.75,\"r\":192},{\"k\":8,\"tx\":184.13,\"ty\":21.6,\"r\":82},{\"k\":9,\"tx\":11.46,\"ty\":18.25,\"r\":199},{\"k\":10,\"tx\":198.23,\"ty\":16.6},{\"k\":11,\"tx\":193.89,\"ty\":41.22},{\"k\":12,\"tx\":189.55,\"ty\":65.84}],[{\"k\":5,\"tx\":239.15,\"ty\":82.43,\"r\":138},{\"k\":6,\"tx\":220.79,\"ty\":1.2,\"r\":265},{\"k\":7,\"tx\":272.75,\"ty\":74.13,\"r\":193},{\"k\":8,\"tx\":184.6,\"ty\":21.77,\"r\":83},{\"k\":9,\"tx\":11.07,\"ty\":18.56,\"r\":200},{\"k\":10,\"tx\":198.67,\"ty\":14.13},{\"k\":11,\"tx\":194.33,\"ty\":38.75},{\"k\":12,\"tx\":189.98,\"ty\":63.37}],[{\"k\":5,\"tx\":239.28,\"ty\":82.91,\"r\":139},{\"k\":6,\"tx\":220.33,\"ty\":1.01,\"r\":266},{\"k\":7,\"tx\":272.43,\"ty\":74.51,\"r\":194},{\"k\":8,\"tx\":185.07,\"ty\":21.94,\"r\":84},{\"k\":9,\"tx\":10.69,\"ty\":18.88,\"r\":201},{\"k\":10,\"tx\":199.1,\"ty\":11.67},{\"k\":11,\"tx\":194.76,\"ty\":36.29},{\"k\":12,\"tx\":190.42,\"ty\":60.91}],[{\"k\":5,\"tx\":239.41,\"ty\":83.39,\"r\":140},{\"k\":6,\"tx\":219.87,\"ty\":0.83,\"r\":267},{\"k\":7,\"tx\":272.11,\"ty\":74.9,\"r\":195},{\"k\":8,\"tx\":185.54,\"ty\":22.12,\"r\":85},{\"k\":9,\"tx\":10.3,\"ty\":19.19,\"r\":202},{\"k\":10,\"tx\":199.54,\"ty\":9.21},{\"k\":11,\"tx\":195.19,\"ty\":33.83},{\"k\":12,\"tx\":190.85,\"ty\":58.45}],[{\"k\":5,\"tx\":239.54,\"ty\":83.88,\"r\":141},{\"k\":6,\"tx\":219.4,\"ty\":0.64,\"r\":268},{\"k\":7,\"tx\":271.79,\"ty\":75.28,\"r\":196},{\"k\":8,\"tx\":186.01,\"ty\":22.29,\"r\":86},{\"k\":9,\"tx\":9.91,\"ty\":19.51,\"r\":203},{\"k\":10,\"tx\":199.97,\"ty\":6.75},{\"k\":11,\"tx\":195.63,\"ty\":31.37},{\"k\":12,\"tx\":191.29,\"ty\":55.99}],[{\"k\":1,\"children\":[2,3,4,5,6,7,9,10,12]},{\"k\":3,\"text\":\"Score: 10\"},{\"k\":5,\"tx\":239.67,\"ty\":84.36,\"r\":142},{\"k\":6,\"tx\":218.94,\"ty\":0.45,\"r\":269},{\"k\":7,\"tx\":271.47,\"ty\":75.66,\"r\":197},{\"k\":9,\"tx\":9.52,\"ty\":19.82,\"r\":204},{\"k\":10,\"tx\":200.4,\"ty\":4.29},{\"k\":12,\"tx\":191.72,\"ty\":53.53}],[{\"k\":5,\"tx\":239.8,\"ty\":84.84,\"r\":143},{\"k\":6,\"tx\":218.48,\"ty\":0.26,\"r\":270},{\"k\":7,\"tx\":271.15,\"ty\":76.05,\"r\":198},{\"k\":9,\"tx\":9.13,\"ty\":20.14,\"r\":205},{\"k\":10,\"tx\":200.84,\"ty\":1.82},{\"k\":12,\"tx\":192.16,\"ty\":51.06}],[{\"k\":5,\"tx\":239.93,\"ty\":85.32,\"r\":144},{\"k\":6,\"tx\":218.01,\"ty\":0.08,\"r\":271},{\"k\":7,\"tx\":270.82,\"ty\":76.43,\"r\":199},{\"k\":9,\"tx\":8.74,\"ty\":20.45,\"r\":206},{\"k\":10,\"tx\":201.27,\"ty\":239.36},{\"k\":12,\"tx\":192.59,\"ty\":48.6}],[{\"k\":1,\"children\":[2,3,4,5,6,7,9,12]},{\"k\":5,\"tx\":240.06,\"ty\":85.81,\"r\":145},{\"k\":6,\"tx\":217.55,\"ty\":239.89,\"r\":272},{\"k\":7,\"tx\":270.5,\"ty\":76.81,\"r\":200},{\"k\":9,\"tx\":8.35,\"ty\":20.77,\"r\":207},{\"k\":12,\"tx\":193.02,\"ty\":46.14}],[{\"k\":4,\"r\":-76},{\"k\":5,\"tx\":240.19,\"ty\":86.29,\"r\":146},{\"k\":6,\"tx\":217.08,\"ty\":239.7,\"r\":273},{\"k\":7,\"tx\":270.18,\"ty\":77.19,\"r\":201},{\"k\":9,\"tx\":7.97,\"ty\":21.08,\"r\":208},{\"k\":12,\"tx\":193.46,\"ty\":43.68}],[{\"k\":4,\"r\":-72},{\"k\":5,\"tx\":240.32,\"ty\":86.77,\"r\":147},{\"k\":6,\"tx\":216.62,\"ty\":239.51,\"r\":274},{\"k\":7,\"tx\":269.86,\"ty\":77.58,\"r\":202},{\"k\":9,\"tx\":7.58,\"ty\":21.4,\"r\":209},{\"k\":12,\"tx\":193.89,\"ty\":41.22}],[{\"k\":4,\"r\":-68},{\"k\":5,\"tx\":240.45,\"ty\":87.26,\"r\":148},{\"k\":6,\"tx\":216.16,\"ty\":239.33,\"r\":275},{\"k\":7,\"tx\":269.54,\"ty\":77.96,\"r\":203},{\"k\":9,\"tx\":7.19,\"ty\":21.71,\"r\":210},{\"k\":12,\"tx\":194.33,\"ty\":38.75}],[{\"k\":4,\"r\":-64},{\"k\":5,\"tx\":240.58,\"ty\":87.74,\"r\":149},{\"k\":6,\"tx\":215.69,\"ty\":239.14,\"r\":276},{\"k\":7,\"tx\":269.22,\"ty\":78.34,\"r\":204},{\"k\":9,\"tx\":6.8,\"ty\":22.03,\"r\":211},{\"k\":12,\"tx\":194.76,\"ty\":36.29}],[{\"k\":4,\"r\":-60},{\"k\":5,\"tx\":240.71,\"ty\":88.22,\"r\":150},{\"k\":6,\"tx\":215.23,\"ty\":238.95,\"r\":277},{\"k\":7,\"tx\":268.9,\"ty\":78.73,\"r\":205},{\"k\":9,\"tx\":6.41,\"ty\":22.34,\"r\":212},{\"k\":12,\"tx\":195.19,\"ty\":33.83}],[{\"k\":4,\"r\":-56},{\"k\":5,\"tx\":240.84,\"ty\":88.71,\"r\":151},{\"k\":6,\"tx\":214.77,\"ty\":238.76,\"r\":278},{\"k\":7,\"tx\":268.57,\"ty\":79.11,\"r\":206},{\"k\":9,\"tx\":6.02,\"ty\":22.66,\"r\":213},{\"k\":12,\"tx\":195.63,\"ty\":31.37}],[{\"k\":4,\"r\":-52},{\"k\":5,\"tx\":240.96,\"ty\":89.19,\"r\":152},{\"k\":6,\"tx\":214.3,\"ty\":238.58,\"r\":279},{\"k\":7,\"tx\":268.25,\"ty\":79.49,\"r\":207},{\"k\":9,\"tx\":5.63,\"ty\":22.97,\"r\":214},{\"k\":12,\"tx\":196.06,\"ty\":28.91}],[{\"k\":4,\"r\":-48},{\"k\":5,\"tx\":241.09,\"ty\":89.67,\"r\":153},{\"k\":6,\"tx\":213.84,\"ty\":238.39,\"r\":280},{\"k\":7,\"tx\":267.93,\"ty\":79.88,\"r\":208},{\"k\":9,\"tx\":5.25,\"ty\":23.28,\"r\":215},{\"k\":12,\"tx\":196.5,\"ty\":26.44}],[{\"k\":4,\"r\":-44},{\"k\":5,\"tx\":241.22,\"ty\":90.15,\"r\":154},{\"k\":6,\"tx\":213.38,\"ty\":238.2,\"r\":281},{\"k\":7,\"tx\":267.61,\"ty\":80.26,\"r\":209},{\"k\":9,\"tx\":4.86,\"ty\":23.6,\"r\":216},{\"k\":12,\"tx\":196.93,\"ty\":23.98}],[{\"k\":4,\"r\":-40},{\"k\":5,\"tx\":241.35,\"ty\":90.64,\"r\":155},{\"k\":6,\"tx\":212.91,\"ty\":238.02,\"r\":282},{\"k\":7,\"tx\":267.29,\"ty\":80.64,\"r\":210},{\"k\":9,\"tx\":4.47,\"ty\":23.91,\"r\":217},{\"k\":12,\"tx\":197.36,\"ty\":21.52}],[{\"k\":4,\"r\":-36},{\"k\":5,\"tx\":241.48,\"ty\":91.12,\"r\":156},{\"k\":6,\"tx\":212.45,\"ty\":237.83,\"r\":283},{\"k\":7,\"tx\":266.97,\"ty\":81.02,\"r\":211},{\"k\":9,\"tx\":4.08,\"ty\":24.23,\"r\":218},{\"k\":12,\"tx\":197.8,\"ty\":19.06}],[{\"k\":4,\"r\":-32},{\"k\":5,\"tx\":241.61,\"ty\":91.6,\"r\":157},{\"k\":6,\"tx\":211.99,\"ty\":237.64,\"r\":284},{\"k\":7,\"tx\":266.65,\"ty\":81.41,\"r\":212},{\"k\":9,\"tx\":3.69,\"ty\":24.54,\"r\":219},{\"k\":12,\"tx\":198.23,\"ty\":16.6}],[{\"k\":4,\"r\":-28},{\"k\":5,\"tx\":241.74,\"ty\":92.09,\"r\":158},{\"k\":6,\"tx\":211.52,\"ty\":237.45,\"r\":285},{\"k\":7,\"tx\":266.32,\"ty\":81.79,\"r\":213},{\"k\":9,\"tx\":3.3,\"ty\":24.86,\"r\":220},{\"k\":12,\"tx\":198.67,\"ty\":14.13}],[{\"k\":4,\"r\":-24},{\"k\":5,\"tx\":241.87,\"ty\":92.57,\"r\":159},{\"k\":6,\"tx\":211.06,\"ty\":237.27,\"r\":286},{\"k\":7,\"tx\":266,\"ty\":82.17,\"r\":214},{\"k\":9,\"tx\":2.91,\"ty\":25.17,\"r\":221},{\"k\":12,\"tx\":199.1,\"ty\":11.67}],[{\"k\":4,\"r\":-20},{\"k\":5,\"tx\":242,\"ty\":93.05,\"r\":160},{\"k\":6,\"tx\":210.59,\"ty\":237.08,\"r\":287},{\"k\":7,\"tx\":265.68,\"ty\":82.56,\"r\":215},{\"k\":9,\"tx\":2.53,\"ty\":25.49,\"r\":222},{\"k\":12,\"tx\":199.54,\"ty\":9.21}],[{\"k\":4,\"r\":-16},{\"k\":5,\"tx\":242.13,\"ty\":93.53,\"r\":161},{\"k\":6,\"tx\":210.13,\"ty\":236.89,\"r\":288},{\"k\":7,\"tx\":265.36,\"ty\":82.94,\"r\":216},{\"k\":9,\"tx\":2.14,\"ty\":25.8,\"r\":223},{\"k\":12,\"tx\":199.97,\"ty\":6.75}],[{\"k\":4,\"r\":-12},{\"k\":5,\"tx\":242.26,\"ty\":94.02,\"r\":162},{\"k\":6,\"tx\":209.67,\"ty\":236.7,\"r\":289},{\"k\":7,\"tx\":265.04,\"ty\":83.32,\"r\":217},{\"k\":9,\"tx\":1.75,\"ty\":26.12,\"r\":224},{\"k\":12,\"tx\":200.4,\"ty\":4.29}],[{\"k\":4,\"r\":-8},{\"k\":5,\"tx\":242.39,\"ty\":94.5,\"r\":163},{\"k\":6,\"tx\":209.2,\"ty\":236.52,\"r\":290},{\"k\":7,\"tx\":264.72,\"ty\":83.71,\"r\":218},{\"k\":9,\"tx\":1.36,\"ty\":26.43,\"r\":225},{\"k\":12,\"tx\":200.84,\"ty\":1.82}],[{\"k\":1,\"children\":[2,3,4,5,7,9]},{\"k\":3,\"text\":\"Score: 20\"},{\"k\":4,\"r\":-4},{\"k\":5,\"tx\":242.52,\"ty\":94.98,\"r\":164},{\"k\":7,\"tx\":264.4,\"ty\":84.09,\"r\":219},{\"k\":9,\"tx\":0.97,\"ty\":26.75,\"r\":226}],[{\"k\":4,\"r\":0},{\"k\":5,\"tx\":242.65,\"ty\":95.47,\"r\":165},{\"k\":7,\"tx\":264.07,\"ty\":84.47,\"r\":220},{\"k\":9,\"tx\":0.58,\"ty\":27.06,\"r\":227}],[{\"k\":4,\"r\":4},{\"k\":5,\"tx\":242.78,\"ty\":95.95,\"r\":166},{\"k\":7,\"tx\":263.75,\"ty\":84.86,\"r\":221},{\"k\":9,\"tx\":0.19,\"ty\":27.38,\"r\":228}],[{\"k\":4,\"r\":8},{\"k\":5,\"tx\":242.91,\"ty\":96.43,\"r\":167},{\"k\":7,\"tx\":263.43,\"ty\":85.24,\"r\":222},{\"k\":9,\"tx\":359.81,\"ty\":27.69,\"r\":229}],[{\"k\":4,\"r\":12},{\"k\":5,\"tx\":243.04,\"ty\":96.92,\"r\":168},{\"k\":7,\"tx\":263.11,\"ty\":85.62,\"r\":223},{\"k\":9,\"tx\":359.42,\"ty\":28,\"r\":230}],[{\"k\":4,\"r\":16},{\"k\":5,\"tx\":243.16,\"ty\":97.4,\"r\":169},{\"k\":7,\"tx\":262.79,\"ty\":86,\"r\":224},{\"k\":9,\"tx\":359.03,\"ty\":28.32,\"r\":231}],[{\"k\":4,\"r\":20},{\"k\":5,\"tx\":243.29,\"ty\":97.88,\"r\":170},{\"k\":7,\"tx\":262.47,\"ty\":86.39,\"r\":225},{\"k\":9,\"tx\":358.64,\"ty\":28.63,\"r\":232}],[{\"k\":1,\"children\":[2,3,4,5,7,9,13]},{\"k\":5,\"tx\":243.42,\"ty\":98.36,\"r\":171},{\"k\":7,\"tx\":262.15,\"ty\":86.77,\"r\":226},{\"k\":9,\"tx\":358.25,\"ty\":28.95,\"r\":233},{\"k\":13,\"type\":\"Circle\",\"tx\":182.35,\"ty\":120.86,\"r\":20,\"radius\":3,\"fill\":\"#e0ffff\"}],[{\"k\":5,\"tx\":243.55,\"ty\":98.85,\"r\":172},{\"k\":7,\"tx\":261.82,\"ty\":87.15,\"r\":227},{\"k\":9,\"tx\":357.86,\"ty\":29.26,\"r\":234},{\"k\":13,\"tx\":184.7,\"ty\":121.71}],[{\"k\":5,\"tx\":243.68,\"ty\":99.33,\"r\":173},{\"k\":7,\"tx\":261.5,\"ty\":87.54,\"r\":228},{\"k\":9,\"tx\":357.47,\"ty\":29.58,\"r\":235},{\"k\":13,\"tx\":187.05,\"ty\":122.57}],[{\"k\":5,\"tx\":243.81,\"ty\":99.81,\"r\":174},{\"k\":7,\"tx\":261.18,\"ty\":87.92,\"r\":229},{\"k\":9,\"tx\":357.09,\"ty\":29.89,\"r\":236},{\"k\":13,\"tx\":189.4,\"ty\":123.42}],[{\"k\":5,\"tx\":243.94,\"ty\":100.3,\"r\":175},{\"k\":7,\"tx\":260.86,\"ty\":88.3,\"r\":230},{\"k\":9,\"tx\":356.7,\"ty\":30.21,\"r\":237},{\"k\":13,\"tx\":191.75,\"ty\":124.28}],[{\"k\":5,\"tx\":244.07,\"ty\":100.78,\"r\":176},{\"k\":7,\"tx\":260.54,\"ty\":88.69,\"r\":231},{\"k\":9,\"tx\":356.31,\"ty\":30.52,\"r\":238},{\"k\":13,\"tx\":194.1,\"ty\":125.13}],[{\"k\":5,\"tx\":244.2,\"ty\":101.26,\"r\":177},{\"k\":7,\"tx\":260.22,\"ty\":89.07,\"r\":232},{\"k\":9,\"tx\":355.92,\"ty\":30.84,\"r\":239},{\"k\":13,\"tx\":196.44,\"ty\":125.99}],[{\"k\":5,\"tx\":244.33,\"ty\":101.75,\"r\":178},{\"k\":7,\"tx\":259.9,\"ty\":89.45,\"r\":233},{\"k\":9,\"tx\":355.53,\"ty\":31.15,\"r\":240},{\"k\":13,\"tx\":198.79,\"ty\":126.84}],[{\"k\":5,\"tx\":244.46,\"ty\":102.23,\"r\":179},{\"k\":7,\"tx\":259.58,\"ty\":89.83,\"r\":234},{\"k\":9,\"tx\":355.14,\"ty\":31.47,\"r\":241},{\"k\":13,\"tx\":201.14,\"ty\":127.7}],[{\"k\":5,\"tx\":244.59,\"ty\":102.71,\"r\":180},{\"k\":7,\"tx\":259.25,\"ty\":90.22,\"r\":235},{\"k\":9,\"tx\":354.75,\"ty\":31.78,\"r\":242},{\"k\":13,\"tx\":203.49,\"ty\":128.55}],[{\"k\":5,\"tx\":244.72,\"ty\":103.19,\"r\":181},{\"k\":7,\"tx\":258.93,\"ty\":90.6,\"r\":236},{\"k\":9,\"tx\":354.37,\"ty\":32.1,\"r\":243},{\"k\":13,\"tx\":205.84,\"ty\":129.41}],[{\"k\":5,\"tx\":244.85,\"ty\":103.68,\"r\":182},{\"k\":7,\"tx\":258.61,\"ty\":90.98,\"r\":237},{\"k\":9,\"tx\":353.98,\"ty\":32.41,\"r\":244},{\"k\":13,\"tx\":208.19,\"ty\":130.26}],[{\"k\":5,\"tx\":244.98,\"ty\":104.16,\"r\":183},{\"k\":7,\"tx\":258.29,\"ty\":91.37,\"r\":238},{\"k\":9,\"tx\":353.59,\"ty\":32.72,\"r\":245},{\"k\":13,\"tx\":210.54,\"ty\":131.12}],[{\"k\":5,\"tx\":245.11,\"ty\":104.64,\"r\":184},{\"k\":7,\"tx\":257.97,\"ty\":91.75,\"r\":239},{\"k\":9,\"tx\":353.2,\"ty\":33.04,\"r\":246},{\"k\":13,\"tx\":212.89,\"ty\":131.97}],[{\"k\":5,\"tx\":245.24,\"ty\":105.13,\"r\":185},{\"k\":7,\"tx\":257.65,\"ty\":92.13,\"r\":240},{\"k\":9,\"tx\":352.81,\"ty\":33.35,\"r\":247},{\"k\":13,\"tx\":215.24,\"ty\":132.83}],[{\"k\":5,\"tx\":245.36,\"ty\":105.61,\"r\":186},{\"k\":7,\"tx\":257.33,\"ty\":92.52,\"r\":241},{\"k\":9,\"tx\":352.42,\"ty\":33.67,\"r\":248},{\"k\":13,\"tx\":217.59,\"ty\":133.68}],[{\"k\":5,\"tx\":245.49,\"ty\":106.09,\"r\":187},{\"k\":7,\"tx\":257,\"ty\":92.9,\"r\":242},{\"k\":9,\"tx\":352.03,\"ty\":33.98,\"r\":249},{\"k\":13,\"tx\":219.94,\"ty\":134.54}],[{\"k\":5,\"tx\":245.62,\"ty\":106.57,\"r\":188},{\"k\":7,\"tx\":256.68,\"ty\":93.28,\"r\":243},{\"k\":9,\"tx\":351.65,\"ty\":34.3,\"r\":250},{\"k\":13,\"tx\":222.29,\"ty\":135.39}],[{\"k\":5,\"tx\":245.75,\"ty\":107.06,\"r\":189},{\"k\":7,\"tx\":256.36,\"ty\":93.66,\"r\":244},{\"k\":9,\"tx\":351.26,\"ty\":34.61,\"r\":251},{\"k\":13,\"tx\":224.64,\"ty\":136.25}],[{\"k\":5,\"tx\":245.88,\"ty\":107.54,\"r\":190},{\"k\":7,\"tx\":256.04,\"ty\":94.05,\"r\":245},{\"k\":9,\"tx\":350.87,\"ty\":34.93,\"r\":252},{\"k\":13,\"tx\":226.98,\"ty\":137.1}],[{\"k\":4,\"tx\":180.12,\"ty\":120.04},{\"k\":5,\"tx\":246.01,\"ty\":108.02,\"r\":191},{\"k\":7,\"tx\":255.72,\"ty\":94.43,\"r\":246},{\"k\":9,\"tx\":350.48,\"ty\":35.24,\"r\":253},{\"k\":13,\"tx\":229.33,\"ty\":137.96}],[{\"k\":4,\"tx\":180.35,\"ty\":120.13},{\"k\":5,\"tx\":246.14,\"ty\":108.51,\"r\":192},{\"k\":7,\"tx\":255.4,\"ty\":94.81,\"r\":247},{\"k\":9,\"tx\":350.09,\"ty\":35.56,\"r\":254},{\"k\":13,\"tx\":231.68,\"ty\":138.81}],[{\"k\":4,\"tx\":180.7,\"ty\":120.26},{\"k\":5,\"tx\":246.27,\"ty\":108.99,\"r\":193},{\"k\":7,\"tx\":255.08,\"ty\":95.2,\"r\":248},{\"k\":9,\"tx\":349.7,\"ty\":35.87,\"r\":255},{\"k\":13,\"tx\":234.03,\"ty\":139.67}],[{\"k\":4,\"tx\":181.17,\"ty\":120.43},{\"k\":5,\"tx\":246.4,\"ty\":109.47,\"r\":194},{\"k\":7,\"tx\":254.75,\"ty\":95.58,\"r\":249},{\"k\":9,\"tx\":349.31,\"ty\":36.19,\"r\":256},{\"k\":13,\"tx\":236.38,\"ty\":140.52}],[{\"k\":4,\"tx\":181.76,\"ty\":120.64},{\"k\":5,\"tx\":246.53,\"ty\":109.96,\"r\":195},{\"k\":7,\"tx\":254.43,\"ty\":95.96,\"r\":250},{\"k\":9,\"tx\":348.93,\"ty\":36.5,\"r\":257},{\"k\":13,\"tx\":238.73,\"ty\":141.38}],[{\"k\":4,\"tx\":182.47,\"ty\":120.9},{\"k\":5,\"tx\":246.66,\"ty\":110.44,\"r\":196},{\"k\":7,\"tx\":254.11,\"ty\":96.35,\"r\":251},{\"k\":9,\"tx\":348.54,\"ty\":36.82,\"r\":258},{\"k\":13,\"tx\":241.08,\"ty\":142.23}],[{\"k\":4,\"tx\":183.29,\"ty\":121.2},{\"k\":5,\"tx\":246.79,\"ty\":110.92,\"r\":197},{\"k\":7,\"tx\":253.79,\"ty\":96.73,\"r\":252},{\"k\":9,\"tx\":348.15,\"ty\":37.13,\"r\":259},{\"k\":13,\"tx\":243.43,\"ty\":143.09}],[{\"k\":4,\"tx\":184.23,\"ty\":121.54},{\"k\":5,\"tx\":246.92,\"ty\":111.4,\"r\":198},{\"k\":7,\"tx\":253.47,\"ty\":97.11,\"r\":253},{\"k\":9,\"tx\":347.76,\"ty\":37.44,\"r\":260},{\"k\":13,\"tx\":245.78,\"ty\":143.94}],[{\"k\":4,\"tx\":185.29,\"ty\":121.92},{\"k\":5,\"tx\":247.05,\"ty\":111.89,\"r\":199},{\"k\":7,\"tx\":253.15,\"ty\":97.49,\"r\":254},{\"k\":9,\"tx\":347.37,\"ty\":37.76,\"r\":261},{\"k\":13,\"tx\":248.13,\"ty\":144.8}],[{\"k\":4,\"tx\":186.46,\"ty\":122.35},{\"k\":5,\"tx\":247.18,\"ty\":112.37,\"r\":200},{\"k\":7,\"tx\":252.83,\"ty\":97.88,\"r\":255},{\"k\":9,\"tx\":346.98,\"ty\":38.07,\"r\":262},{\"k\":13,\"tx\":250.48,\"ty\":145.65}],[{\"k\":4,\"tx\":187.64,\"ty\":122.78},{\"k\":5,\"tx\":247.31,\"ty\":112.85,\"r\":201},{\"k\":7,\"tx\":252.5,\"ty\":98.26,\"r\":256},{\"k\":9,\"tx\":346.59,\"ty\":38.39,\"r\":263},{\"k\":13,\"tx\":252.83,\"ty\":146.51}],[{\"k\":4,\"tx\":188.81,\"ty\":123.21},{\"k\":5,\"tx\":247.44,\"ty\":113.34,\"r\":202},{\"k\":7,\"tx\":252.18,\"ty\":98.64,\"r\":257},{\"k\":9,\"tx\":346.21,\"ty\":38.7,\"r\":264},{\"k\":13,\"tx\":255.18,\"ty\":147.36}],[{\"k\":4,\"tx\":189.98,\"ty\":123.63},{\"k\":5,\"tx\":247.56,\"ty\":113.82,\"r\":203},{\"k\":7,\"tx\":251.86,\"ty\":99.03,\"r\":258},{\"k\":9,\"tx\":345.82,\"ty\":39.02,\"r\":265},{\"k\":13,\"tx\":257.52,\"ty\":148.22}],[{\"k\":4,\"tx\":191.16,\"ty\":124.06},{\"k\":5,\"tx\":247.69,\"ty\":114.3,\"r\":204},{\"k\":7,\"tx\":251.54,\"ty\":99.41,\"r\":259},{\"k\":9,\"tx\":345.43,\"ty\":39.33,\"r\":266},{\"k\":13,\"tx\":259.87,\"ty\":149.07}],[{\"k\":4,\"tx\":192.33,\"ty\":124.49},{\"k\":5,\"tx\":247.82,\"ty\":114.79,\"r\":205},{\"k\":7,\"tx\":251.22,\"ty\":99.79,\"r\":260},{\"k\":9,\"tx\":345.04,\"ty\":39.65,\"r\":267},{\"k\":13,\"tx\":262.22,\"ty\":149.93}],[{\"k\":4,\"tx\":193.51,\"ty\":124.92},{\"k\":5,\"tx\":247.95,\"ty\":115.27,\"r\":206},{\"k\":7,\"tx\":250.9,\"ty\":100.18,\"r\":261},{\"k\":9,\"tx\":344.65,\"ty\":39.96,\"r\":268},{\"k\":13,\"tx\":264.57,\"ty\":150.78}],[{\"k\":4,\"tx\":194.68,\"ty\":125.34},{\"k\":5,\"tx\":248.08,\"ty\":115.75,\"r\":207},{\"k\":7,\"tx\":250.58,\"ty\":100.56,\"r\":262},{\"k\":9,\"tx\":344.26,\"ty\":40.28,\"r\":269},{\"k\":13,\"tx\":266.92,\"ty\":151.64}],[{\"k\":4,\"tx\":195.86,\"ty\":125.77},{\"k\":5,\"tx\":248.21,\"ty\":116.23,\"r\":208},{\"k\":7,\"tx\":250.25,\"ty\":100.94,\"r\":263},{\"k\":9,\"tx\":343.87,\"ty\":40.59,\"r\":270},{\"k\":13,\"tx\":269.27,\"ty\":152.49}],[{\"k\":4,\"tx\":197.03,\"ty\":126.2},{\"k\":5,\"tx\":248.34,\"ty\":116.72,\"r\":209},{\"k\":7,\"tx\":249.93,\"ty\":101.32,\"r\":264},{\"k\":9,\"tx\":343.49,\"ty\":40.91,\"r\":271},{\"k\":13,\"tx\":271.62,\"ty\":153.35}],[{\"k\":4,\"tx\":198.21,\"ty\":126.63},{\"k\":5,\"tx\":248.47,\"ty\":117.2,\"r\":210},{\"k\":7,\"tx\":249.61,\"ty\":101.71,\"r\":265},{\"k\":9,\"tx\":343.1,\"ty\":41.22,\"r\":272},{\"k\":13,\"tx\":273.97,\"ty\":154.2}],[{\"k\":4,\"tx\":199.38,\"ty\":127.05},{\"k\":5,\"tx\":248.6,\"ty\":117.68,\"r\":211},{\"k\":7,\"tx\":249.29,\"ty\":102.09,\"r\":266},{\"k\":9,\"tx\":342.71,\"ty\":41.54,\"r\":273},{\"k\":13,\"tx\":276.32,\"ty\":155.06}],[{\"k\":4,\"tx\":200.56,\"ty\":127.48},{\"k\":5,\"tx\":248.73,\"ty\":118.17,\"r\":212},{\"k\":7,\"tx\":248.97,\"ty\":102.47,\"r\":267},{\"k\":9,\"tx\":342.32,\"ty\":41.85,\"r\":274},{\"k\":13,\"tx\":278.67,\"ty\":155.91}],[{\"k\":4,\"tx\":201.73,\"ty\":127.91},{\"k\":5,\"tx\":248.86,\"ty\":118.65,\"r\":213},{\"k\":7,\"tx\":248.65,\"ty\":102.86,\"r\":268},{\"k\":9,\"tx\":341.93,\"ty\":42.16,\"r\":275},{\"k\":13,\"tx\":281.02,\"ty\":156.77}],[{\"k\":4,\"tx\":202.91,\"ty\":128.34},{\"k\":5,\"tx\":248.99,\"ty\":119.13,\"r\":214},{\"k\":7,\"tx\":248.33,\"ty\":103.24,\"r\":269},{\"k\":9,\"tx\":341.54,\"ty\":42.48,\"r\":276},{\"k\":13,\"tx\":283.37,\"ty\":157.62}],[{\"k\":4,\"tx\":204.08,\"ty\":128.76},{\"k\":5,\"tx\":249.12,\"ty\":119.61,\"r\":215},{\"k\":7,\"tx\":248,\"ty\":103.62,\"r\":270},{\"k\":9,\"tx\":341.15,\"ty\":42.79,\"r\":277},{\"k\":13,\"tx\":285.72,\"ty\":158.48}],[{\"k\":4,\"tx\":205.25,\"ty\":129.19},{\"k\":5,\"tx\":249.25,\"ty\":120.1,\"r\":216},{\"k\":7,\"tx\":247.68,\"ty\":104.01,\"r\":271},{\"k\":9,\"tx\":340.77,\"ty\":43.11,\"r\":278},{\"k\":13,\"tx\":288.06,\"ty\":159.33}],[{\"k\":4,\"tx\":206.43,\"ty\":129.62},{\"k\":5,\"tx\":249.38,\"ty\":120.58,\"r\":217},{\"k\":7,\"tx\":247.36,\"ty\":104.39,\"r\":272},{\"k\":9,\"tx\":340.38,\"ty\":43.42,\"r\":279},{\"k\":13,\"tx\":290.41,\"ty\":160.19}],[{\"k\":4,\"tx\":207.6,\"ty\":130.05},{\"k\":5,\"tx\":249.51,\"ty\":121.06,\"r\":218},{\"k\":7,\"tx\":247.04,\"ty\":104.77,\"r\":273},{\"k\":9,\"tx\":339.99,\"ty\":43.74,\"r\":280},{\"k\":13,\"tx\":292.76,\"ty\":161.04}],[{\"k\":4,\"tx\":208.78,\"ty\":130.47},{\"k\":5,\"tx\":249.63,\"ty\":121.55,\"r\":219},{\"k\":7,\"tx\":246.72,\"ty\":105.16,\"r\":274},{\"k\":9,\"tx\":339.6,\"ty\":44.05,\"r\":281},{\"k\":13,\"tx\":295.11,\"ty\":161.9}],[{\"k\":1,\"children\":[2,3,4,5,7,9]},{\"k\":4,\"tx\":209.95,\"ty\":130.9},{\"k\":5,\"tx\":249.76,\"ty\":122.03,\"r\":220},{\"k\":7,\"tx\":246.4,\"ty\":105.54,\"r\":275},{\"k\":9,\"tx\":339.21,\"ty\":44.37,\"r\":282}],[{\"k\":4,\"tx\":211.13,\"ty\":131.33},{\"k\":5,\"tx\":249.89,\"ty\":122.51,\"r\":221},{\"k\":7,\"tx\":246.08,\"ty\":105.92,\"r\":276},{\"k\":9,\"tx\":338.82,\"ty\":44.68,\"r\":283}],[{\"k\":4,\"tx\":212.3,\"ty\":131.76},{\"k\":5,\"tx\":250.02,\"ty\":123,\"r\":222},{\"k\":7,\"tx\":245.76,\"ty\":106.3,\"r\":277},{\"k\":9,\"tx\":338.43,\"ty\":45,\"r\":284}],[{\"k\":4,\"tx\":213.48,\"ty\":132.18},{\"k\":5,\"tx\":250.15,\"ty\":123.48,\"r\":223},{\"k\":7,\"tx\":245.43,\"ty\":106.69,\"r\":278},{\"k\":9,\"tx\":338.05,\"ty\":45.31,\"r\":285}],[{\"k\":4,\"tx\":214.65,\"ty\":132.61},{\"k\":5,\"tx\":250.28,\"ty\":123.96,\"r\":224},{\"k\":7,\"tx\":245.11,\"ty\":107.07,\"r\":279},{\"k\":9,\"tx\":337.66,\"ty\":45.63,\"r\":286}],[{\"k\":4,\"tx\":215.83,\"ty\":133.04},{\"k\":5,\"tx\":250.41,\"ty\":124.44,\"r\":225},{\"k\":7,\"tx\":244.79,\"ty\":107.45,\"r\":280},{\"k\":9,\"tx\":337.27,\"ty\":45.94,\"r\":287}],[{\"k\":4,\"tx\":217,\"ty\":133.47},{\"k\":5,\"tx\":250.54,\"ty\":124.93,\"r\":226},{\"k\":7,\"tx\":244.47,\"ty\":107.84,\"r\":281},{\"k\":9,\"tx\":336.88,\"ty\":46.26,\"r\":288}],[{\"k\":4,\"tx\":218.18,\"ty\":133.89},{\"k\":5,\"tx\":250.67,\"ty\":125.41,\"r\":227},{\"k\":7,\"tx\":244.15,\"ty\":108.22,\"r\":282},{\"k\":9,\"tx\":336.49,\"ty\":46.57,\"r\":289}],[{\"k\":4,\"tx\":219.35,\"ty\":134.32},{\"k\":5,\"tx\":250.8,\"ty\":125.89,\"r\":228},{\"k\":7,\"tx\":243.83,\"ty\":108.6,\"r\":283},{\"k\":9,\"tx\":336.1,\"ty\":46.88,\"r\":290}],[{\"k\":4,\"tx\":220.52,\"ty\":134.75},{\"k\":5,\"tx\":250.93,\"ty\":126.38,\"r\":229},{\"k\":7,\"tx\":243.51,\"ty\":108.99,\"r\":284},{\"k\":9,\"tx\":335.71,\"ty\":47.2,\"r\":291}],[{\"k\":4,\"tx\":221.7,\"ty\":135.18},{\"k\":5,\"tx\":251.06,\"ty\":126.86,\"r\":230},{\"k\":7,\"tx\":243.18,\"ty\":109.37,\"r\":285},{\"k\":9,\"tx\":335.33,\"ty\":47.51,\"r\":292}],[{\"k\":4,\"tx\":222.87,\"ty\":135.6},{\"k\":5,\"tx\":251.19,\"ty\":127.34,\"r\":231},{\"k\":7,\"tx\":242.86,\"ty\":109.75,\"r\":286},{\"k\":9,\"tx\":334.94,\"ty\":47.83,\"r\":293}],[{\"k\":4,\"tx\":224.05,\"ty\":136.03},{\"k\":5,\"tx\":251.32,\"ty\":127.83,\"r\":232},{\"k\":7,\"tx\":242.54,\"ty\":110.13,\"r\":287},{\"k\":9,\"tx\":334.55,\"ty\":48.14,\"r\":294}],[{\"k\":4,\"tx\":225.22,\"ty\":136.46},{\"k\":5,\"tx\":251.45,\"ty\":128.31,\"r\":233},{\"k\":7,\"tx\":242.22,\"ty\":110.52,\"r\":288},{\"k\":9,\"tx\":334.16,\"ty\":48.46,\"r\":295}],[{\"k\":4,\"tx\":226.4,\"ty\":136.89},{\"k\":5,\"tx\":251.58,\"ty\":128.79,\"r\":234},{\"k\":7,\"tx\":241.9,\"ty\":110.9,\"r\":289},{\"k\":9,\"tx\":333.77,\"ty\":48.77,\"r\":296}],[{\"k\":4,\"tx\":227.57,\"ty\":137.31},{\"k\":5,\"tx\":251.71,\"ty\":129.27,\"r\":235},{\"k\":7,\"tx\":241.58,\"ty\":111.28,\"r\":290},{\"k\":9,\"tx\":333.38,\"ty\":49.09,\"r\":297}],[{\"k\":4,\"tx\":228.75,\"ty\":137.74},{\"k\":5,\"tx\":251.83,\"ty\":129.76,\"r\":236},{\"k\":7,\"tx\":241.26,\"ty\":111.67,\"r\":291},{\"k\":9,\"tx\":332.99,\"ty\":49.4,\"r\":298}],[{\"k\":4,\"tx\":229.92,\"ty\":138.17},{\"k\":5,\"tx\":251.96,\"ty\":130.24,\"r\":237},{\"k\":7,\"tx\":240.93,\"ty\":112.05,\"r\":292},{\"k\":9,\"tx\":332.61,\"ty\":49.72,\"r\":299}],[{\"k\":4,\"tx\":231.1,\"ty\":138.6},{\"k\":5,\"tx\":252.09,\"ty\":130.72,\"r\":238},{\"k\":7,\"tx\":240.61,\"ty\":112.43,\"r\":293},{\"k\":9,\"tx\":332.22,\"ty\":50.03,\"r\":300}],[{\"k\":4,\"tx\":232.27,\"ty\":139.02},{\"k\":5,\"tx\":252.22,\"ty\":131.21,\"r\":239},{\"k\":7,\"tx\":240.29,\"ty\":112.82,\"r\":294},{\"k\":9,\"tx\":331.83,\"ty\":50.35,\"r\":301}],[{\"k\":4,\"tx\":233.45,\"ty\":139.45,\"fill\":\"#ff0000\"},{\"k\":5,\"tx\":252.35,\"ty\":131.69,\"r\":240},{\"k\":7,\"tx\":239.97,\"ty\":113.2,\"r\":295},{\"k\":9,\"tx\":331.44,\"ty\":50.66,\"r\":302},{\"k\":3,\"text\":\"Game over! Score: 20\"}],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]}},\"outline\":\"Window \\\"Deep dive\\\"\\n  Pane 360 x 240\\n    Rectangle 360 x 240 at (0, 0), fill #191970\\n    Text \\\"Game over! Score: 20\\\" at (12, 24), fill #ffffff\\n    Polygon (-15, -6) (9, -6) (15, 0) (9, 6) (-15, 6), at (233.4450178071981, 139.45239565164704), rotate 20, fill #ff0000\\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (252.35257122095965, 131.68888066884804), rotate 240, fill #da70d6\\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (239.9700222008575, 113.19866655731516), rotate 295, fill #da70d6\\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (331.43975010271294, 50.66029147951172), rotate 302, fill #da70d6\\nframes run: 270\"}\n```\n\n```output\nScore: 10\nScore: 20\nGame over! Score: 20\n```\n\nTwo pops, new jellyfish from the surface, and a bump. The `key SPACE` after the game over fires nothing. In a challenge below, \"Run with my input\" runs your own game: choose which keys are held and how many frames run, and see where the submarine ends up.\n\n### What section 14.3 covered\n\nThis module built the MOOC's larger application of section 14.3 in its own theme, one idea per step:\n\n- a **Pane** of a fixed size with **shapes** in it: `Polygon`, `Circle`, `Rectangle` and `Text`, moved with `setTranslateX` and `setTranslateY` and turned with `setRotate`\n- **key events** on the scene, the held keys in a `Map<KeyCode, Boolean>`, and a **game loop**, an `AnimationTimer` whose `handle` runs once a frame\n- movement with **Point2D**: a velocity added in every frame, and speeding up where the nose points with `Math.cos` and `Math.sin`\n- one **abstract class** for everything that moves, with subclasses that override `move`\n- **collisions** with `Shape.intersect`, many jellyfish from a **seeded** Random, and stopping the timer\n- **wrapping** at the edges with `%`, using the window's size as constants\n- **bubbles** fired on a key press, marked as not alive and removed with streams, from the list and from the pane\n- **points** in a Text, new jellyfish with a chance in every frame, and a **game over**\n\nThe same structure carries over to many small games: a list of things that move, a loop that moves them and checks what touches what, and keys kept in a map.\n\n### Running it on your own computer\n\nOn your own computer, the same code runs with the real JavaFX, live: about 60 frames a second, with the keys you press while it runs, and the real clock behind `now`. Installing JavaFX is a separate step: the MOOC's exercise templates bring it in through Maven (module 54 names the dependency), and the MOOC's [section 13.1](https://java-programming.mooc.fi/part-13/1-graphical-user-interfaces) has a note for Linux machines. There, holding a key repeats its press after a moment. Turning and speeding up don't notice, since the timer reads them from the map. Firing does: the pressed handler makes the bubble, so on a computer a held Space fires again on every repeat (after a short pause, about 30 a second) while fewer than 4 bubbles are out. Here a held Space fires once, so use `key SPACE` for each shot. If you like, take the game further there: a seed that changes on every run (`new Random()`), sounds (module 52 showed what they need), or levels that get harder. The MOOC's own version of the game is in [its section 14.3](https://java-programming.mooc.fi/part-14/3-larger-application-asteroids). The next module is about libraries, Maven and databases, and ends the course.\n","task":"Points. The starter code is the game of step 7, with bubbles that pop after 50 frames, and it prints `Pop!` for every hit. Make the hits count instead:\n\n1. add a field `points`, 0 at the start, and a Text `score`: `new Text(12, 24, \"Score: 0\")`, filled with `Color.WHITE`, added to the pane right after the water\n2. a hit counts only when the bubble and the jellyfish are both still alive (check that before `collides`); then mark both as not alive as before, add 10 to `points`, set the Text to `Score: ` and the points, and print the same text (in place of `Pop!`)\n\nThe test is the one of step 7's first challenge.\n```\nScore: 10\nScore: 20\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.stream.Collectors;\nimport javafx.animation.AnimationTimer;\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.input.KeyCode;\nimport javafx.scene.layout.Pane;\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Rectangle;\nimport javafx.scene.text.Text;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    public static final int WIDTH = 360;\n    public static final int HEIGHT = 240;\n\n    private Map<KeyCode, Boolean> held = new HashMap<>();\n    private Random random = new Random(16);\n    private List<Jellyfish> jellyfish = new ArrayList<>();\n    private List<Bubble> bubbles = new ArrayList<>();\n\n    @Override\n    public void start(Stage stage) {\n        Pane pane = new Pane();\n        pane.setPrefSize(WIDTH, HEIGHT);\n        pane.getChildren().add(new Rectangle(WIDTH, HEIGHT, Color.MIDNIGHTBLUE));\n\n        Sub sub = new Sub(WIDTH / 2, HEIGHT / 2);\n        pane.getChildren().add(sub.getShape());\n        for (int i = 0; i < 4; i++) {\n            Jellyfish j = new Jellyfish(random.nextInt(WIDTH), random.nextInt(60), random.nextInt(360));\n            jellyfish.add(j);\n            pane.getChildren().add(j.getShape());\n        }\n\n        Scene scene = new Scene(pane);\n        scene.setOnKeyPressed(event -> {\n            held.put(event.getCode(), true);\n            if (event.getCode() == KeyCode.SPACE && bubbles.size() < 4) {\n                Bubble bubble = new Bubble(sub.getShape().getTranslateX(), sub.getShape().getTranslateY(), sub.getShape().getRotate());\n                bubbles.add(bubble);\n                pane.getChildren().add(bubble.getShape());\n            }\n        });\n        scene.setOnKeyReleased(event -> held.put(event.getCode(), false));\n\n        new AnimationTimer() {\n            @Override\n            public void handle(long now) {\n                if (held.getOrDefault(KeyCode.LEFT, false)) {\n                    sub.turn(-4);\n                }\n                if (held.getOrDefault(KeyCode.RIGHT, false)) {\n                    sub.turn(4);\n                }\n                if (held.getOrDefault(KeyCode.UP, false)) {\n                    sub.accelerate(0.125);\n                }\n                sub.move();\n                jellyfish.forEach(j -> j.move());\n                bubbles.forEach(b -> b.move());\n\n                for (Bubble b : bubbles) {\n                    for (Jellyfish j : jellyfish) {\n                        if (b.collides(j)) {\n                            b.setAlive(false);\n                            j.setAlive(false);\n                            System.out.println(\"Pop!\");\n                        }\n                    }\n                }\n                bubbles.stream()\n                        .filter(b -> !b.isAlive())\n                        .forEach(b -> pane.getChildren().remove(b.getShape()));\n                jellyfish.stream()\n                        .filter(j -> !j.isAlive())\n                        .forEach(j -> pane.getChildren().remove(j.getShape()));\n                bubbles = bubbles.stream()\n                        .filter(b -> b.isAlive())\n                        .collect(Collectors.toList());\n                jellyfish = jellyfish.stream()\n                        .filter(j -> j.isAlive())\n                        .collect(Collectors.toList());\n\n                for (Jellyfish j : jellyfish) {\n                    if (sub.collides(j)) {\n                        sub.getShape().setFill(Color.RED);\n                        System.out.println(\"Bump!\");\n                        stop();\n                        break;\n                    }\n                }\n            }\n        }.start();\n\n        stage.setScene(scene);\n        stage.setTitle(\"Deep dive\");\n        stage.show();\n    }\n\n    public static double wrap(double value, double size) {\n        double result = value % size;\n        if (result < 0) {\n            result = result + size;\n        }\n        return result;\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n\n// ==== Mover.java ====\nimport javafx.geometry.Point2D;\nimport javafx.scene.shape.Shape;\n\npublic abstract class Mover {\n    private Shape shape;\n    private Point2D velocity;\n    private boolean alive;\n\n    public Mover(Shape shape, double x, double y) {\n        this.shape = shape;\n        this.shape.setTranslateX(x);\n        this.shape.setTranslateY(y);\n        this.velocity = new Point2D(0, 0);\n        this.alive = true;\n    }\n\n    public Shape getShape() {\n        return shape;\n    }\n\n    public boolean isAlive() {\n        return alive;\n    }\n\n    public void setAlive(boolean alive) {\n        this.alive = alive;\n    }\n\n    public void turn(double degrees) {\n        shape.setRotate(shape.getRotate() + degrees);\n    }\n\n    public void accelerate(double amount) {\n        double angle = Math.toRadians(shape.getRotate());\n        velocity = velocity.add(Math.cos(angle) * amount, Math.sin(angle) * amount);\n    }\n\n    public void move() {\n        shape.setTranslateX(Main.wrap(shape.getTranslateX() + velocity.getX(), Main.WIDTH));\n        shape.setTranslateY(Main.wrap(shape.getTranslateY() + velocity.getY(), Main.HEIGHT));\n    }\n\n    public boolean collides(Mover other) {\n        Shape overlap = Shape.intersect(shape, other.getShape());\n        return overlap.getBoundsInLocal().getWidth() != -1;\n    }\n}\n\n// ==== Sub.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Sub extends Mover {\n\n    public Sub(double x, double y) {\n        super(new Polygon(-15, -6, 9, -6, 15, 0, 9, 6, -15, 6), x, y);\n        getShape().setFill(Color.GOLD);\n    }\n}\n\n// ==== Jellyfish.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Jellyfish extends Mover {\n\n    public Jellyfish(double x, double y, double heading) {\n        super(new Polygon(-10, 0, -6, -8, 0, -10, 6, -8, 10, 0, 7, 10, 3, 2, 0, 10, -3, 2, -7, 10), x, y);\n        getShape().setFill(Color.ORCHID);\n        turn(heading);\n        accelerate(0.5);\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        turn(1);\n    }\n}\n\n// ==== Bubble.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Circle;\n\npublic class Bubble extends Mover {\n    private int age;\n\n    public Bubble(double x, double y, double heading) {\n        super(new Circle(3, Color.LIGHTCYAN), x, y);\n        turn(heading);\n        accelerate(2.5);\n        age = 0;\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        age++;\n        if (age == 50) {\n            setAlive(false);\n        }\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.stream.Collectors;\nimport javafx.animation.AnimationTimer;\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.input.KeyCode;\nimport javafx.scene.layout.Pane;\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Rectangle;\nimport javafx.scene.text.Text;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    public static final int WIDTH = 360;\n    public static final int HEIGHT = 240;\n\n    private Map<KeyCode, Boolean> held = new HashMap<>();\n    private Random random = new Random(16);\n    private List<Jellyfish> jellyfish = new ArrayList<>();\n    private List<Bubble> bubbles = new ArrayList<>();\n    private int points = 0;\n\n    @Override\n    public void start(Stage stage) {\n        Pane pane = new Pane();\n        pane.setPrefSize(WIDTH, HEIGHT);\n        pane.getChildren().add(new Rectangle(WIDTH, HEIGHT, Color.MIDNIGHTBLUE));\n        Text score = new Text(12, 24, \"Score: 0\");\n        score.setFill(Color.WHITE);\n        pane.getChildren().add(score);\n\n        Sub sub = new Sub(WIDTH / 2, HEIGHT / 2);\n        pane.getChildren().add(sub.getShape());\n        for (int i = 0; i < 4; i++) {\n            Jellyfish j = new Jellyfish(random.nextInt(WIDTH), random.nextInt(60), random.nextInt(360));\n            jellyfish.add(j);\n            pane.getChildren().add(j.getShape());\n        }\n\n        Scene scene = new Scene(pane);\n        scene.setOnKeyPressed(event -> {\n            held.put(event.getCode(), true);\n            if (event.getCode() == KeyCode.SPACE && bubbles.size() < 4) {\n                Bubble bubble = new Bubble(sub.getShape().getTranslateX(), sub.getShape().getTranslateY(), sub.getShape().getRotate());\n                bubbles.add(bubble);\n                pane.getChildren().add(bubble.getShape());\n            }\n        });\n        scene.setOnKeyReleased(event -> held.put(event.getCode(), false));\n\n        new AnimationTimer() {\n            @Override\n            public void handle(long now) {\n                if (held.getOrDefault(KeyCode.LEFT, false)) {\n                    sub.turn(-4);\n                }\n                if (held.getOrDefault(KeyCode.RIGHT, false)) {\n                    sub.turn(4);\n                }\n                if (held.getOrDefault(KeyCode.UP, false)) {\n                    sub.accelerate(0.125);\n                }\n                sub.move();\n                jellyfish.forEach(j -> j.move());\n                bubbles.forEach(b -> b.move());\n\n                for (Bubble b : bubbles) {\n                    for (Jellyfish j : jellyfish) {\n                        if (b.isAlive() && j.isAlive() && b.collides(j)) {\n                            b.setAlive(false);\n                            j.setAlive(false);\n                            points += 10;\n                            score.setText(\"Score: \" + points);\n                            System.out.println(\"Score: \" + points);\n                        }\n                    }\n                }\n                bubbles.stream()\n                        .filter(b -> !b.isAlive())\n                        .forEach(b -> pane.getChildren().remove(b.getShape()));\n                jellyfish.stream()\n                        .filter(j -> !j.isAlive())\n                        .forEach(j -> pane.getChildren().remove(j.getShape()));\n                bubbles = bubbles.stream()\n                        .filter(b -> b.isAlive())\n                        .collect(Collectors.toList());\n                jellyfish = jellyfish.stream()\n                        .filter(j -> j.isAlive())\n                        .collect(Collectors.toList());\n\n                for (Jellyfish j : jellyfish) {\n                    if (sub.collides(j)) {\n                        sub.getShape().setFill(Color.RED);\n                        System.out.println(\"Bump!\");\n                        stop();\n                        break;\n                    }\n                }\n            }\n        }.start();\n\n        stage.setScene(scene);\n        stage.setTitle(\"Deep dive\");\n        stage.show();\n    }\n\n    public static double wrap(double value, double size) {\n        double result = value % size;\n        if (result < 0) {\n            result = result + size;\n        }\n        return result;\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n\n// ==== Mover.java ====\nimport javafx.geometry.Point2D;\nimport javafx.scene.shape.Shape;\n\npublic abstract class Mover {\n    private Shape shape;\n    private Point2D velocity;\n    private boolean alive;\n\n    public Mover(Shape shape, double x, double y) {\n        this.shape = shape;\n        this.shape.setTranslateX(x);\n        this.shape.setTranslateY(y);\n        this.velocity = new Point2D(0, 0);\n        this.alive = true;\n    }\n\n    public Shape getShape() {\n        return shape;\n    }\n\n    public boolean isAlive() {\n        return alive;\n    }\n\n    public void setAlive(boolean alive) {\n        this.alive = alive;\n    }\n\n    public void turn(double degrees) {\n        shape.setRotate(shape.getRotate() + degrees);\n    }\n\n    public void accelerate(double amount) {\n        double angle = Math.toRadians(shape.getRotate());\n        velocity = velocity.add(Math.cos(angle) * amount, Math.sin(angle) * amount);\n    }\n\n    public void move() {\n        shape.setTranslateX(Main.wrap(shape.getTranslateX() + velocity.getX(), Main.WIDTH));\n        shape.setTranslateY(Main.wrap(shape.getTranslateY() + velocity.getY(), Main.HEIGHT));\n    }\n\n    public boolean collides(Mover other) {\n        Shape overlap = Shape.intersect(shape, other.getShape());\n        return overlap.getBoundsInLocal().getWidth() != -1;\n    }\n}\n\n// ==== Sub.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Sub extends Mover {\n\n    public Sub(double x, double y) {\n        super(new Polygon(-15, -6, 9, -6, 15, 0, 9, 6, -15, 6), x, y);\n        getShape().setFill(Color.GOLD);\n    }\n}\n\n// ==== Jellyfish.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Jellyfish extends Mover {\n\n    public Jellyfish(double x, double y, double heading) {\n        super(new Polygon(-10, 0, -6, -8, 0, -10, 6, -8, 10, 0, 7, 10, 3, 2, 0, 10, -3, 2, -7, 10), x, y);\n        getShape().setFill(Color.ORCHID);\n        turn(heading);\n        accelerate(0.5);\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        turn(1);\n    }\n}\n\n// ==== Bubble.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Circle;\n\npublic class Bubble extends Mover {\n    private int age;\n\n    public Bubble(double x, double y, double heading) {\n        super(new Circle(3, Color.LIGHTCYAN), x, y);\n        turn(heading);\n        accelerate(2.5);\n        age = 0;\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        age++;\n        if (age == 50) {\n            setAlive(false);\n        }\n    }\n}\n","hints":["The field is `private int points = 0;`. In `start`, after the water: `Text score = new Text(12, 24, \"Score: 0\");`, `score.setFill(Color.WHITE);` and `pane.getChildren().add(score);`.","The check becomes `if (b.isAlive() && j.isAlive() && b.collides(j))`, and inside it, after the two `setAlive(false)` lines: `points += 10;`, `score.setText(\"Score: \" + points);` and the print."],"tests":[{"name":"Test 1","stdin":"","expect":"Score: 10\nScore: 20","hidden":false,"events":["press key LEFT","frames 20","release key LEFT","key SPACE","frames 10","key SPACE","frames 10","key SPACE","frames 30","press key RIGHT","frames 30","release key RIGHT","key SPACE","frames 40"],"window":{"windows":[{"title":"Deep dive","scene":{"width":360,"height":240,"onKeyPressed":true,"onKeyReleased":true,"root":{"n":1,"type":"Pane","f":1,"prefWidth":360,"prefHeight":240,"children":[{"n":2,"type":"Rectangle","f":2,"x":0,"y":0,"width":360,"height":240,"fill":"#191970"},{"n":3,"type":"Text","f":3,"text":"Score: 20","x":12,"y":24,"fill":"#ffffff"},{"n":4,"type":"Polygon","f":4,"translateX":180,"translateY":120,"rotate":40,"points":[-15,-6,9,-6,15,0,9,6,-15,6],"fill":"#ffd700"},{"n":5,"type":"Polygon","f":5,"translateX":249.11733315717788,"translateY":119.61480784023462,"rotate":215,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":6,"type":"Polygon","f":7,"translateX":248.0048673219392,"translateY":103.62311101832802,"rotate":270,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":7,"type":"Circle","f":12,"translateX":256.6044443118983,"translateY":184.27876096865367,"rotate":40,"centerX":0,"centerY":0,"radius":3,"fill":"#e0ffff"}]}}}],"problems":[],"frames":{"count":140,"list":[]}},"outline":"Window \"Deep dive\"\n  Pane 360 x 240\n    Rectangle 360 x 240 at (0, 0), fill #191970\n    Text \"Score: 20\" at (12, 24), fill #ffffff\n    Polygon (-15, -6) (9, -6) (15, 0) (9, 6) (-15, 6), at (180, 120), rotate 40, fill #ffd700\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (249.11733315717788, 119.61480784023462), rotate 215, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (248.0048673219392, 103.62311101832802), rotate 270, fill #da70d6\n    Circle radius 3 at (0, 0), translate (256.6044443118983, 184.27876096865367), rotate 40, fill #e0ffff\nframes run: 140"},{"name":"Test 2","stdin":"","expect":"","hidden":true,"events":[],"window":{"windows":[{"title":"Deep dive","scene":{"width":360,"height":240,"onKeyPressed":true,"onKeyReleased":true,"root":{"n":1,"type":"Pane","prefWidth":360,"prefHeight":240,"children":[{"n":2,"type":"Rectangle","x":0,"y":0,"width":360,"height":240,"fill":"#191970"},{"n":3,"type":"Text","text":"Score: 0","x":12,"y":24,"fill":"#ffffff"},{"n":4,"type":"Polygon","translateX":180,"translateY":120,"points":[-15,-6,9,-6,15,0,9,6,-15,6],"fill":"#ffd700"},{"n":5,"type":"Polygon","translateX":231,"translateY":52,"rotate":75,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":6,"type":"Polygon","translateX":250,"translateY":13,"rotate":202,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":7,"type":"Polygon","translateX":293,"translateY":50,"rotate":130,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":8,"type":"Polygon","translateX":155,"translateY":11,"rotate":20,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"}]}}}],"problems":[]},"outline":"Window \"Deep dive\"\n  Pane 360 x 240\n    Rectangle 360 x 240 at (0, 0), fill #191970\n    Text \"Score: 0\" at (12, 24), fill #ffffff\n    Polygon (-15, -6) (9, -6) (15, 0) (9, 6) (-15, 6), at (180, 120), fill #ffd700\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (231, 52), rotate 75, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (250, 13), rotate 202, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (293, 50), rotate 130, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (155, 11), rotate 20, fill #da70d6"},{"name":"Test 3","stdin":"","expect":"Score: 10","hidden":true,"events":["press key RIGHT","frames 12","release key RIGHT","key SPACE","frames 5","key SPACE","frames 5","press key LEFT","frames 30","release key LEFT","key SPACE","frames 80","key SPACE","frames 30"],"window":{"windows":[{"title":"Deep dive","scene":{"width":360,"height":240,"onKeyPressed":true,"onKeyReleased":true,"root":{"n":1,"type":"Pane","f":1,"prefWidth":360,"prefHeight":240,"children":[{"n":2,"type":"Rectangle","f":2,"x":0,"y":0,"width":360,"height":240,"fill":"#191970"},{"n":3,"type":"Text","f":3,"text":"Score: 10","x":12,"y":24,"fill":"#ffffff"},{"n":4,"type":"Polygon","f":4,"translateX":180,"translateY":120,"rotate":-72,"points":[-15,-6,9,-6,15,0,9,6,-15,6],"fill":"#ffd700"},{"n":5,"type":"Polygon","f":5,"translateX":251.96434265330583,"translateY":130.2399919294144,"rotate":237,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":6,"type":"Polygon","f":6,"translateX":174.8981077800887,"translateY":222.65686593331014,"rotate":364,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":7,"type":"Polygon","f":7,"translateX":240.9342036153873,"translateY":112.0495998926367,"rotate":292,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":8,"type":"Circle","f":12,"translateX":203.17627457812137,"translateY":48.67076127786348,"rotate":-72,"centerX":0,"centerY":0,"radius":3,"fill":"#e0ffff"}]}}}],"problems":[],"frames":{"count":162,"list":[]}},"outline":"Window \"Deep dive\"\n  Pane 360 x 240\n    Rectangle 360 x 240 at (0, 0), fill #191970\n    Text \"Score: 10\" at (12, 24), fill #ffffff\n    Polygon (-15, -6) (9, -6) (15, 0) (9, 6) (-15, 6), at (180, 120), rotate -72, fill #ffd700\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (251.96434265330583, 130.2399919294144), rotate 237, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (174.8981077800887, 222.65686593331014), rotate 364, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (240.9342036153873, 112.0495998926367), rotate 292, fill #da70d6\n    Circle radius 3 at (0, 0), translate (203.17627457812137, 48.67076127786348), rotate -72, fill #e0ffff\nframes run: 162"}],"require":[],"forbid":[],"more":[{"task":"New jellyfish from the surface. The starter code is the game with points. In `handle`, right after the lines that remove what popped, add the new jellyfish:\n\n- if `random.nextDouble()` is less than 0.02, make a jellyfish at x `random.nextInt(WIDTH)`, y 0, with the heading `random.nextInt(360)` (take the numbers in that order: the chance, x, heading)\n- add it to the list and its shape to the pane, but only if it doesn't collide with the submarine\n\nUse the field `random` that placed the first jellyfish. The test runs the game of the lesson's example.\n```\nScore: 10\nScore: 20\nBump!\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.stream.Collectors;\nimport javafx.animation.AnimationTimer;\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.input.KeyCode;\nimport javafx.scene.layout.Pane;\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Rectangle;\nimport javafx.scene.text.Text;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    public static final int WIDTH = 360;\n    public static final int HEIGHT = 240;\n\n    private Map<KeyCode, Boolean> held = new HashMap<>();\n    private Random random = new Random(16);\n    private List<Jellyfish> jellyfish = new ArrayList<>();\n    private List<Bubble> bubbles = new ArrayList<>();\n    private int points = 0;\n\n    @Override\n    public void start(Stage stage) {\n        Pane pane = new Pane();\n        pane.setPrefSize(WIDTH, HEIGHT);\n        pane.getChildren().add(new Rectangle(WIDTH, HEIGHT, Color.MIDNIGHTBLUE));\n        Text score = new Text(12, 24, \"Score: 0\");\n        score.setFill(Color.WHITE);\n        pane.getChildren().add(score);\n\n        Sub sub = new Sub(WIDTH / 2, HEIGHT / 2);\n        pane.getChildren().add(sub.getShape());\n        for (int i = 0; i < 4; i++) {\n            Jellyfish j = new Jellyfish(random.nextInt(WIDTH), random.nextInt(60), random.nextInt(360));\n            jellyfish.add(j);\n            pane.getChildren().add(j.getShape());\n        }\n\n        Scene scene = new Scene(pane);\n        scene.setOnKeyPressed(event -> {\n            held.put(event.getCode(), true);\n            if (event.getCode() == KeyCode.SPACE && bubbles.size() < 4) {\n                Bubble bubble = new Bubble(sub.getShape().getTranslateX(), sub.getShape().getTranslateY(), sub.getShape().getRotate());\n                bubbles.add(bubble);\n                pane.getChildren().add(bubble.getShape());\n            }\n        });\n        scene.setOnKeyReleased(event -> held.put(event.getCode(), false));\n\n        new AnimationTimer() {\n            @Override\n            public void handle(long now) {\n                if (held.getOrDefault(KeyCode.LEFT, false)) {\n                    sub.turn(-4);\n                }\n                if (held.getOrDefault(KeyCode.RIGHT, false)) {\n                    sub.turn(4);\n                }\n                if (held.getOrDefault(KeyCode.UP, false)) {\n                    sub.accelerate(0.125);\n                }\n                sub.move();\n                jellyfish.forEach(j -> j.move());\n                bubbles.forEach(b -> b.move());\n\n                for (Bubble b : bubbles) {\n                    for (Jellyfish j : jellyfish) {\n                        if (b.isAlive() && j.isAlive() && b.collides(j)) {\n                            b.setAlive(false);\n                            j.setAlive(false);\n                            points += 10;\n                            score.setText(\"Score: \" + points);\n                            System.out.println(\"Score: \" + points);\n                        }\n                    }\n                }\n                bubbles.stream()\n                        .filter(b -> !b.isAlive())\n                        .forEach(b -> pane.getChildren().remove(b.getShape()));\n                jellyfish.stream()\n                        .filter(j -> !j.isAlive())\n                        .forEach(j -> pane.getChildren().remove(j.getShape()));\n                bubbles = bubbles.stream()\n                        .filter(b -> b.isAlive())\n                        .collect(Collectors.toList());\n                jellyfish = jellyfish.stream()\n                        .filter(j -> j.isAlive())\n                        .collect(Collectors.toList());\n\n                for (Jellyfish j : jellyfish) {\n                    if (sub.collides(j)) {\n                        sub.getShape().setFill(Color.RED);\n                        System.out.println(\"Bump!\");\n                        stop();\n                        break;\n                    }\n                }\n            }\n        }.start();\n\n        stage.setScene(scene);\n        stage.setTitle(\"Deep dive\");\n        stage.show();\n    }\n\n    public static double wrap(double value, double size) {\n        double result = value % size;\n        if (result < 0) {\n            result = result + size;\n        }\n        return result;\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n\n// ==== Mover.java ====\nimport javafx.geometry.Point2D;\nimport javafx.scene.shape.Shape;\n\npublic abstract class Mover {\n    private Shape shape;\n    private Point2D velocity;\n    private boolean alive;\n\n    public Mover(Shape shape, double x, double y) {\n        this.shape = shape;\n        this.shape.setTranslateX(x);\n        this.shape.setTranslateY(y);\n        this.velocity = new Point2D(0, 0);\n        this.alive = true;\n    }\n\n    public Shape getShape() {\n        return shape;\n    }\n\n    public boolean isAlive() {\n        return alive;\n    }\n\n    public void setAlive(boolean alive) {\n        this.alive = alive;\n    }\n\n    public void turn(double degrees) {\n        shape.setRotate(shape.getRotate() + degrees);\n    }\n\n    public void accelerate(double amount) {\n        double angle = Math.toRadians(shape.getRotate());\n        velocity = velocity.add(Math.cos(angle) * amount, Math.sin(angle) * amount);\n    }\n\n    public void move() {\n        shape.setTranslateX(Main.wrap(shape.getTranslateX() + velocity.getX(), Main.WIDTH));\n        shape.setTranslateY(Main.wrap(shape.getTranslateY() + velocity.getY(), Main.HEIGHT));\n    }\n\n    public boolean collides(Mover other) {\n        Shape overlap = Shape.intersect(shape, other.getShape());\n        return overlap.getBoundsInLocal().getWidth() != -1;\n    }\n}\n\n// ==== Sub.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Sub extends Mover {\n\n    public Sub(double x, double y) {\n        super(new Polygon(-15, -6, 9, -6, 15, 0, 9, 6, -15, 6), x, y);\n        getShape().setFill(Color.GOLD);\n    }\n}\n\n// ==== Jellyfish.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Jellyfish extends Mover {\n\n    public Jellyfish(double x, double y, double heading) {\n        super(new Polygon(-10, 0, -6, -8, 0, -10, 6, -8, 10, 0, 7, 10, 3, 2, 0, 10, -3, 2, -7, 10), x, y);\n        getShape().setFill(Color.ORCHID);\n        turn(heading);\n        accelerate(0.5);\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        turn(1);\n    }\n}\n\n// ==== Bubble.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Circle;\n\npublic class Bubble extends Mover {\n    private int age;\n\n    public Bubble(double x, double y, double heading) {\n        super(new Circle(3, Color.LIGHTCYAN), x, y);\n        turn(heading);\n        accelerate(2.5);\n        age = 0;\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        age++;\n        if (age == 50) {\n            setAlive(false);\n        }\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.stream.Collectors;\nimport javafx.animation.AnimationTimer;\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.input.KeyCode;\nimport javafx.scene.layout.Pane;\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Rectangle;\nimport javafx.scene.text.Text;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    public static final int WIDTH = 360;\n    public static final int HEIGHT = 240;\n\n    private Map<KeyCode, Boolean> held = new HashMap<>();\n    private Random random = new Random(16);\n    private List<Jellyfish> jellyfish = new ArrayList<>();\n    private List<Bubble> bubbles = new ArrayList<>();\n    private int points = 0;\n\n    @Override\n    public void start(Stage stage) {\n        Pane pane = new Pane();\n        pane.setPrefSize(WIDTH, HEIGHT);\n        pane.getChildren().add(new Rectangle(WIDTH, HEIGHT, Color.MIDNIGHTBLUE));\n        Text score = new Text(12, 24, \"Score: 0\");\n        score.setFill(Color.WHITE);\n        pane.getChildren().add(score);\n\n        Sub sub = new Sub(WIDTH / 2, HEIGHT / 2);\n        pane.getChildren().add(sub.getShape());\n        for (int i = 0; i < 4; i++) {\n            Jellyfish j = new Jellyfish(random.nextInt(WIDTH), random.nextInt(60), random.nextInt(360));\n            jellyfish.add(j);\n            pane.getChildren().add(j.getShape());\n        }\n\n        Scene scene = new Scene(pane);\n        scene.setOnKeyPressed(event -> {\n            held.put(event.getCode(), true);\n            if (event.getCode() == KeyCode.SPACE && bubbles.size() < 4) {\n                Bubble bubble = new Bubble(sub.getShape().getTranslateX(), sub.getShape().getTranslateY(), sub.getShape().getRotate());\n                bubbles.add(bubble);\n                pane.getChildren().add(bubble.getShape());\n            }\n        });\n        scene.setOnKeyReleased(event -> held.put(event.getCode(), false));\n\n        new AnimationTimer() {\n            @Override\n            public void handle(long now) {\n                if (held.getOrDefault(KeyCode.LEFT, false)) {\n                    sub.turn(-4);\n                }\n                if (held.getOrDefault(KeyCode.RIGHT, false)) {\n                    sub.turn(4);\n                }\n                if (held.getOrDefault(KeyCode.UP, false)) {\n                    sub.accelerate(0.125);\n                }\n                sub.move();\n                jellyfish.forEach(j -> j.move());\n                bubbles.forEach(b -> b.move());\n\n                for (Bubble b : bubbles) {\n                    for (Jellyfish j : jellyfish) {\n                        if (b.isAlive() && j.isAlive() && b.collides(j)) {\n                            b.setAlive(false);\n                            j.setAlive(false);\n                            points += 10;\n                            score.setText(\"Score: \" + points);\n                            System.out.println(\"Score: \" + points);\n                        }\n                    }\n                }\n                bubbles.stream()\n                        .filter(b -> !b.isAlive())\n                        .forEach(b -> pane.getChildren().remove(b.getShape()));\n                jellyfish.stream()\n                        .filter(j -> !j.isAlive())\n                        .forEach(j -> pane.getChildren().remove(j.getShape()));\n                bubbles = bubbles.stream()\n                        .filter(b -> b.isAlive())\n                        .collect(Collectors.toList());\n                jellyfish = jellyfish.stream()\n                        .filter(j -> j.isAlive())\n                        .collect(Collectors.toList());\n\n                if (random.nextDouble() < 0.02) {\n                    Jellyfish newcomer = new Jellyfish(random.nextInt(WIDTH), 0, random.nextInt(360));\n                    if (!newcomer.collides(sub)) {\n                        jellyfish.add(newcomer);\n                        pane.getChildren().add(newcomer.getShape());\n                    }\n                }\n\n                for (Jellyfish j : jellyfish) {\n                    if (sub.collides(j)) {\n                        sub.getShape().setFill(Color.RED);\n                        System.out.println(\"Bump!\");\n                        stop();\n                        break;\n                    }\n                }\n            }\n        }.start();\n\n        stage.setScene(scene);\n        stage.setTitle(\"Deep dive\");\n        stage.show();\n    }\n\n    public static double wrap(double value, double size) {\n        double result = value % size;\n        if (result < 0) {\n            result = result + size;\n        }\n        return result;\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n\n// ==== Mover.java ====\nimport javafx.geometry.Point2D;\nimport javafx.scene.shape.Shape;\n\npublic abstract class Mover {\n    private Shape shape;\n    private Point2D velocity;\n    private boolean alive;\n\n    public Mover(Shape shape, double x, double y) {\n        this.shape = shape;\n        this.shape.setTranslateX(x);\n        this.shape.setTranslateY(y);\n        this.velocity = new Point2D(0, 0);\n        this.alive = true;\n    }\n\n    public Shape getShape() {\n        return shape;\n    }\n\n    public boolean isAlive() {\n        return alive;\n    }\n\n    public void setAlive(boolean alive) {\n        this.alive = alive;\n    }\n\n    public void turn(double degrees) {\n        shape.setRotate(shape.getRotate() + degrees);\n    }\n\n    public void accelerate(double amount) {\n        double angle = Math.toRadians(shape.getRotate());\n        velocity = velocity.add(Math.cos(angle) * amount, Math.sin(angle) * amount);\n    }\n\n    public void move() {\n        shape.setTranslateX(Main.wrap(shape.getTranslateX() + velocity.getX(), Main.WIDTH));\n        shape.setTranslateY(Main.wrap(shape.getTranslateY() + velocity.getY(), Main.HEIGHT));\n    }\n\n    public boolean collides(Mover other) {\n        Shape overlap = Shape.intersect(shape, other.getShape());\n        return overlap.getBoundsInLocal().getWidth() != -1;\n    }\n}\n\n// ==== Sub.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Sub extends Mover {\n\n    public Sub(double x, double y) {\n        super(new Polygon(-15, -6, 9, -6, 15, 0, 9, 6, -15, 6), x, y);\n        getShape().setFill(Color.GOLD);\n    }\n}\n\n// ==== Jellyfish.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Jellyfish extends Mover {\n\n    public Jellyfish(double x, double y, double heading) {\n        super(new Polygon(-10, 0, -6, -8, 0, -10, 6, -8, 10, 0, 7, 10, 3, 2, 0, 10, -3, 2, -7, 10), x, y);\n        getShape().setFill(Color.ORCHID);\n        turn(heading);\n        accelerate(0.5);\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        turn(1);\n    }\n}\n\n// ==== Bubble.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Circle;\n\npublic class Bubble extends Mover {\n    private int age;\n\n    public Bubble(double x, double y, double heading) {\n        super(new Circle(3, Color.LIGHTCYAN), x, y);\n        turn(heading);\n        accelerate(2.5);\n        age = 0;\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        age++;\n        if (age == 50) {\n            setAlive(false);\n        }\n    }\n}\n","hints":["`if (random.nextDouble() < 0.02) { ... }`, and inside it `Jellyfish newcomer = new Jellyfish(random.nextInt(WIDTH), 0, random.nextInt(360));`.","Then `if (!newcomer.collides(sub)) { jellyfish.add(newcomer); pane.getChildren().add(newcomer.getShape()); }`. The order of the random calls matters, since every call takes the next number."],"tests":[{"name":"Test 1","stdin":"","expect":"Score: 10\nScore: 20\nBump!","hidden":false,"events":["press key LEFT","frames 20","release key LEFT","key SPACE","frames 10","key SPACE","frames 10","key SPACE","frames 30","press key RIGHT","frames 25","release key RIGHT","key SPACE","frames 20","press key UP","frames 10","release key UP","frames 140","key SPACE","frames 5"],"window":{"windows":[{"title":"Deep dive","scene":{"width":360,"height":240,"onKeyPressed":true,"onKeyReleased":true,"root":{"n":1,"type":"Pane","f":1,"prefWidth":360,"prefHeight":240,"children":[{"n":2,"type":"Rectangle","f":2,"x":0,"y":0,"width":360,"height":240,"fill":"#191970"},{"n":3,"type":"Text","f":3,"text":"Score: 20","x":12,"y":24,"fill":"#ffffff"},{"n":4,"type":"Polygon","f":4,"translateX":233.4450178071981,"translateY":139.45239565164704,"rotate":20,"points":[-15,-6,9,-6,15,0,9,6,-15,6],"fill":"#ff0000"},{"n":5,"type":"Polygon","f":5,"translateX":252.35257122095965,"translateY":131.68888066884804,"rotate":240,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":6,"type":"Polygon","f":7,"translateX":239.9700222008575,"translateY":113.19866655731516,"rotate":295,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":7,"type":"Polygon","f":9,"translateX":331.43975010271294,"translateY":50.66029147951172,"rotate":302,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":8,"type":"Circle","f":14,"translateX":233.4450178071981,"translateY":139.45239565164704,"rotate":20,"centerX":0,"centerY":0,"radius":3,"fill":"#e0ffff"}]}}}],"problems":[],"frames":{"count":270,"list":[]}},"outline":"Window \"Deep dive\"\n  Pane 360 x 240\n    Rectangle 360 x 240 at (0, 0), fill #191970\n    Text \"Score: 20\" at (12, 24), fill #ffffff\n    Polygon (-15, -6) (9, -6) (15, 0) (9, 6) (-15, 6), at (233.4450178071981, 139.45239565164704), rotate 20, fill #ff0000\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (252.35257122095965, 131.68888066884804), rotate 240, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (239.9700222008575, 113.19866655731516), rotate 295, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (331.43975010271294, 50.66029147951172), rotate 302, fill #da70d6\n    Circle radius 3 at (0, 0), translate (233.4450178071981, 139.45239565164704), rotate 20, fill #e0ffff\nframes run: 270"},{"name":"Test 2","stdin":"","expect":"","hidden":true,"events":["frames 200"],"window":{"windows":[{"title":"Deep dive","scene":{"width":360,"height":240,"onKeyPressed":true,"onKeyReleased":true,"root":{"n":1,"type":"Pane","f":1,"prefWidth":360,"prefHeight":240,"children":[{"n":2,"type":"Rectangle","f":2,"x":0,"y":0,"width":360,"height":240,"fill":"#191970"},{"n":3,"type":"Text","f":3,"text":"Score: 0","x":12,"y":24,"fill":"#ffffff"},{"n":4,"type":"Polygon","f":4,"translateX":180,"translateY":120,"points":[-15,-6,9,-6,15,0,9,6,-15,6],"fill":"#ffd700"},{"n":5,"type":"Polygon","f":5,"translateX":256.8819045102541,"translateY":148.5925826289072,"rotate":275,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":6,"type":"Polygon","f":6,"translateX":157.2816145433194,"translateY":215.5393406584074,"rotate":402,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":7,"type":"Polygon","f":7,"translateX":228.72123903134312,"translateY":126.60444431189717,"rotate":330,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":8,"type":"Polygon","f":8,"translateX":248.96926207859337,"translateY":45.20201433256693,"rotate":220,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":9,"type":"Polygon","f":9,"translateX":317.8396957772155,"translateY":61.673398322883756,"rotate":337,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":10,"type":"Polygon","f":10,"translateX":88.70633909777092,"translateY":238.14589803375043,"rotate":354,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":11,"type":"Polygon","f":11,"translateX":32.97260947684137,"translateY":239.47735768366186,"rotate":364,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"}]}}}],"problems":[],"frames":{"count":200,"list":[]}},"outline":"Window \"Deep dive\"\n  Pane 360 x 240\n    Rectangle 360 x 240 at (0, 0), fill #191970\n    Text \"Score: 0\" at (12, 24), fill #ffffff\n    Polygon (-15, -6) (9, -6) (15, 0) (9, 6) (-15, 6), at (180, 120), fill #ffd700\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (256.8819045102541, 148.5925826289072), rotate 275, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (157.2816145433194, 215.5393406584074), rotate 402, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (228.72123903134312, 126.60444431189717), rotate 330, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (248.96926207859337, 45.20201433256693), rotate 220, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (317.8396957772155, 61.673398322883756), rotate 337, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (88.70633909777092, 238.14589803375043), rotate 354, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (32.97260947684137, 239.47735768366186), rotate 364, fill #da70d6\nframes run: 200"},{"name":"Test 3","stdin":"","expect":"Score: 10","hidden":true,"events":["press key DOWN","frames 5","press key RIGHT","frames 30","key SPACE","frames 40","release key RIGHT","key SPACE","frames 100"],"window":{"windows":[{"title":"Deep dive","scene":{"width":360,"height":240,"onKeyPressed":true,"onKeyReleased":true,"root":{"n":1,"type":"Pane","f":1,"prefWidth":360,"prefHeight":240,"children":[{"n":2,"type":"Rectangle","f":2,"x":0,"y":0,"width":360,"height":240,"fill":"#191970"},{"n":3,"type":"Text","f":3,"text":"Score: 10","x":12,"y":24,"fill":"#ffffff"},{"n":4,"type":"Polygon","f":4,"translateX":180,"translateY":120,"rotate":280,"points":[-15,-6,9,-6,15,0,9,6,-15,6],"fill":"#ffd700"},{"n":5,"type":"Polygon","f":5,"translateX":253.64666644647235,"translateY":136.51850980029351,"rotate":250,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":6,"type":"Polygon","f":6,"translateX":168.87141272540447,"translateY":220.22192307610658,"rotate":377,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":7,"type":"Polygon","f":7,"translateX":236.75608415242482,"translateY":117.02888877291002,"rotate":305,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":8,"type":"Polygon","f":9,"translateX":327.55402029542796,"translateY":53.80689343476087,"rotate":312,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"}]}}}],"problems":[],"frames":{"count":175,"list":[]}},"outline":"Window \"Deep dive\"\n  Pane 360 x 240\n    Rectangle 360 x 240 at (0, 0), fill #191970\n    Text \"Score: 10\" at (12, 24), fill #ffffff\n    Polygon (-15, -6) (9, -6) (15, 0) (9, 6) (-15, 6), at (180, 120), rotate 280, fill #ffd700\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (253.64666644647235, 136.51850980029351), rotate 250, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (168.87141272540447, 220.22192307610658), rotate 377, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (236.75608415242482, 117.02888877291002), rotate 305, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (327.55402029542796, 53.80689343476087), rotate 312, fill #da70d6\nframes run: 175"}],"require":[],"forbid":[]},{"task":"Game over. When the submarine bumps into a jellyfish, the starter code turns it red, prints `Bump!` and stops the timer, but the keys still work: Space still fires bubbles from a stopped game. Add a field `over`, `false` at the start. When the submarine bumps into a jellyfish: set `over` to `true`, turn the submarine red, set the Text to `Game over! Score: ` and the points, print the same text (in place of `Bump!`), stop the timer and leave the loop. And the pressed handler does nothing at all once `over` is `true`.\n\nThe test is the lesson's example: after the bump, Space is pressed and 5 more frames run.\n```\nScore: 10\nScore: 20\nGame over! Score: 20\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.stream.Collectors;\nimport javafx.animation.AnimationTimer;\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.input.KeyCode;\nimport javafx.scene.layout.Pane;\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Rectangle;\nimport javafx.scene.text.Text;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    public static final int WIDTH = 360;\n    public static final int HEIGHT = 240;\n\n    private Map<KeyCode, Boolean> held = new HashMap<>();\n    private Random random = new Random(16);\n    private List<Jellyfish> jellyfish = new ArrayList<>();\n    private List<Bubble> bubbles = new ArrayList<>();\n    private int points = 0;\n\n    @Override\n    public void start(Stage stage) {\n        Pane pane = new Pane();\n        pane.setPrefSize(WIDTH, HEIGHT);\n        pane.getChildren().add(new Rectangle(WIDTH, HEIGHT, Color.MIDNIGHTBLUE));\n        Text score = new Text(12, 24, \"Score: 0\");\n        score.setFill(Color.WHITE);\n        pane.getChildren().add(score);\n\n        Sub sub = new Sub(WIDTH / 2, HEIGHT / 2);\n        pane.getChildren().add(sub.getShape());\n        for (int i = 0; i < 4; i++) {\n            Jellyfish j = new Jellyfish(random.nextInt(WIDTH), random.nextInt(60), random.nextInt(360));\n            jellyfish.add(j);\n            pane.getChildren().add(j.getShape());\n        }\n\n        Scene scene = new Scene(pane);\n        scene.setOnKeyPressed(event -> {\n            held.put(event.getCode(), true);\n            if (event.getCode() == KeyCode.SPACE && bubbles.size() < 4) {\n                Bubble bubble = new Bubble(sub.getShape().getTranslateX(), sub.getShape().getTranslateY(), sub.getShape().getRotate());\n                bubbles.add(bubble);\n                pane.getChildren().add(bubble.getShape());\n            }\n        });\n        scene.setOnKeyReleased(event -> held.put(event.getCode(), false));\n\n        new AnimationTimer() {\n            @Override\n            public void handle(long now) {\n                if (held.getOrDefault(KeyCode.LEFT, false)) {\n                    sub.turn(-4);\n                }\n                if (held.getOrDefault(KeyCode.RIGHT, false)) {\n                    sub.turn(4);\n                }\n                if (held.getOrDefault(KeyCode.UP, false)) {\n                    sub.accelerate(0.125);\n                }\n                sub.move();\n                jellyfish.forEach(j -> j.move());\n                bubbles.forEach(b -> b.move());\n\n                for (Bubble b : bubbles) {\n                    for (Jellyfish j : jellyfish) {\n                        if (b.isAlive() && j.isAlive() && b.collides(j)) {\n                            b.setAlive(false);\n                            j.setAlive(false);\n                            points += 10;\n                            score.setText(\"Score: \" + points);\n                            System.out.println(\"Score: \" + points);\n                        }\n                    }\n                }\n                bubbles.stream()\n                        .filter(b -> !b.isAlive())\n                        .forEach(b -> pane.getChildren().remove(b.getShape()));\n                jellyfish.stream()\n                        .filter(j -> !j.isAlive())\n                        .forEach(j -> pane.getChildren().remove(j.getShape()));\n                bubbles = bubbles.stream()\n                        .filter(b -> b.isAlive())\n                        .collect(Collectors.toList());\n                jellyfish = jellyfish.stream()\n                        .filter(j -> j.isAlive())\n                        .collect(Collectors.toList());\n\n                if (random.nextDouble() < 0.02) {\n                    Jellyfish newcomer = new Jellyfish(random.nextInt(WIDTH), 0, random.nextInt(360));\n                    if (!newcomer.collides(sub)) {\n                        jellyfish.add(newcomer);\n                        pane.getChildren().add(newcomer.getShape());\n                    }\n                }\n\n                for (Jellyfish j : jellyfish) {\n                    if (sub.collides(j)) {\n                        sub.getShape().setFill(Color.RED);\n                        System.out.println(\"Bump!\");\n                        stop();\n                        break;\n                    }\n                }\n            }\n        }.start();\n\n        stage.setScene(scene);\n        stage.setTitle(\"Deep dive\");\n        stage.show();\n    }\n\n    public static double wrap(double value, double size) {\n        double result = value % size;\n        if (result < 0) {\n            result = result + size;\n        }\n        return result;\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n\n// ==== Mover.java ====\nimport javafx.geometry.Point2D;\nimport javafx.scene.shape.Shape;\n\npublic abstract class Mover {\n    private Shape shape;\n    private Point2D velocity;\n    private boolean alive;\n\n    public Mover(Shape shape, double x, double y) {\n        this.shape = shape;\n        this.shape.setTranslateX(x);\n        this.shape.setTranslateY(y);\n        this.velocity = new Point2D(0, 0);\n        this.alive = true;\n    }\n\n    public Shape getShape() {\n        return shape;\n    }\n\n    public boolean isAlive() {\n        return alive;\n    }\n\n    public void setAlive(boolean alive) {\n        this.alive = alive;\n    }\n\n    public void turn(double degrees) {\n        shape.setRotate(shape.getRotate() + degrees);\n    }\n\n    public void accelerate(double amount) {\n        double angle = Math.toRadians(shape.getRotate());\n        velocity = velocity.add(Math.cos(angle) * amount, Math.sin(angle) * amount);\n    }\n\n    public void move() {\n        shape.setTranslateX(Main.wrap(shape.getTranslateX() + velocity.getX(), Main.WIDTH));\n        shape.setTranslateY(Main.wrap(shape.getTranslateY() + velocity.getY(), Main.HEIGHT));\n    }\n\n    public boolean collides(Mover other) {\n        Shape overlap = Shape.intersect(shape, other.getShape());\n        return overlap.getBoundsInLocal().getWidth() != -1;\n    }\n}\n\n// ==== Sub.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Sub extends Mover {\n\n    public Sub(double x, double y) {\n        super(new Polygon(-15, -6, 9, -6, 15, 0, 9, 6, -15, 6), x, y);\n        getShape().setFill(Color.GOLD);\n    }\n}\n\n// ==== Jellyfish.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Jellyfish extends Mover {\n\n    public Jellyfish(double x, double y, double heading) {\n        super(new Polygon(-10, 0, -6, -8, 0, -10, 6, -8, 10, 0, 7, 10, 3, 2, 0, 10, -3, 2, -7, 10), x, y);\n        getShape().setFill(Color.ORCHID);\n        turn(heading);\n        accelerate(0.5);\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        turn(1);\n    }\n}\n\n// ==== Bubble.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Circle;\n\npublic class Bubble extends Mover {\n    private int age;\n\n    public Bubble(double x, double y, double heading) {\n        super(new Circle(3, Color.LIGHTCYAN), x, y);\n        turn(heading);\n        accelerate(2.5);\n        age = 0;\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        age++;\n        if (age == 50) {\n            setAlive(false);\n        }\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.stream.Collectors;\nimport javafx.animation.AnimationTimer;\nimport javafx.application.Application;\nimport javafx.scene.Scene;\nimport javafx.scene.input.KeyCode;\nimport javafx.scene.layout.Pane;\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Rectangle;\nimport javafx.scene.text.Text;\nimport javafx.stage.Stage;\n\npublic class Main extends Application {\n    public static final int WIDTH = 360;\n    public static final int HEIGHT = 240;\n\n    private Map<KeyCode, Boolean> held = new HashMap<>();\n    private Random random = new Random(16);\n    private List<Jellyfish> jellyfish = new ArrayList<>();\n    private List<Bubble> bubbles = new ArrayList<>();\n    private int points = 0;\n    private boolean over = false;\n\n    @Override\n    public void start(Stage stage) {\n        Pane pane = new Pane();\n        pane.setPrefSize(WIDTH, HEIGHT);\n        pane.getChildren().add(new Rectangle(WIDTH, HEIGHT, Color.MIDNIGHTBLUE));\n        Text score = new Text(12, 24, \"Score: 0\");\n        score.setFill(Color.WHITE);\n        pane.getChildren().add(score);\n\n        Sub sub = new Sub(WIDTH / 2, HEIGHT / 2);\n        pane.getChildren().add(sub.getShape());\n        for (int i = 0; i < 4; i++) {\n            Jellyfish j = new Jellyfish(random.nextInt(WIDTH), random.nextInt(60), random.nextInt(360));\n            jellyfish.add(j);\n            pane.getChildren().add(j.getShape());\n        }\n\n        Scene scene = new Scene(pane);\n        scene.setOnKeyPressed(event -> {\n            if (over) {\n                return;\n            }\n            held.put(event.getCode(), true);\n            if (event.getCode() == KeyCode.SPACE && bubbles.size() < 4) {\n                Bubble bubble = new Bubble(sub.getShape().getTranslateX(), sub.getShape().getTranslateY(), sub.getShape().getRotate());\n                bubbles.add(bubble);\n                pane.getChildren().add(bubble.getShape());\n            }\n        });\n        scene.setOnKeyReleased(event -> held.put(event.getCode(), false));\n\n        new AnimationTimer() {\n            @Override\n            public void handle(long now) {\n                if (held.getOrDefault(KeyCode.LEFT, false)) {\n                    sub.turn(-4);\n                }\n                if (held.getOrDefault(KeyCode.RIGHT, false)) {\n                    sub.turn(4);\n                }\n                if (held.getOrDefault(KeyCode.UP, false)) {\n                    sub.accelerate(0.125);\n                }\n                sub.move();\n                jellyfish.forEach(j -> j.move());\n                bubbles.forEach(b -> b.move());\n\n                for (Bubble b : bubbles) {\n                    for (Jellyfish j : jellyfish) {\n                        if (b.isAlive() && j.isAlive() && b.collides(j)) {\n                            b.setAlive(false);\n                            j.setAlive(false);\n                            points += 10;\n                            score.setText(\"Score: \" + points);\n                            System.out.println(\"Score: \" + points);\n                        }\n                    }\n                }\n                bubbles.stream()\n                        .filter(b -> !b.isAlive())\n                        .forEach(b -> pane.getChildren().remove(b.getShape()));\n                jellyfish.stream()\n                        .filter(j -> !j.isAlive())\n                        .forEach(j -> pane.getChildren().remove(j.getShape()));\n                bubbles = bubbles.stream()\n                        .filter(b -> b.isAlive())\n                        .collect(Collectors.toList());\n                jellyfish = jellyfish.stream()\n                        .filter(j -> j.isAlive())\n                        .collect(Collectors.toList());\n\n                if (random.nextDouble() < 0.02) {\n                    Jellyfish newcomer = new Jellyfish(random.nextInt(WIDTH), 0, random.nextInt(360));\n                    if (!newcomer.collides(sub)) {\n                        jellyfish.add(newcomer);\n                        pane.getChildren().add(newcomer.getShape());\n                    }\n                }\n\n                for (Jellyfish j : jellyfish) {\n                    if (sub.collides(j)) {\n                        over = true;\n                        sub.getShape().setFill(Color.RED);\n                        score.setText(\"Game over! Score: \" + points);\n                        System.out.println(\"Game over! Score: \" + points);\n                        stop();\n                        break;\n                    }\n                }\n            }\n        }.start();\n\n        stage.setScene(scene);\n        stage.setTitle(\"Deep dive\");\n        stage.show();\n    }\n\n    public static double wrap(double value, double size) {\n        double result = value % size;\n        if (result < 0) {\n            result = result + size;\n        }\n        return result;\n    }\n\n    public static void main(String[] args) {\n        launch(Main.class);\n    }\n}\n\n// ==== Mover.java ====\nimport javafx.geometry.Point2D;\nimport javafx.scene.shape.Shape;\n\npublic abstract class Mover {\n    private Shape shape;\n    private Point2D velocity;\n    private boolean alive;\n\n    public Mover(Shape shape, double x, double y) {\n        this.shape = shape;\n        this.shape.setTranslateX(x);\n        this.shape.setTranslateY(y);\n        this.velocity = new Point2D(0, 0);\n        this.alive = true;\n    }\n\n    public Shape getShape() {\n        return shape;\n    }\n\n    public boolean isAlive() {\n        return alive;\n    }\n\n    public void setAlive(boolean alive) {\n        this.alive = alive;\n    }\n\n    public void turn(double degrees) {\n        shape.setRotate(shape.getRotate() + degrees);\n    }\n\n    public void accelerate(double amount) {\n        double angle = Math.toRadians(shape.getRotate());\n        velocity = velocity.add(Math.cos(angle) * amount, Math.sin(angle) * amount);\n    }\n\n    public void move() {\n        shape.setTranslateX(Main.wrap(shape.getTranslateX() + velocity.getX(), Main.WIDTH));\n        shape.setTranslateY(Main.wrap(shape.getTranslateY() + velocity.getY(), Main.HEIGHT));\n    }\n\n    public boolean collides(Mover other) {\n        Shape overlap = Shape.intersect(shape, other.getShape());\n        return overlap.getBoundsInLocal().getWidth() != -1;\n    }\n}\n\n// ==== Sub.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Sub extends Mover {\n\n    public Sub(double x, double y) {\n        super(new Polygon(-15, -6, 9, -6, 15, 0, 9, 6, -15, 6), x, y);\n        getShape().setFill(Color.GOLD);\n    }\n}\n\n// ==== Jellyfish.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Polygon;\n\npublic class Jellyfish extends Mover {\n\n    public Jellyfish(double x, double y, double heading) {\n        super(new Polygon(-10, 0, -6, -8, 0, -10, 6, -8, 10, 0, 7, 10, 3, 2, 0, 10, -3, 2, -7, 10), x, y);\n        getShape().setFill(Color.ORCHID);\n        turn(heading);\n        accelerate(0.5);\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        turn(1);\n    }\n}\n\n// ==== Bubble.java ====\nimport javafx.scene.paint.Color;\nimport javafx.scene.shape.Circle;\n\npublic class Bubble extends Mover {\n    private int age;\n\n    public Bubble(double x, double y, double heading) {\n        super(new Circle(3, Color.LIGHTCYAN), x, y);\n        turn(heading);\n        accelerate(2.5);\n        age = 0;\n    }\n\n    @Override\n    public void move() {\n        super.move();\n        age++;\n        if (age == 50) {\n            setAlive(false);\n        }\n    }\n}\n","hints":["The field is `private boolean over = false;`. The pressed handler starts with `if (over) { return; }`: a `return` in a lambda leaves the lambda.","In the bump check: `over = true;`, `sub.getShape().setFill(Color.RED);`, `score.setText(\"Game over! Score: \" + points);`, the print, `stop();` and `break;`."],"tests":[{"name":"Test 1","stdin":"","expect":"Score: 10\nScore: 20\nGame over! Score: 20","hidden":false,"events":["press key LEFT","frames 20","release key LEFT","key SPACE","frames 10","key SPACE","frames 10","key SPACE","frames 30","press key RIGHT","frames 25","release key RIGHT","key SPACE","frames 20","press key UP","frames 10","release key UP","frames 140","key SPACE","frames 5"],"window":{"windows":[{"title":"Deep dive","scene":{"width":360,"height":240,"onKeyPressed":true,"onKeyReleased":true,"root":{"n":1,"type":"Pane","f":1,"prefWidth":360,"prefHeight":240,"children":[{"n":2,"type":"Rectangle","f":2,"x":0,"y":0,"width":360,"height":240,"fill":"#191970"},{"n":3,"type":"Text","f":3,"text":"Game over! Score: 20","x":12,"y":24,"fill":"#ffffff"},{"n":4,"type":"Polygon","f":4,"translateX":233.4450178071981,"translateY":139.45239565164704,"rotate":20,"points":[-15,-6,9,-6,15,0,9,6,-15,6],"fill":"#ff0000"},{"n":5,"type":"Polygon","f":5,"translateX":252.35257122095965,"translateY":131.68888066884804,"rotate":240,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":6,"type":"Polygon","f":7,"translateX":239.9700222008575,"translateY":113.19866655731516,"rotate":295,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":7,"type":"Polygon","f":9,"translateX":331.43975010271294,"translateY":50.66029147951172,"rotate":302,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"}]}}}],"problems":[],"frames":{"count":270,"list":[]}},"outline":"Window \"Deep dive\"\n  Pane 360 x 240\n    Rectangle 360 x 240 at (0, 0), fill #191970\n    Text \"Game over! Score: 20\" at (12, 24), fill #ffffff\n    Polygon (-15, -6) (9, -6) (15, 0) (9, 6) (-15, 6), at (233.4450178071981, 139.45239565164704), rotate 20, fill #ff0000\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (252.35257122095965, 131.68888066884804), rotate 240, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (239.9700222008575, 113.19866655731516), rotate 295, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (331.43975010271294, 50.66029147951172), rotate 302, fill #da70d6\nframes run: 270"},{"name":"Test 2","stdin":"","expect":"Score: 10\nScore: 20\nGame over! Score: 20","hidden":true,"events":["press key LEFT","frames 20","release key LEFT","key SPACE","frames 10","key SPACE","frames 10","key SPACE","frames 30","press key RIGHT","frames 25","release key RIGHT","key SPACE","frames 20","press key UP","frames 10","release key UP","frames 140","press key LEFT","key SPACE","frames 10"],"window":{"windows":[{"title":"Deep dive","scene":{"width":360,"height":240,"onKeyPressed":true,"onKeyReleased":true,"root":{"n":1,"type":"Pane","f":1,"prefWidth":360,"prefHeight":240,"children":[{"n":2,"type":"Rectangle","f":2,"x":0,"y":0,"width":360,"height":240,"fill":"#191970"},{"n":3,"type":"Text","f":3,"text":"Game over! Score: 20","x":12,"y":24,"fill":"#ffffff"},{"n":4,"type":"Polygon","f":4,"translateX":233.4450178071981,"translateY":139.45239565164704,"rotate":20,"points":[-15,-6,9,-6,15,0,9,6,-15,6],"fill":"#ff0000"},{"n":5,"type":"Polygon","f":5,"translateX":252.35257122095965,"translateY":131.68888066884804,"rotate":240,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":6,"type":"Polygon","f":7,"translateX":239.9700222008575,"translateY":113.19866655731516,"rotate":295,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":7,"type":"Polygon","f":9,"translateX":331.43975010271294,"translateY":50.66029147951172,"rotate":302,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"}]}}}],"problems":[],"frames":{"count":275,"list":[]}},"outline":"Window \"Deep dive\"\n  Pane 360 x 240\n    Rectangle 360 x 240 at (0, 0), fill #191970\n    Text \"Game over! Score: 20\" at (12, 24), fill #ffffff\n    Polygon (-15, -6) (9, -6) (15, 0) (9, 6) (-15, 6), at (233.4450178071981, 139.45239565164704), rotate 20, fill #ff0000\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (252.35257122095965, 131.68888066884804), rotate 240, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (239.9700222008575, 113.19866655731516), rotate 295, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (331.43975010271294, 50.66029147951172), rotate 302, fill #da70d6\nframes run: 275"},{"name":"Test 3","stdin":"","expect":"","hidden":true,"events":["frames 60"],"window":{"windows":[{"title":"Deep dive","scene":{"width":360,"height":240,"onKeyPressed":true,"onKeyReleased":true,"root":{"n":1,"type":"Pane","f":1,"prefWidth":360,"prefHeight":240,"children":[{"n":2,"type":"Rectangle","f":2,"x":0,"y":0,"width":360,"height":240,"fill":"#191970"},{"n":3,"type":"Text","f":3,"text":"Score: 0","x":12,"y":24,"fill":"#ffffff"},{"n":4,"type":"Polygon","f":4,"translateX":180,"translateY":120,"points":[-15,-6,9,-6,15,0,9,6,-15,6],"fill":"#ffd700"},{"n":5,"type":"Polygon","f":5,"translateX":238.76457135307624,"translateY":80.97777478867198,"rotate":135,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":6,"type":"Polygon","f":6,"translateX":222.18448436299582,"translateY":1.7618021975226412,"rotate":262,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":7,"type":"Polygon","f":7,"translateX":273.7163717094022,"translateY":72.98133329356915,"rotate":190,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":8,"type":"Polygon","f":8,"translateX":183.190778623578,"translateY":21.26060429977008,"rotate":80,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"},{"n":9,"type":"Polygon","f":9,"translateX":12.239913079204776,"translateY":17.620970949395453,"rotate":197,"points":[-10,0,-6,-8,0,-10,6,-8,10,0,7,10,3,2,0,10,-3,2,-7,10],"fill":"#da70d6"}]}}}],"problems":[],"frames":{"count":60,"list":[]}},"outline":"Window \"Deep dive\"\n  Pane 360 x 240\n    Rectangle 360 x 240 at (0, 0), fill #191970\n    Text \"Score: 0\" at (12, 24), fill #ffffff\n    Polygon (-15, -6) (9, -6) (15, 0) (9, 6) (-15, 6), at (180, 120), fill #ffd700\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (238.76457135307624, 80.97777478867198), rotate 135, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (222.18448436299582, 1.7618021975226412), rotate 262, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (273.7163717094022, 72.98133329356915), rotate 190, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (183.190778623578, 21.26060429977008), rotate 80, fill #da70d6\n    Polygon (-10, 0) (-6, -8) (0, -10) (6, -8) (10, 0) (7, 10) (3, 2) (0, 10) (-3, 2) (-7, 10), at (12.239913079204776, 17.620970949395453), rotate 197, fill #da70d6\nframes run: 60"}],"require":[],"forbid":[]}]}