{"id":"randomness-next-int","slug":"next-int","title":"Random and nextInt","text":"Every program in this course so far does the same thing each time it runs with the same input. Plenty of programs shouldn't: a board game rolls dice, a quiz asks its questions in a new order, a workout app picks today's exercises, and a simulation tries out thousands of possible days. They need numbers that nobody can predict: **random numbers**. Java makes them with the class `Random`, from the package `java.util`.\n\n### Asking for a number\n\n```java\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random();\n        for (int i = 0; i < 5; i++) {\n            System.out.println(random.nextInt(10));\n        }\n    }\n}\n```\n\nA run might print:\n\n```text\n5\n2\n7\n0\n0\n```\n\nRun it again, and you'll get other numbers.\n\n- `import java.util.Random;` makes the class available, like the import line of a Scanner.\n- `new Random()` creates a **random number generator**: an object whose job is to hand out random numbers.\n- `random.nextInt(10)` returns a random whole number from 0 to 9. The number in the parentheses is the **bound**: the result is always at least 0 and always less than the bound. All ten numbers are equally likely, and each call is a new draw, so the same number can come up twice in a row, like the two zeros above.\n\nMake one Random at the start, and ask it for as many numbers as you need, the way one Scanner reads all the input.\n\n### From 0 to bound - 1\n\nThe bound itself never comes up. Since the numbers change from run to run, you can't check that by comparing them with a list written down earlier. But you can keep the smallest and the largest of many numbers:\n\n```java\nRandom random = new Random();\nint smallest = 100;\nint largest = -100;\nfor (int i = 0; i < 10000; i++) {\n    int number = random.nextInt(10);\n    if (number < smallest) {\n        smallest = number;\n    }\n    if (number > largest) {\n        largest = number;\n    }\n}\nSystem.out.println(\"smallest \" + smallest + \", largest \" + largest);\n```\n\n```output\nsmallest 0, largest 9\n```\n\nIn 10000 numbers, each of the ten values comes up about a thousand times, so 0 and 9 are there, and 10 never is. The numbers behind it differ on every run, but this output doesn't. Step 5 comes back to this way of checking random results.\n\n`nextInt(10)` gives exactly the indexes of an array or a list of 10 elements, from 0 to 9. Step 4 uses that.\n\n### Shifting the range\n\nA die shows 1 to 6, not 0 to 5. `nextInt(6)` gives six different numbers, 0 to 5, and adding 1 to each moves them up to 1 to 6:\n\n```java\nint roll = random.nextInt(6) + 1;\n```\n\nThe same works for any range. For the whole numbers from `low` to `high`, both included:\n\n- there are `high - low + 1` of them, and that's the bound\n- adding `low` moves the smallest one from 0 up to `low`\n\nSo a treasure chest with 10 to 20 coins in it is `random.nextInt(11) + 10`: 11 numbers, from 0 + 10 = 10 to 10 + 10 = 20. A change of -3 to 3 is `random.nextInt(7) - 3`.\n\nTwo easy slips: `random.nextInt(20) + 10` gives 10 to 29, since the bound is how many numbers there are, not the largest one. And `random.nextInt(10) + 10` stops at 19: when you count the numbers in a range, count both ends.\n\n(Since Java 17, a Random can also do this in one call: `random.nextInt(1, 7)` gives 1 to 6, the first number included and the second not, like `substring`. This course shifts the range itself, which works in every version of Java.)\n\n### Two dice\n\nA board game moves a piece by the total of two dice. Each die is a call of its own:\n\n```java\nint first = random.nextInt(6) + 1;\nint second = random.nextInt(6) + 1;\nSystem.out.println(\"You rolled \" + first + \" and \" + second + \": move \" + (first + second) + \" squares\");\n```\n\n`random.nextInt(11) + 2` also gives a number from 2 to 12, but not the way two dice do. Of the 36 ways two dice can land, six make 7 (1 and 6, 2 and 5, 3 and 4, and the other way around), and just one makes 2 (1 and 1). So with two dice, a 7 comes up six times as often as a 2, while `nextInt(11) + 2` makes all eleven totals equally likely. When a program imitates something random, it should do what the real thing does: roll each die.\n\n### A Random as a parameter\n\nA method that needs random numbers can take the Random as a parameter, the way methods in earlier modules took the Scanner they read from:\n\n```java\npublic static int rollDie(Random random) {\n    return random.nextInt(6) + 1;\n}\n```\n\n`main` creates one Random and passes it to every call. The next step shows why that's more than a habit.\n","task":"In a board game, a storm card blows your piece back a random number of squares: 2, 3, 4 or 5, each as likely as the others. Fill in the blanks so that `stormSquares` returns such a number. `main` draws 10000 storm cards and prints the smallest and the largest number of squares:\n\n```\nsmallest 2, largest 5\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();\n        int smallest = 100;\n        int largest = -100;\n        for (int i = 0; i < 10000; i++) {\n            int squares = stormSquares(random);\n            if (squares < smallest) {\n                smallest = squares;\n            }\n            if (squares > largest) {\n                largest = squares;\n            }\n        }\n        System.out.println(\"smallest \" + smallest + \", largest \" + largest);\n    }\n\n    public static int stormSquares(Random random) {\n        return random.nextInt([[4]]) + [[2]];\n    }\n}\n","solution":"import java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random();\n        int smallest = 100;\n        int largest = -100;\n        for (int i = 0; i < 10000; i++) {\n            int squares = stormSquares(random);\n            if (squares < smallest) {\n                smallest = squares;\n            }\n            if (squares > largest) {\n                largest = squares;\n            }\n        }\n        System.out.println(\"smallest \" + smallest + \", largest \" + largest);\n    }\n\n    public static int stormSquares(Random random) {\n        return random.nextInt(4) + 2;\n    }\n}\n","hints":["How many whole numbers are there from 2 to 5, counting both ends? That count is the bound, and `nextInt` starts at 0.","2, 3, 4 and 5 are four numbers, so the bound is 4: `nextInt(4)` gives 0 to 3. Adding the smallest number of squares, 2, moves that up to 2 to 5."],"tests":[{"name":"10000 storm cards","stdin":"","expect":"smallest 2, largest 5","hidden":false},{"name":"Test 2","stdin":"","call":"Random random = new Random();\nboolean[] seen = new boolean[4];\nfor (int i = 0; i < 4000; i++) {\n    int squares = stormSquares(random);\n    if (squares >= 2 && squares <= 5) {\n        seen[squares - 2] = true;\n    }\n}\nSystem.out.println(\"2 to 5 all came up: \" + Arrays.toString(seen));\n","expect":"2 to 5 all came up: [true, true, true, true]","hidden":true}],"require":[],"forbid":[],"more":[{"task":"A board game moves your piece by the total of two dice. Write the method `rollTwoDice(Random random)`, which rolls two six-sided dice with the Random it's given and returns their total. Roll each die with a `nextInt` call of its own: as the lesson showed, `nextInt(11) + 2` gives the right range but the wrong chances.\n\nThe check rolls 18000 times. It prints whether every total was from 2 to 12, and whether a 7 came up at least three times as often as a 2, which is true for real dice:\n\n```\nevery total from 2 to 12: true\n7 at least 3 times as often as 2: true\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();\n        System.out.println(\"You rolled \" + rollTwoDice(random));\n    }\n\n    public static int rollTwoDice(Random random) {\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();\n        System.out.println(\"You rolled \" + rollTwoDice(random));\n    }\n\n    public static int rollTwoDice(Random random) {\n        int first = random.nextInt(6) + 1;\n        int second = random.nextInt(6) + 1;\n        return first + second;\n    }\n}\n","hints":["Roll one die from 1 to 6 the way the lesson did, then roll a second one, and add them up. Use the Random from the parameter: no `new Random()` in the method.","`int first = random.nextInt(6) + 1;`, the same for `second`, then `return first + second;`."],"tests":[{"name":"Test 1","stdin":"","call":"Random random = new Random();\nint[] counts = new int[13];\nboolean inRange = true;\nfor (int i = 0; i < 18000; i++) {\n    int total = rollTwoDice(random);\n    if (total < 2 || total > 12) {\n        inRange = false;\n    } else {\n        counts[total]++;\n    }\n}\nSystem.out.println(\"every total from 2 to 12: \" + inRange);\nSystem.out.println(\"7 at least 3 times as often as 2: \" + (counts[7] >= 3 * counts[2]));\n","expect":"every total from 2 to 12: true\n7 at least 3 times as often as 2: true","hidden":false},{"name":"Test 2","stdin":"","call":"Random random = new Random();\nint[] counts = new int[13];\nfor (int i = 0; i < 18000; i++) {\n    int total = rollTwoDice(random);\n    if (total >= 2 && total <= 12) {\n        counts[total]++;\n    }\n}\nboolean allSeen = true;\nfor (int total = 2; total <= 12; total++) {\n    if (counts[total] == 0) {\n        allSeen = false;\n    }\n}\nSystem.out.println(\"every total came up: \" + allSeen);\nSystem.out.println(\"7 at least 3 times as often as 12: \" + (counts[7] >= 3 * counts[12]));\nSystem.out.println(\"6 more often than 3: \" + (counts[6] > counts[3]));\n","expect":"every total came up: true\n7 at least 3 times as often as 12: true\n6 more often than 3: true","hidden":true},{"name":"Test 3","stdin":"","call":"Random random = new Random(11);\nfor (int i = 0; i < 10; i++) {\n    System.out.print(rollTwoDice(random) + \" \");\n}\nSystem.out.println();\n","expect":"4 8 8 11 10 4 10 10 5 4","hidden":true}],"require":[],"forbid":[]},{"task":"A wind card moves your piece anything from 2 squares back to 2 squares ahead. What does this program print? (The 1 in `new Random(1)` is a seed, which the next step explains. It doesn't change the answer.)\n","kind":"predict","seed":"import java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random(1);\n        int low = 100;\n        int high = -100;\n        for (int i = 0; i < 10000; i++) {\n            int move = random.nextInt(5) - 2;\n            if (move < low) {\n                low = move;\n            }\n            if (move > high) {\n                high = move;\n            }\n        }\n        System.out.println(low + \" to \" + high);\n    }\n}\n","solution":"import java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        Random random = new Random(1);\n        int low = 100;\n        int high = -100;\n        for (int i = 0; i < 10000; i++) {\n            int move = random.nextInt(5) - 2;\n            if (move < low) {\n                low = move;\n            }\n            if (move > high) {\n                high = move;\n            }\n        }\n        System.out.println(low + \" to \" + high);\n    }\n}\n","hints":["`nextInt(5)` gives 0, 1, 2, 3 or 4, never 5. In 10000 draws, each of the five comes up many times.","Subtracting 2 moves the whole range down by two."],"tests":[{"name":"Output","stdin":"","expect":"-2 to 2","hidden":false}],"require":[],"forbid":[],"lines":["-2 to 2"]}]}