{"id":"randomness-chances","slug":"decimals-and-chances","title":"Decimal numbers and chances","text":"`nextInt` gives whole numbers. For decimal numbers, and for things that should happen with a given chance, there's `nextDouble`.\n\n### nextDouble\n\n`random.nextDouble()` returns a random `double` from 0.0 up to, but not including, 1.0. Every value in between is as likely as any other:\n\n```java\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random(3);\n        for (int i = 0; i < 4; i++) {\n            System.out.println(random.nextDouble());\n        }\n    }\n}\n```\n\n```output\n0.731057369148862\n0.07099203475193139\n0.06712000939049956\n0.768156984078079\n```\n\nTo get a decimal number in another range, stretch it and move it, as with `nextInt`. Multiplying by 3.0 spreads the numbers out from 0.0 up to 3.0, and adding 2.0 moves them to 2.0 up to 5.0. A reaction game that waits a random time before it shows its signal, so that players can't count along:\n\n```java\ndouble waitSeconds = 2.0 + random.nextDouble() * 3.0;\n```\n\nFor a range from `low` up to `high`, multiply by `high - low` and add `low`.\n\n### A chance\n\nHow do you make something happen 30% of the time? Draw a `nextDouble()` and compare it with 0.3. The numbers are spread evenly from 0.0 to 1.0, so 30% of them are below 0.3:\n\n```java\nif (random.nextDouble() < 0.3) {\n    System.out.println(\"You found a treasure!\");\n}\n```\n\nWith a seed, you can see how close it gets:\n\n```java\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random(5);\n        int treasures = 0;\n        for (int i = 0; i < 10000; i++) {\n            if (random.nextDouble() < 0.3) {\n                treasures++;\n            }\n        }\n        System.out.println(treasures + \" treasures on 10000 squares\");\n    }\n}\n```\n\n```output\n3014 treasures on 10000 squares\n```\n\nAbout 3000, but not exactly: random results wobble around what you expect. The more tries, the smaller the wobble is compared with the whole.\n\n- `random.nextDouble() < 0.05` is true 5% of the time, and `random.nextDouble() < 1.0` always.\n- Whole numbers work too: `random.nextInt(100) < 30` is true for 0 to 29, which is 30 of the 100 numbers.\n- For a 50-50 choice, such as a coin flip, `random.nextBoolean()` returns `true` or `false`, each half the time.\n\n### Several outcomes\n\nA board game's chance square sends you 2 squares ahead half the time, gives you another roll 30% of the time, and makes you miss a turn the other 20%. To choose between several outcomes, draw **one** number and split the range from 0.0 to 1.0 into parts:\n\n```java\npublic static String chanceSquare(Random random) {\n    double draw = random.nextDouble();\n    if (draw < 0.5) {\n        return \"move 2 squares ahead\";\n    } else if (draw < 0.8) {\n        return \"roll again\";\n    } else {\n        return \"miss a turn\";\n    }\n}\n```\n\n- 0.0 to 0.5 is half of the range: 50% for moving ahead.\n- 0.5 to 0.8 is 0.3 of it: 30% for another roll. The `else if` is only reached when the draw is 0.5 or more, so its test is `< 0.8`, which is 0.5 + 0.3, not `< 0.3`.\n- The rest, 0.8 to 1.0, is 20% for missing a turn.\n\nDraw the number once, before the `if`. With a new `random.nextDouble()` in each test, the second test would only be reached half the time, and then be true 80% of that time: another roll 40% of the time instead of 30%.\n\n### Math.random()\n\n`Math.random()` returns a random double from 0.0 up to 1.0, just like `nextDouble()`. It needs no import and no object, which makes it handy in a quick program:\n\n```java\nif (Math.random() < 0.3) {\n    System.out.println(\"You found a treasure!\");\n}\n```\n\nBehind the scenes, Java creates one Random for `Math.random()` the first time it's called, without a seed, and you can't give it one. So a program built on `Math.random()` can't repeat its numbers, and its exact output can't be tested. For anything you want to test, pass a Random around instead.\n\nTo get a whole number from `Math.random()`, multiply it and cast the result to `int`. A cast to `int` drops the decimals: `(int) 5.83` is 5. So a die roll is:\n\n```java\nint roll = (int) (Math.random() * 6) + 1;\n```\n\n`Math.random() * 6` is from 0.0 up to 6.0, the cast turns it into a whole number from 0 to 5, and adding 1 makes it 1 to 6. The parentheses around `Math.random() * 6` matter. Like the cast to `double` in module 4, a cast applies to the value right after it: `(int) Math.random() * 6` casts `Math.random()` alone, which is below 1.0 and so always becomes 0, and 0 * 6 is 0.\n","task":"A board game has bonus squares: landing on one gives you a bonus 25% of the time. Fill in the blanks so that `bonus` returns `true` with that chance, using `nextDouble`. `main` lands on 10000 bonus squares, with a seeded Random, and prints how many gave a bonus:\n\n```\nBonus on 2506 of 10000 squares\n```\n","kind":"fill","seed":"import java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random(23);\n        int bonuses = 0;\n        for (int i = 0; i < 10000; i++) {\n            if (bonus(random)) {\n                bonuses++;\n            }\n        }\n        System.out.println(\"Bonus on \" + bonuses + \" of 10000 squares\");\n    }\n\n    public static boolean bonus(Random random) {\n        return random.[[nextDouble]]() < [[0.25]];\n    }\n}\n","solution":"import java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random(23);\n        int bonuses = 0;\n        for (int i = 0; i < 10000; i++) {\n            if (bonus(random)) {\n                bonuses++;\n            }\n        }\n        System.out.println(\"Bonus on \" + bonuses + \" of 10000 squares\");\n    }\n\n    public static boolean bonus(Random random) {\n        return random.nextDouble() < 0.25;\n    }\n}\n","hints":["The method that gives a decimal number from 0.0 up to 1.0 is `nextDouble`.","25% of the numbers from 0.0 to 1.0 are below 0.25."],"tests":[{"name":"10000 squares, seed 23","stdin":"","expect":"Bonus on 2506 of 10000 squares","hidden":false},{"name":"Test 2","stdin":"","call":"Random random = new Random();\nint bonuses = 0;\nfor (int i = 0; i < 20000; i++) {\n    if (bonus(random)) {\n        bonuses++;\n    }\n}\nSystem.out.println(\"between 22% and 28%: \" + (bonuses > 4400 && bonuses < 5600));\n","expect":"between 22% and 28%: true","hidden":true}],"require":[],"forbid":[],"more":[{"task":"A reaction game waits a random time before it shows `GO!`, so that players can't count along. Write the method `waitSeconds()`, which returns a random `double` from 1.5 up to 4.0 seconds (4.0 itself left out), using `Math.random()`.\n\nThe check calls it 10000 times. It prints whether every wait was in the range, and whether the waits filled the range, with some below 1.6 seconds and some above 3.9:\n\n```\nall from 1.5 up to 4.0: true\nsome below 1.6: true\nsome above 3.9: true\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(\"Get ready...\");\n        System.out.println(\"Waiting \" + waitSeconds() + \" seconds\");\n        System.out.println(\"GO!\");\n    }\n\n    public static double waitSeconds() {\n        return 0.0;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(\"Get ready...\");\n        System.out.println(\"Waiting \" + waitSeconds() + \" seconds\");\n        System.out.println(\"GO!\");\n    }\n\n    public static double waitSeconds() {\n        return 1.5 + Math.random() * 2.5;\n    }\n}\n","hints":["The range is 4.0 - 1.5 = 2.5 seconds wide, so multiply `Math.random()` by 2.5. That gives 0.0 up to 2.5.","Then add 1.5, the shortest wait: `return 1.5 + Math.random() * 2.5;`"],"tests":[{"name":"Test 1","stdin":"","call":"boolean inRange = true;\nboolean low = false;\nboolean high = false;\nfor (int i = 0; i < 10000; i++) {\n    double wait = waitSeconds();\n    if (wait < 1.5 || wait >= 4.0) {\n        inRange = false;\n    }\n    if (wait < 1.6) {\n        low = true;\n    }\n    if (wait > 3.9) {\n        high = true;\n    }\n}\nSystem.out.println(\"all from 1.5 up to 4.0: \" + inRange);\nSystem.out.println(\"some below 1.6: \" + low);\nSystem.out.println(\"some above 3.9: \" + high);\n","expect":"all from 1.5 up to 4.0: true\nsome below 1.6: true\nsome above 3.9: true","hidden":false},{"name":"Test 2","stdin":"","call":"double total = 0;\nfor (int i = 0; i < 10000; i++) {\n    total += waitSeconds();\n}\ndouble average = total / 10000;\nSystem.out.println(\"average between 2.65 and 2.85: \" + (average > 2.65 && average < 2.85));\n","expect":"average between 2.65 and 2.85: true","hidden":true}],"require":[{"pattern":"Math\\.random\\s*\\(","message":"Use `Math.random()` for the random part."}],"forbid":[]},{"task":"A capsule machine at a fair gives a `sticker` 50% of the time, a `keychain` 25% of the time, a `badge` 20% of the time and a `plush toy` the other 5%. In `PrizeMachine.java`, write the class `PrizeMachine` with a constructor `PrizeMachine(Random random)` and a method `prize()`. `prize()` draws one `nextDouble()` from the machine's Random and returns the prize: a sticker below 0.5, a keychain below 0.75, a badge below 0.95, and a plush toy otherwise. The check runs:\n\n```java\nPrizeMachine machine = new PrizeMachine(new Random(24));\nfor (int i = 0; i < 6; i++) {\n    System.out.println(machine.prize());\n}\n```\n\nand expects:\n\n```\nkeychain\nbadge\nsticker\nsticker\nkeychain\nplush toy\n```\n","kind":"code","seed":"// ==== PrizeMachine.java ====\nimport java.util.Random;\n\npublic class PrizeMachine {\n\n}\n\n// ==== Main.java ====\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        PrizeMachine machine = new PrizeMachine(new Random(24));\n        for (int i = 0; i < 6; i++) {\n            System.out.println(machine.prize());\n        }\n    }\n}\n","solution":"// ==== PrizeMachine.java ====\nimport java.util.Random;\n\npublic class PrizeMachine {\n    private Random random;\n\n    public PrizeMachine(Random random) {\n        this.random = random;\n    }\n\n    public String prize() {\n        double draw = this.random.nextDouble();\n        if (draw < 0.5) {\n            return \"sticker\";\n        } else if (draw < 0.75) {\n            return \"keychain\";\n        } else if (draw < 0.95) {\n            return \"badge\";\n        } else {\n            return \"plush toy\";\n        }\n    }\n}\n\n// ==== Main.java ====\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        PrizeMachine machine = new PrizeMachine(new Random(24));\n        for (int i = 0; i < 6; i++) {\n            System.out.println(machine.prize());\n        }\n    }\n}\n","hints":["Keep the Random in an instance variable. In `prize()`, draw the number once: `double draw = this.random.nextDouble();`","Then `if (draw < 0.5)` gives a sticker, `else if (draw < 0.75)` a keychain (0.5 + 0.25), `else if (draw < 0.95)` a badge (0.75 + 0.2), and `else` a plush toy."],"tests":[{"name":"Test 1","stdin":"","call":"PrizeMachine machine = new PrizeMachine(new Random(24));\nfor (int i = 0; i < 6; i++) {\n    System.out.println(machine.prize());\n}\n","expect":"keychain\nbadge\nsticker\nsticker\nkeychain\nplush toy","hidden":false},{"name":"Test 2","stdin":"","call":"PrizeMachine machine = new PrizeMachine(new Random(2025));\nfor (int i = 0; i < 10; i++) {\n    System.out.print(machine.prize() + \", \");\n}\nSystem.out.println();\n","expect":"keychain, sticker, keychain, badge, plush toy, sticker, keychain, sticker, sticker, keychain,","hidden":true},{"name":"Test 3","stdin":"","call":"PrizeMachine machine = new PrizeMachine(new Random());\nint stickers = 0;\nint keychains = 0;\nint badges = 0;\nint toys = 0;\nfor (int i = 0; i < 20000; i++) {\n    String prize = machine.prize();\n    if (prize.equals(\"sticker\")) {\n        stickers++;\n    } else if (prize.equals(\"keychain\")) {\n        keychains++;\n    } else if (prize.equals(\"badge\")) {\n        badges++;\n    } else if (prize.equals(\"plush toy\")) {\n        toys++;\n    }\n}\nSystem.out.println(\"stickers 47% to 53%: \" + (stickers > 9400 && stickers < 10600));\nSystem.out.println(\"keychains 22% to 28%: \" + (keychains > 4400 && keychains < 5600));\nSystem.out.println(\"badges 17% to 23%: \" + (badges > 3400 && badges < 4600));\nSystem.out.println(\"plush toys 3% to 7%: \" + (toys > 600 && toys < 1400));\n","expect":"stickers 47% to 53%: true\nkeychains 22% to 28%: true\nbadges 17% to 23%: true\nplush toys 3% to 7%: true","hidden":true}],"require":[{"pattern":"\\.nextDouble\\s*\\(","message":"Draw the prize's number with `nextDouble()`, so that a seed gives the same prizes as the check's."}],"forbid":[]}]}