{"id":"text-ui-command-loop","slug":"command-loop","title":"A loop that reads commands","text":"Many programs work like a conversation: the user types a command, the program answers, and then it waits for the next command, until the user types the one that ends it. The shopping list at the end of module 14 was one of them. This module is about writing such programs so that they stay easy to read and to change as they grow. It starts with everything in `main`, and then splits the program into a class that does the work and a class that talks with the user.\n\nHere's the starting point, an info desk at a swimming pool. It knows two commands, and `quit`:\n\n```java\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        while (true) {\n            System.out.print(\"> \");\n            String command = scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Bye!\");\n                break;\n            }\n            if (command.equals(\"hours\")) {\n                System.out.println(\"Open every day from 7 to 21\");\n            } else if (command.equals(\"price\")) {\n                System.out.println(\"A swim costs 6 euros\");\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n}\n```\n\n```input\nhours\nprice\nsauna\nquit\n```\n\n```output\n> Open every day from 7 to 21\n> A swim costs 6 euros\n> Unknown command: sauna\n> Bye!\n```\n\n- `while (true)` repeats until a `break` stops it. Each round reads one command and answers it.\n- The `quit` check comes right after reading. `break` ends the loop, and since nothing comes after the loop, the program ends too.\n- Each command has its own `if` or `else if`. The last `else` answers everything else, so a typo like `hour` gets a message. Without it, the program would say nothing, and the user couldn't tell whether anything happened.\n- The command is read once in each round, into `command`, and every branch compares that same variable with `equals`.\n\n### The prompt, and what the outputs show\n\n`System.out.print(\"> \")` prints a **prompt**: a sign that the program is waiting for a command. It's printed with `print`, not `println`, so what the user types goes on the same line. In a terminal, the conversation above looks like this:\n\n```\n> hours\nOpen every day from 7 to 21\n> price\nA swim costs 6 euros\n> sauna\nUnknown command: sauna\n> quit\nBye!\n```\n\nAs in module 2, the checks on this site give the program all of its input at the start, and the output doesn't show what was typed. So each answer comes right after its `> `, as in the output block above. Every program in this module works this way:\n\n- Before reading a command, it prints `> ` with `print`. Each `> ` in an output is one command read, and the rest of that line is the program's answer.\n- A command that needs a value, such as a name or a number, reads it from the next line, without a prompt of its own.\n","task":"A display at a tram stop answers commands: `next` prints `Tram 4 in 6 minutes`, `help` prints `Commands: next, help, quit`, and `quit` prints `Goodbye` and ends the program. Anything else prints `Unknown command: ` and the command. Fill in the blanks. For the input shown, the program prints:\n\n```\n> Tram 4 in 6 minutes\n> Commands: next, help, quit\n> Unknown command: bus\n> Goodbye\n```\n","kind":"fill","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        while ([[true]]) {\n            System.out.[[print]](\"> \");\n            String command = scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Goodbye\");\n                [[break]];\n            }\n            if (command.equals(\"next\")) {\n                System.out.println(\"Tram 4 in 6 minutes\");\n            } else if (command.equals(\"help\")) {\n                System.out.println(\"Commands: next, help, quit\");\n            } [[else]] {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        while (true) {\n            System.out.print(\"> \");\n            String command = scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Goodbye\");\n                break;\n            }\n            if (command.equals(\"next\")) {\n                System.out.println(\"Tram 4 in 6 minutes\");\n            } else if (command.equals(\"help\")) {\n                System.out.println(\"Commands: next, help, quit\");\n            } else {\n                System.out.println(\"Unknown command: \" + command);\n            }\n        }\n    }\n}\n","hints":["The loop and the `quit` branch have the same shape as in the swimming pool program above. The prompt stays on the line where the command is typed.","The condition is `true`, so the loop runs until `break;` stops it. The prompt is printed with `print`, not `println`, and the branch for everything else starts with `else`."],"tests":[{"name":"Test 1","stdin":"next\nhelp\nbus\nquit\n","expect":"> Tram 4 in 6 minutes\n> Commands: next, help, quit\n> Unknown command: bus\n> Goodbye","hidden":false},{"name":"Test 2","stdin":"quit\n","expect":"> Goodbye","hidden":true},{"name":"Test 3","stdin":"Next\nnext\nnext\nstop\nquit\n","expect":"> Unknown command: Next\n> Tram 4 in 6 minutes\n> Tram 4 in 6 minutes\n> Unknown command: stop\n> Goodbye","hidden":true}],"require":[],"forbid":[],"more":[{"task":"A virtual cat answers commands. Write the command loop. Before reading each command, print the prompt `> ` with `print`. The commands:\n\n- `feed` prints `The cat eats and purrs`\n- `pet` prints `The cat closes its eyes`\n- `sleep` prints `The cat curls up. Goodnight!` and ends the program\n- anything else prints `The cat ignores \"`, the command and a closing `\"`, like `The cat ignores \"bath\"`\n\nFor the input shown, the program prints:\n\n```\n> The cat eats and purrs\n> The cat ignores \"bath\"\n> The cat closes its eyes\n> The cat curls up. Goodnight!\n```\n","kind":"code","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        // Write the command loop here.\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        // Write the command loop here.\n        while (true) {\n            System.out.print(\"> \");\n            String command = scanner.nextLine();\n            if (command.equals(\"sleep\")) {\n                System.out.println(\"The cat curls up. Goodnight!\");\n                break;\n            }\n            if (command.equals(\"feed\")) {\n                System.out.println(\"The cat eats and purrs\");\n            } else if (command.equals(\"pet\")) {\n                System.out.println(\"The cat closes its eyes\");\n            } else {\n                System.out.println(\"The cat ignores \\\"\" + command + \"\\\"\");\n            }\n        }\n    }\n}\n","hints":["Start from the swimming pool program: `while (true)`, the prompt, one `nextLine()` into `command`, and the check for `sleep` with a `break`.","A quote inside a String is written `\\\"`, so the last answer is `\"The cat ignores \\\"\" + command + \"\\\"\"`."],"tests":[{"name":"Test 1","stdin":"feed\nbath\npet\nsleep\n","expect":"> The cat eats and purrs\n> The cat ignores \"bath\"\n> The cat closes its eyes\n> The cat curls up. Goodnight!","hidden":false},{"name":"Test 2","stdin":"sleep\n","expect":"> The cat curls up. Goodnight!","hidden":true},{"name":"Test 3","stdin":"pet\npet\n\nFeed\nfeed\nsleep\n","expect":"> The cat closes its eyes\n> The cat closes its eyes\n> The cat ignores \"\"\n> The cat ignores \"Feed\"\n> The cat eats and purrs\n> The cat curls up. Goodnight!","hidden":true}],"require":[],"forbid":[]},{"task":"This program should answer every command, but for the input shown it prints only `> Unknown command` and `> Disconnected`. With other input it even crashes. Find out why, and fix it, so that it prints:\n\n```\n> pong\n> Server 2.4\n> pong\n> Disconnected\n```\n","kind":"code","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        while (true) {\n            System.out.print(\"> \");\n            if (scanner.nextLine().equals(\"quit\")) {\n                System.out.println(\"Disconnected\");\n                break;\n            }\n            if (scanner.nextLine().equals(\"ping\")) {\n                System.out.println(\"pong\");\n            } else if (scanner.nextLine().equals(\"version\")) {\n                System.out.println(\"Server 2.4\");\n            } else {\n                System.out.println(\"Unknown command\");\n            }\n        }\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        while (true) {\n            System.out.print(\"> \");\n            String command = scanner.nextLine();\n            if (command.equals(\"quit\")) {\n                System.out.println(\"Disconnected\");\n                break;\n            }\n            if (command.equals(\"ping\")) {\n                System.out.println(\"pong\");\n            } else if (command.equals(\"version\")) {\n                System.out.println(\"Server 2.4\");\n            } else {\n                System.out.println(\"Unknown command\");\n            }\n        }\n    }\n}\n","hints":["Each `scanner.nextLine()` reads a new line. How many lines does one round of the loop read, when the command isn't `quit`?","Read the command once, at the start of the round, into a variable: `String command = scanner.nextLine();`. Then compare that variable in every `if`."],"tests":[{"name":"Test 1","stdin":"ping\nversion\nping\nquit\n","expect":"> pong\n> Server 2.4\n> pong\n> Disconnected","hidden":false},{"name":"Test 2","stdin":"version\nquit\n","expect":"> Server 2.4\n> Disconnected","hidden":true},{"name":"Test 3","stdin":"hello\nping\nping\nstatus\nversion\nquit\n","expect":"> Unknown command\n> pong\n> pong\n> Unknown command\n> Server 2.4\n> Disconnected","hidden":true}],"require":[{"pattern":"\\.nextLine\\s*\\(\\s*\\)","max":1,"message":"Read the command once in each round, with a single `nextLine()`, and keep it in a variable."}],"forbid":[]}]}