{"id":"randomness-simulations","slug":"simulations-and-checks","title":"Simulations, and checking random results","text":"This last step puts random numbers to work in whole programs: simulations that answer questions about chance, checks that a random result is right, and a word on where Random doesn't belong.\n\n### Simulations\n\nSome questions about chance are hard to work out by hand but easy to try: play the game many times, and count. That's a **simulation**. How many rolls of a die does it take, on average, to get the first six?\n\n```java\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random(1);\n        int games = 10000;\n        int totalRolls = 0;\n        for (int i = 0; i < games; i++) {\n            totalRolls += rollsUntilSix(random);\n        }\n        System.out.println(\"Average rolls: \" + (double) totalRolls / games);\n    }\n\n    public static int rollsUntilSix(Random random) {\n        int rolls = 0;\n        int roll = 0;\n        while (roll != 6) {\n            roll = random.nextInt(6) + 1;\n            rolls++;\n        }\n        return rolls;\n    }\n}\n```\n\n```output\nAverage rolls: 5.9766\n```\n\nClose to 6, which is also what probability math says: with a chance of 1 in 6 on each roll, it takes 6 rolls on average. In a single game it can take 1 roll, or 20. Simulations earn their keep when the math gets hard: a whole board game with several players, special squares and cards is much easier to simulate than to calculate.\n\n- The more games a simulation plays, the closer its answer usually is to the true one. Try 100 games instead of 10000, with a few different seeds, and the averages are much further apart.\n- The seed makes the whole simulation repeatable. Anyone who runs it gets exactly the same average, and can check your work.\n\n### Checking random results\n\nA test of a program with random numbers has two tools. With a seed, it can compare the exact output, as this module's checks do. Without one, it can still check what must be true of **every** run, however the numbers fall. Such facts are called **properties**:\n\n- every value is in its range: a die roll is from 1 to 6\n- every possible value comes up, given enough tries: in 6000 rolls, all six faces\n- a draw without repeats has no repeats, and a shuffled list has the same elements as before\n- a share is close to its chance: of 100000 tries with a 30% chance, between 28% and 32% hit\n\nThe last one needs a margin, since random results wobble. With enough tries, a wide margin is practically never crossed by chance: when such a check fails, look for the mistake in the code. The hidden tests of this module's challenges check properties like these.\n\nHere's a property of a shuffle. However the list is shuffled, sorting it gives back the sorted original:\n\n```java\nArrayList<String> guests = new ArrayList<>();\nguests.add(\"Noor\");\nguests.add(\"Emil\");\nguests.add(\"Sade\");\nguests.add(\"Luca\");\nArrayList<String> sorted = new ArrayList<>(guests);\nCollections.sort(sorted);\nRandom random = new Random();\nboolean same = true;\nfor (int i = 0; i < 1000; i++) {\n    ArrayList<String> shuffled = new ArrayList<>(guests);\n    Collections.shuffle(shuffled, random);\n    Collections.sort(shuffled);\n    if (!shuffled.equals(sorted)) {\n        same = false;\n    }\n}\nSystem.out.println(\"The same guests after 1000 shuffles: \" + same);\n```\n\n```output\nThe same guests after 1000 shuffles: true\n```\n\n### Not for secrets\n\nRandom is fine for games, simulations and tests, but not for passwords, secret codes or anything else that someone would like to guess. Its formula is public, and someone who sees enough of its numbers can work out the ones that come next. Java has a separate class for secrets, `SecureRandom` in the package `java.security`, which is built so that its numbers can't be worked out that way.\n","task":"A coin flip streak counter. Write the method `longestStreak(Random random, int flips)`, which flips a coin `flips` times and returns the longest streak: the most flips in a row that landed on the same side. Flip each coin with one `random.nextBoolean()` call (`true` is heads, `false` is tails), so that a seed gives the same flips as the check's. `flips` is at least 1. For example, the flips heads, tails, tails, tails, heads have a longest streak of 3. The check runs:\n\n```java\nRandom random = new Random(42);\nSystem.out.println(longestStreak(random, 10));\nSystem.out.println(longestStreak(random, 100));\n```\n\nand expects:\n\n```\n2\n6\n```\n","kind":"code","seed":"import java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random(42);\n        System.out.println(longestStreak(random, 10));\n        System.out.println(longestStreak(random, 100));\n    }\n\n    public static int longestStreak(Random random, int flips) {\n        return 0;\n    }\n}\n","solution":"import java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random(42);\n        System.out.println(longestStreak(random, 10));\n        System.out.println(longestStreak(random, 100));\n    }\n\n    public static int longestStreak(Random random, int flips) {\n        boolean previous = random.nextBoolean();\n        int streak = 1;\n        int longest = 1;\n        for (int i = 1; i < flips; i++) {\n            boolean flip = random.nextBoolean();\n            if (flip == previous) {\n                streak++;\n            } else {\n                streak = 1;\n            }\n            if (streak > longest) {\n                longest = streak;\n            }\n            previous = flip;\n        }\n        return longest;\n    }\n}\n","hints":["Flip the first coin before the loop, and keep it in `previous`. The streak so far is 1, and so is the longest one.","Loop for the other `flips - 1` coins. When a flip is the same as `previous`, the streak grows; otherwise it starts again at 1. Update the longest streak, and remember the flip in `previous` for the next round."],"tests":[{"name":"Test 1","stdin":"","call":"Random random = new Random(42);\nSystem.out.println(longestStreak(random, 10));\nSystem.out.println(longestStreak(random, 100));\n","expect":"2\n6","hidden":false},{"name":"Test 2","stdin":"","call":"Random random = new Random(3);\nSystem.out.println(longestStreak(random, 1));\nSystem.out.println(longestStreak(random, 2));\nSystem.out.println(longestStreak(random, 20));\nSystem.out.println(longestStreak(random, 1000));\n","expect":"1\n1\n3\n9","hidden":true},{"name":"Test 3","stdin":"","call":"Random random = new Random();\nboolean inRange = true;\nfor (int i = 0; i < 1000; i++) {\n    int streak = longestStreak(random, 5);\n    if (streak < 1 || streak > 5) {\n        inRange = false;\n    }\n}\nSystem.out.println(\"from 1 to 5 in 5 flips: \" + inRange);\nSystem.out.println(\"1 flip: \" + longestStreak(random, 1));\n","expect":"from 1 to 5 in 5 flips: true\n1 flip: 1","hidden":true},{"name":"Test 4","stdin":"","call":"Random random = new Random(8);\nint first = longestStreak(random, 30);\nint second = longestStreak(random, 30);\nRandom again = new Random(8);\nSystem.out.println(first + \" \" + second + \" \" + longestStreak(again, 30) + \" \" + longestStreak(again, 30));\n","expect":"3 4 3 4","hidden":true}],"require":[{"pattern":"\\.nextBoolean\\s*\\(","message":"Flip each coin with `random.nextBoolean()`, so that a seed gives the same flips as the check's."}],"forbid":[],"more":[{"task":"`Collections.shuffle` only changes the order of a list. What does this program print?\n","kind":"predict","seed":"import java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Integer> cards = new ArrayList<>();\n        for (int i = 1; i <= 5; i++) {\n            cards.add(i * 10);\n        }\n        ArrayList<Integer> deck = new ArrayList<>(cards);\n        Collections.shuffle(deck, new Random(9));\n        int sum = 0;\n        for (int card : deck) {\n            sum += card;\n        }\n        System.out.println(deck.size() + \" \" + sum);\n        System.out.println(deck.contains(30) + \" \" + deck.contains(60));\n        Collections.sort(deck);\n        System.out.println(deck.equals(cards));\n    }\n}\n","solution":"import java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Integer> cards = new ArrayList<>();\n        for (int i = 1; i <= 5; i++) {\n            cards.add(i * 10);\n        }\n        ArrayList<Integer> deck = new ArrayList<>(cards);\n        Collections.shuffle(deck, new Random(9));\n        int sum = 0;\n        for (int card : deck) {\n            sum += card;\n        }\n        System.out.println(deck.size() + \" \" + sum);\n        System.out.println(deck.contains(30) + \" \" + deck.contains(60));\n        Collections.sort(deck);\n        System.out.println(deck.equals(cards));\n    }\n}\n","hints":["The deck is a copy of the cards 10, 20, 30, 40 and 50, in some new order. The order changes, but not which numbers there are, nor how many.","After sorting, the deck is in increasing order again, just like `cards`, and `equals` compares two lists element by element."],"tests":[{"name":"Output","stdin":"","expect":"5 150\ntrue false\ntrue","hidden":false}],"require":[],"forbid":[],"lines":["5 150","true false","true"]},{"task":"To finish the module, a random seating plan for a dinner party. In `SeatingPlan.java`, write the class `SeatingPlan` with:\n\n- a constructor `SeatingPlan(ArrayList<String> guests, int tables, Random random)`. It shuffles a copy of the guest list with `Collections.shuffle(copy, random)` (the list it's given keeps its order), and then deals the shuffled guests out to the tables in turn, the way cards are dealt: the first guest to table 1, the second to table 2, and so on, back to table 1 after the last table.\n- `table(int number)`, which returns an `ArrayList<String>` of the guests at that table, in the order they were dealt. Tables are numbered from 1.\n- `toString()`, which returns one line for each table, like `Table 1: Noor, Luca`, with the names separated by a comma and a space, and a line break between the tables.\n\nThe check runs:\n\n```java\nArrayList<String> guests = new ArrayList<>();\nguests.add(\"Noor\");\nguests.add(\"Emil\");\nguests.add(\"Sade\");\nguests.add(\"Luca\");\nguests.add(\"Mei\");\nguests.add(\"Arjun\");\nguests.add(\"Rosa\");\nSeatingPlan plan = new SeatingPlan(guests, 3, new Random(4));\nSystem.out.println(plan);\nSystem.out.println(plan.table(2).size() + \" at table 2\");\n```\n\nand expects:\n\n```\nTable 1: Emil, Arjun, Luca\nTable 2: Sade, Rosa\nTable 3: Noor, Mei\n2 at table 2\n```\n","kind":"code","seed":"// ==== SeatingPlan.java ====\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Random;\n\npublic class SeatingPlan {\n\n}\n\n// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> guests = new ArrayList<>();\n        guests.add(\"Noor\");\n        guests.add(\"Emil\");\n        guests.add(\"Sade\");\n        guests.add(\"Luca\");\n        guests.add(\"Mei\");\n        guests.add(\"Arjun\");\n        guests.add(\"Rosa\");\n        SeatingPlan plan = new SeatingPlan(guests, 3, new Random(4));\n        System.out.println(plan);\n        System.out.println(plan.table(2).size() + \" at table 2\");\n    }\n}\n","solution":"// ==== SeatingPlan.java ====\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Random;\n\npublic class SeatingPlan {\n    private ArrayList<String> order;\n    private int tables;\n\n    public SeatingPlan(ArrayList<String> guests, int tables, Random random) {\n        this.order = new ArrayList<>(guests);\n        Collections.shuffle(this.order, random);\n        this.tables = tables;\n    }\n\n    public ArrayList<String> table(int number) {\n        ArrayList<String> seated = new ArrayList<>();\n        for (int i = 0; i < this.order.size(); i++) {\n            if (i % this.tables == number - 1) {\n                seated.add(this.order.get(i));\n            }\n        }\n        return seated;\n    }\n\n    @Override\n    public String toString() {\n        String plan = \"\";\n        for (int number = 1; number <= this.tables; number++) {\n            if (number > 1) {\n                plan += \"\\n\";\n            }\n            plan += \"Table \" + number + \": \";\n            ArrayList<String> seated = this.table(number);\n            for (int i = 0; i < seated.size(); i++) {\n                if (i > 0) {\n                    plan += \", \";\n                }\n                plan += seated.get(i);\n            }\n        }\n        return plan;\n    }\n}\n\n// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> guests = new ArrayList<>();\n        guests.add(\"Noor\");\n        guests.add(\"Emil\");\n        guests.add(\"Sade\");\n        guests.add(\"Luca\");\n        guests.add(\"Mei\");\n        guests.add(\"Arjun\");\n        guests.add(\"Rosa\");\n        SeatingPlan plan = new SeatingPlan(guests, 3, new Random(4));\n        System.out.println(plan);\n        System.out.println(plan.table(2).size() + \" at table 2\");\n    }\n}\n","hints":["In the constructor, copy the guests, shuffle the copy with the Random, and keep the copy and the number of tables in instance variables. That shuffled order is all the plan needs.","Dealing in turn puts the guest at index `i` of the shuffled list at table `i % tables + 1`. So `table(number)` collects the guests whose index gives `i % this.tables == number - 1`, and `toString` adds each table's names in a loop, with `\", \"` before every name except the first, which an index loop can tell by `i > 0` (as in module 39)."],"tests":[{"name":"Test 1","stdin":"","call":"ArrayList<String> guests = new ArrayList<>();\nguests.add(\"Noor\");\nguests.add(\"Emil\");\nguests.add(\"Sade\");\nguests.add(\"Luca\");\nguests.add(\"Mei\");\nguests.add(\"Arjun\");\nguests.add(\"Rosa\");\nSeatingPlan plan = new SeatingPlan(guests, 3, new Random(4));\nSystem.out.println(plan);\nSystem.out.println(plan.table(2).size() + \" at table 2\");\n","expect":"Table 1: Emil, Arjun, Luca\nTable 2: Sade, Rosa\nTable 3: Noor, Mei\n2 at table 2","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<String> guests = new ArrayList<>();\nguests.add(\"Ada\");\nguests.add(\"Ben\");\nguests.add(\"Cleo\");\nguests.add(\"Dev\");\nSeatingPlan plan = new SeatingPlan(guests, 2, new Random(15));\nSystem.out.println(plan);\nSystem.out.println(plan.table(1));\nSystem.out.println(guests);\n","expect":"Table 1: Ben, Dev\nTable 2: Ada, Cleo\n[Ben, Dev]\n[Ada, Ben, Cleo, Dev]","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<String> guests = new ArrayList<>();\nfor (int i = 1; i <= 11; i++) {\n    guests.add(\"Guest\" + i);\n}\nSeatingPlan plan = new SeatingPlan(guests, 4, new Random());\nArrayList<String> everyone = new ArrayList<>();\nint smallest = 100;\nint largest = 0;\nfor (int number = 1; number <= 4; number++) {\n    ArrayList<String> table = plan.table(number);\n    everyone.addAll(table);\n    smallest = Math.min(smallest, table.size());\n    largest = Math.max(largest, table.size());\n}\nCollections.sort(everyone);\nArrayList<String> sorted = new ArrayList<>(guests);\nCollections.sort(sorted);\nSystem.out.println(\"everyone seated once: \" + everyone.equals(sorted));\nSystem.out.println(\"table sizes \" + smallest + \" to \" + largest);\n","expect":"everyone seated once: true\ntable sizes 2 to 3","hidden":true}],"require":[],"forbid":[]}]}