{"id":"gui-views-practice-app-logic","slug":"practice-app-logic","title":"A practice app, part 1: the logic","text":"This step and the next build a larger application, in the way step 5 described: the logic first, in classes that know nothing about windows, and then the views on top of them.\n\n### What the app does\n\nThe app trains the capitals of countries, with cards:\n\n- The user **adds cards**: a country and its capital, such as Peru and Lima.\n- The user **trains**: the app shows a country, the user types its capital, and the app says whether that was right and goes on to the next card. It counts the right and the wrong answers.\n- The cards come in the order they were added, and after the last one the first one comes again.\n\nA real trainer might shuffle the cards with Random (module 46). A fixed order keeps every run the same, which makes the app easy to check, and shuffling can be added later in one place: the logic.\n\n### Three classes\n\nThe logic has two jobs, so it gets two main classes. A **CardBox** stores the cards, each a small **Card** object with a country and its capital. A **PracticeRound** runs the training: whose turn it is, and the counts.\n\n\n<figure class=\"uml\"><div class=\"uml-scroll\" tabindex=\"0\" role=\"group\" aria-label=\"Class diagram of Card, CardBox and PracticeRound\">\n<svg class=\"uml-svg\" viewBox=\"0 0 367 540\" width=\"367\" height=\"540\" style=\"width:22.94rem;min-width:21.03rem;aspect-ratio:367/540\" font-size=\"12\" aria-hidden=\"true\" focusable=\"false\"><path class=\"u-edge\" fill=\"none\" d=\"M183.5 170L183.5 126\"/><path class=\"u-edge\" fill=\"none\" d=\"M183.5 350L183.5 306\"/><path class=\"u-edge\" fill=\"none\" d=\"M189 136L183.5 126L178 136\"/><path class=\"u-edge\" fill=\"none\" d=\"M189 316L183.5 306L178 316\"/><rect class=\"u-bg\" fill=\"none\" x=\"35\" y=\"6\" width=\"297\" height=\"120\"/><rect class=\"u-head\" fill=\"none\" x=\"35\" y=\"6\" width=\"297\" height=\"24\"/><text x=\"183.5\" y=\"22\" text-anchor=\"middle\" class=\"u-name\">Card</text><text x=\"43\" y=\"46\">-country: String</text><text x=\"43\" y=\"62\">-capital: String</text><text x=\"43\" y=\"86\">+Card(country: String, capital: String)</text><text x=\"43\" y=\"102\">+getCountry(): String</text><text x=\"43\" y=\"118\">+getCapital(): String</text><path class=\"u-sep\" fill=\"none\" d=\"M35 30h297M35 70h297\"/><rect class=\"u-frame\" fill=\"none\" x=\"35\" y=\"6\" width=\"297\" height=\"120\"/><rect class=\"u-bg\" fill=\"none\" x=\"6\" y=\"170\" width=\"355\" height=\"136\"/><rect class=\"u-head\" fill=\"none\" x=\"6\" y=\"170\" width=\"355\" height=\"24\"/><text x=\"183.5\" y=\"186\" text-anchor=\"middle\" class=\"u-name\">CardBox</text><text x=\"14\" y=\"210\">-cards: ArrayList&lt;Card&gt;</text><text x=\"14\" y=\"234\">+CardBox()</text><text x=\"14\" y=\"250\">+add(country: String, capital: String): boolean</text><text x=\"14\" y=\"266\">+capitalOf(country: String): String</text><text x=\"14\" y=\"282\">+countryAt(index: int): String</text><text x=\"14\" y=\"298\">+size(): int</text><path class=\"u-sep\" fill=\"none\" d=\"M6 194h355M6 218h355\"/><rect class=\"u-frame\" fill=\"none\" x=\"6\" y=\"170\" width=\"355\" height=\"136\"/><rect class=\"u-bg\" fill=\"none\" x=\"67.5\" y=\"350\" width=\"232\" height=\"184\"/><rect class=\"u-head\" fill=\"none\" x=\"67.5\" y=\"350\" width=\"232\" height=\"24\"/><text x=\"183.5\" y=\"366\" text-anchor=\"middle\" class=\"u-name\">PracticeRound</text><text x=\"75.5\" y=\"390\">-box: CardBox</text><text x=\"75.5\" y=\"406\">-next: int</text><text x=\"75.5\" y=\"422\">-right: int</text><text x=\"75.5\" y=\"438\">-wrong: int</text><text x=\"75.5\" y=\"462\">+PracticeRound(box: CardBox)</text><text x=\"75.5\" y=\"478\">+question(): String</text><text x=\"75.5\" y=\"494\">+answer(text: String): boolean</text><text x=\"75.5\" y=\"510\">+getRight(): int</text><text x=\"75.5\" y=\"526\">+getWrong(): int</text><path class=\"u-sep\" fill=\"none\" d=\"M67.5 374h232M67.5 446h232\"/><rect class=\"u-frame\" fill=\"none\" x=\"67.5\" y=\"350\" width=\"232\" height=\"184\"/><text x=\"191.5\" y=\"139\" class=\"u-mult\">*</text></svg>\n</div><details class=\"uml-text\"><summary>The diagram as text</summary><ul><li><strong>Card</strong>, a class<ul><li>private field <code>country: String</code></li><li>private field <code>capital: String</code></li><li>public constructor <code>Card(country: String, capital: String)</code></li><li>public method <code>getCountry(): String</code></li><li>public method <code>getCapital(): String</code></li></ul></li><li><strong>CardBox</strong>, a class<ul><li>private field <code>cards: ArrayList&lt;Card&gt;</code></li><li>public constructor <code>CardBox()</code></li><li>public method <code>add(country: String, capital: String): boolean</code></li><li>public method <code>capitalOf(country: String): String</code></li><li>public method <code>countryAt(index: int): String</code></li><li>public method <code>size(): int</code></li></ul></li><li><strong>PracticeRound</strong>, a class<ul><li>private field <code>box: CardBox</code></li><li>private field <code>next: int</code></li><li>private field <code>right: int</code></li><li>private field <code>wrong: int</code></li><li>public constructor <code>PracticeRound(box: CardBox)</code></li><li>public method <code>question(): String</code></li><li>public method <code>answer(text: String): boolean</code></li><li>public method <code>getRight(): int</code></li><li>public method <code>getWrong(): int</code></li></ul></li></ul><p>Connections:</p><ul><li>Each CardBox has any number of Card objects.</li><li>Each PracticeRound has one CardBox object.</li></ul></details></figure>\n\n\nThe window will use only some of these: the view for adding cards calls `add` and `size`, and the training view calls `question`, `answer`, the getters, and `capitalOf` for its feedback. Deciding what the logic offers before any window exists is the point of starting with it.\n\n### The card box\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        CardBox box = new CardBox();\n        System.out.println(box.add(\"Peru\", \"Lima\"));\n        System.out.println(box.add(\"Kenya\", \" Nairobi \"));\n        System.out.println(box.add(\"Peru\", \"Cusco\"));\n        System.out.println(box.add(\" \", \"Oslo\"));\n        System.out.println(box.size() + \" cards, the first is \" + box.countryAt(0));\n        System.out.println(box.capitalOf(\"Kenya\") + \" \" + box.capitalOf(\"Chile\"));\n    }\n}\n// ==== CardBox.java ====\nimport java.util.ArrayList;\n\npublic class CardBox {\n    private ArrayList<Card> cards;\n\n    public CardBox() {\n        this.cards = new ArrayList<>();\n    }\n\n    public boolean add(String country, String capital) {\n        String name = country.trim();\n        String city = capital.trim();\n        if (name.isEmpty() || city.isEmpty() || this.capitalOf(name) != null) {\n            return false;\n        }\n        this.cards.add(new Card(name, city));\n        return true;\n    }\n\n    public String capitalOf(String country) {\n        for (Card card : this.cards) {\n            if (card.getCountry().equals(country)) {\n                return card.getCapital();\n            }\n        }\n        return null;\n    }\n\n    public String countryAt(int index) {\n        return this.cards.get(index).getCountry();\n    }\n\n    public int size() {\n        return this.cards.size();\n    }\n}\n// ==== Card.java ====\npublic class Card {\n    private String country;\n    private String capital;\n\n    public Card(String country, String capital) {\n        this.country = country;\n        this.capital = capital;\n    }\n\n    public String getCountry() {\n        return this.country;\n    }\n\n    public String getCapital() {\n        return this.capital;\n    }\n}\n```\n\n```output\ntrue\ntrue\nfalse\nfalse\n2 cards, the first is Peru\nNairobi null\n```\n\n- The box keeps its cards in one ArrayList of Card objects, so they stay in the order they were added, and `countryAt` gives a card's country by its place in that order. A HashMap from country to capital would find a capital faster, but its order is its own (module 31), so the training would jump around.\n- `capitalOf` walks through the cards and returns the capital of the first card with that country, or `null` when no card has it, as `HashMap`'s `get` would. `add` uses it to find out whether a country is in the box already.\n- `add` refuses a card with an empty country or capital, and a country that is in the box already, and returns `false` for them. The view will turn that `false` into a message, but the rule itself lives here.\n- The texts are trimmed before they're stored, so `\" Nairobi \"` becomes `Nairobi`.\n\n### The practice round\n\nA PracticeRound gets the box in its constructor, the way step 5's views got the jar. It keeps `next`, the index of the card whose turn it is. It starts at 0, and each answer moves it on by one; after the last card it goes back to 0. Since the round asks the box each time, cards added during the training simply join it.\n","task":"Write the class `PracticeRound` in `PracticeRound.java`. `CardBox` is ready.\n\n- a constructor `PracticeRound(CardBox box)`\n- `question()`: returns the country of the card whose turn it is, or `null` when the box is empty\n- `answer(String text)`: when the box is empty, returns `false` and counts nothing. Otherwise the answer is right when `text`, trimmed, is the capital of the card whose turn it is, ignoring upper and lower case (`equalsIgnoreCase`). It counts the answer as right or wrong, moves the turn to the next card (after the last card, back to the first), and returns `true` for a right answer, `false` for a wrong one.\n- `getRight()` and `getWrong()`: the numbers of right and wrong answers so far\n\nThe check runs:\n\n```java\nCardBox box = new CardBox();\nbox.add(\"Peru\", \"Lima\");\nbox.add(\"Kenya\", \"Nairobi\");\nPracticeRound round = new PracticeRound(box);\nSystem.out.println(round.question());\nSystem.out.println(round.answer(\" lima\"));\nSystem.out.println(round.question());\nSystem.out.println(round.answer(\"Mombasa\"));\nSystem.out.println(round.question() + \" \" + round.getRight() + \" \" + round.getWrong());\n```\n\nand expects:\n\n```\nPeru\ntrue\nKenya\nfalse\nPeru 1 1\n```\n","kind":"code","seed":"// ==== PracticeRound.java ====\npublic class PracticeRound {\n\n}\n\n// ==== CardBox.java ====\nimport java.util.ArrayList;\n\npublic class CardBox {\n    private ArrayList<Card> cards;\n\n    public CardBox() {\n        this.cards = new ArrayList<>();\n    }\n\n    public boolean add(String country, String capital) {\n        String name = country.trim();\n        String city = capital.trim();\n        if (name.isEmpty() || city.isEmpty() || this.capitalOf(name) != null) {\n            return false;\n        }\n        this.cards.add(new Card(name, city));\n        return true;\n    }\n\n    public String capitalOf(String country) {\n        for (Card card : this.cards) {\n            if (card.getCountry().equals(country)) {\n                return card.getCapital();\n            }\n        }\n        return null;\n    }\n\n    public String countryAt(int index) {\n        return this.cards.get(index).getCountry();\n    }\n\n    public int size() {\n        return this.cards.size();\n    }\n}\n\n// ==== Card.java ====\npublic class Card {\n    private String country;\n    private String capital;\n\n    public Card(String country, String capital) {\n        this.country = country;\n        this.capital = capital;\n    }\n\n    public String getCountry() {\n        return this.country;\n    }\n\n    public String getCapital() {\n        return this.capital;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        CardBox box = new CardBox();\n        box.add(\"Peru\", \"Lima\");\n        box.add(\"Kenya\", \"Nairobi\");\n        PracticeRound round = new PracticeRound(box);\n        System.out.println(round.question());\n        System.out.println(round.answer(\" lima\"));\n        System.out.println(round.question());\n        System.out.println(round.answer(\"Mombasa\"));\n        System.out.println(round.question() + \" \" + round.getRight() + \" \" + round.getWrong());\n    }\n}\n","solution":"// ==== PracticeRound.java ====\npublic class PracticeRound {\n    private CardBox box;\n    private int next;\n    private int right;\n    private int wrong;\n\n    public PracticeRound(CardBox box) {\n        this.box = box;\n    }\n\n    public String question() {\n        if (this.box.size() == 0) {\n            return null;\n        }\n        return this.box.countryAt(this.next);\n    }\n\n    public boolean answer(String text) {\n        String country = this.question();\n        if (country == null) {\n            return false;\n        }\n        boolean correct = text.trim().equalsIgnoreCase(this.box.capitalOf(country));\n        if (correct) {\n            this.right++;\n        } else {\n            this.wrong++;\n        }\n        this.next++;\n        if (this.next >= this.box.size()) {\n            this.next = 0;\n        }\n        return correct;\n    }\n\n    public int getRight() {\n        return this.right;\n    }\n\n    public int getWrong() {\n        return this.wrong;\n    }\n}\n\n// ==== CardBox.java ====\nimport java.util.ArrayList;\n\npublic class CardBox {\n    private ArrayList<Card> cards;\n\n    public CardBox() {\n        this.cards = new ArrayList<>();\n    }\n\n    public boolean add(String country, String capital) {\n        String name = country.trim();\n        String city = capital.trim();\n        if (name.isEmpty() || city.isEmpty() || this.capitalOf(name) != null) {\n            return false;\n        }\n        this.cards.add(new Card(name, city));\n        return true;\n    }\n\n    public String capitalOf(String country) {\n        for (Card card : this.cards) {\n            if (card.getCountry().equals(country)) {\n                return card.getCapital();\n            }\n        }\n        return null;\n    }\n\n    public String countryAt(int index) {\n        return this.cards.get(index).getCountry();\n    }\n\n    public int size() {\n        return this.cards.size();\n    }\n}\n\n// ==== Card.java ====\npublic class Card {\n    private String country;\n    private String capital;\n\n    public Card(String country, String capital) {\n        this.country = country;\n        this.capital = capital;\n    }\n\n    public String getCountry() {\n        return this.country;\n    }\n\n    public String getCapital() {\n        return this.capital;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        CardBox box = new CardBox();\n        box.add(\"Peru\", \"Lima\");\n        box.add(\"Kenya\", \"Nairobi\");\n        PracticeRound round = new PracticeRound(box);\n        System.out.println(round.question());\n        System.out.println(round.answer(\" lima\"));\n        System.out.println(round.question());\n        System.out.println(round.answer(\"Mombasa\"));\n        System.out.println(round.question() + \" \" + round.getRight() + \" \" + round.getWrong());\n    }\n}\n","hints":["Four instance variables: the box, `next` (the index of the card whose turn it is), and the two counts. `question()` returns `null` when `this.box.size() == 0`, and otherwise `this.box.countryAt(this.next)`.","In `answer`, get the country with `question()` first and return `false` if it's `null`. Compare with `text.trim().equalsIgnoreCase(this.box.capitalOf(country))`, add to the right count, add one to `next`, and set `next` back to 0 when it reaches `this.box.size()`."],"tests":[{"name":"Test 1","stdin":"","call":"CardBox box = new CardBox();\nbox.add(\"Peru\", \"Lima\");\nbox.add(\"Kenya\", \"Nairobi\");\nPracticeRound round = new PracticeRound(box);\nSystem.out.println(round.question());\nSystem.out.println(round.answer(\" lima\"));\nSystem.out.println(round.question());\nSystem.out.println(round.answer(\"Mombasa\"));\nSystem.out.println(round.question() + \" \" + round.getRight() + \" \" + round.getWrong());\n","expect":"Peru\ntrue\nKenya\nfalse\nPeru 1 1","hidden":false},{"name":"Test 2","stdin":"","call":"CardBox box = new CardBox();\nPracticeRound round = new PracticeRound(box);\nSystem.out.println(round.question());\nSystem.out.println(round.answer(\"Oslo\"));\nSystem.out.println(round.getRight() + \" \" + round.getWrong());\nbox.add(\"Norway\", \"Oslo\");\nSystem.out.println(round.question());\nSystem.out.println(round.answer(\"OSLO \"));\nSystem.out.println(round.question());\nSystem.out.println(round.answer(\"Bergen\"));\nSystem.out.println(round.getRight() + \" \" + round.getWrong());\n","expect":"null\nfalse\n0 0\nNorway\ntrue\nNorway\nfalse\n1 1","hidden":true},{"name":"Test 3","stdin":"","call":"CardBox box = new CardBox();\nbox.add(\"Japan\", \"Tokyo\");\nbox.add(\"Chile\", \"Santiago\");\nbox.add(\"Egypt\", \"Cairo\");\nPracticeRound round = new PracticeRound(box);\nround.answer(\"Tokyo\");\nround.answer(\"Santiago\");\nSystem.out.println(round.question());\nround.answer(\"Giza\");\nSystem.out.println(round.question());\nbox.add(\"Ghana\", \"Accra\");\nround.answer(\"tokyo\");\nround.answer(\"Valparaiso\");\nround.answer(\"Cairo\");\nSystem.out.println(round.question());\nround.answer(\"accra\");\nSystem.out.println(round.question() + \" \" + round.getRight() + \" \" + round.getWrong());\n","expect":"Egypt\nJapan\nGhana\nJapan 5 2","hidden":true}],"require":[],"forbid":[{"pattern":"\\bRandom\\b|Math\\.random","message":"The cards come in a fixed order: the order they were added in, and after the last card the first one comes again."}],"more":[{"task":"A trainer should help with the capitals that went wrong. Add a method `missed()` to `PracticeRound` (the class from the first task): it returns an `ArrayList<String>` of the countries whose capital was answered wrong, each country once, in the order of their first wrong answer. A country stays on the list even when it's answered right later. With an empty box, `answer` counts nothing, so nothing is added to the list either. The check runs:\n\n```java\nCardBox box = new CardBox();\nbox.add(\"Peru\", \"Lima\");\nbox.add(\"Kenya\", \"Nairobi\");\nPracticeRound round = new PracticeRound(box);\nround.answer(\"Cusco\");\nround.answer(\"Nairobi\");\nround.answer(\"Arequipa\");\nSystem.out.println(round.missed());\n```\n\nand expects:\n\n```\n[Peru]\n```\n","kind":"code","seed":"// ==== PracticeRound.java ====\npublic class PracticeRound {\n    private CardBox box;\n    private int next;\n    private int right;\n    private int wrong;\n\n    public PracticeRound(CardBox box) {\n        this.box = box;\n    }\n\n    public String question() {\n        if (this.box.size() == 0) {\n            return null;\n        }\n        return this.box.countryAt(this.next);\n    }\n\n    public boolean answer(String text) {\n        String country = this.question();\n        if (country == null) {\n            return false;\n        }\n        boolean correct = text.trim().equalsIgnoreCase(this.box.capitalOf(country));\n        if (correct) {\n            this.right++;\n        } else {\n            this.wrong++;\n        }\n        this.next++;\n        if (this.next >= this.box.size()) {\n            this.next = 0;\n        }\n        return correct;\n    }\n\n    public int getRight() {\n        return this.right;\n    }\n\n    public int getWrong() {\n        return this.wrong;\n    }\n}\n\n// ==== CardBox.java ====\nimport java.util.ArrayList;\n\npublic class CardBox {\n    private ArrayList<Card> cards;\n\n    public CardBox() {\n        this.cards = new ArrayList<>();\n    }\n\n    public boolean add(String country, String capital) {\n        String name = country.trim();\n        String city = capital.trim();\n        if (name.isEmpty() || city.isEmpty() || this.capitalOf(name) != null) {\n            return false;\n        }\n        this.cards.add(new Card(name, city));\n        return true;\n    }\n\n    public String capitalOf(String country) {\n        for (Card card : this.cards) {\n            if (card.getCountry().equals(country)) {\n                return card.getCapital();\n            }\n        }\n        return null;\n    }\n\n    public String countryAt(int index) {\n        return this.cards.get(index).getCountry();\n    }\n\n    public int size() {\n        return this.cards.size();\n    }\n}\n\n// ==== Card.java ====\npublic class Card {\n    private String country;\n    private String capital;\n\n    public Card(String country, String capital) {\n        this.country = country;\n        this.capital = capital;\n    }\n\n    public String getCountry() {\n        return this.country;\n    }\n\n    public String getCapital() {\n        return this.capital;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        CardBox box = new CardBox();\n        box.add(\"Peru\", \"Lima\");\n        box.add(\"Kenya\", \"Nairobi\");\n        PracticeRound round = new PracticeRound(box);\n        round.answer(\"Cusco\");\n        round.answer(\"Nairobi\");\n        round.answer(\"Arequipa\");\n        System.out.println(round.missed());\n    }\n}\n","solution":"// ==== PracticeRound.java ====\nimport java.util.ArrayList;\n\npublic class PracticeRound {\n    private CardBox box;\n    private int next;\n    private int right;\n    private int wrong;\n    private ArrayList<String> missed;\n\n    public PracticeRound(CardBox box) {\n        this.box = box;\n        this.missed = new ArrayList<>();\n    }\n\n    public String question() {\n        if (this.box.size() == 0) {\n            return null;\n        }\n        return this.box.countryAt(this.next);\n    }\n\n    public boolean answer(String text) {\n        String country = this.question();\n        if (country == null) {\n            return false;\n        }\n        boolean correct = text.trim().equalsIgnoreCase(this.box.capitalOf(country));\n        if (correct) {\n            this.right++;\n        } else {\n            this.wrong++;\n            if (!this.missed.contains(country)) {\n                this.missed.add(country);\n            }\n        }\n        this.next++;\n        if (this.next >= this.box.size()) {\n            this.next = 0;\n        }\n        return correct;\n    }\n\n    public int getRight() {\n        return this.right;\n    }\n\n    public int getWrong() {\n        return this.wrong;\n    }\n\n    public ArrayList<String> missed() {\n        return this.missed;\n    }\n}\n\n// ==== CardBox.java ====\nimport java.util.ArrayList;\n\npublic class CardBox {\n    private ArrayList<Card> cards;\n\n    public CardBox() {\n        this.cards = new ArrayList<>();\n    }\n\n    public boolean add(String country, String capital) {\n        String name = country.trim();\n        String city = capital.trim();\n        if (name.isEmpty() || city.isEmpty() || this.capitalOf(name) != null) {\n            return false;\n        }\n        this.cards.add(new Card(name, city));\n        return true;\n    }\n\n    public String capitalOf(String country) {\n        for (Card card : this.cards) {\n            if (card.getCountry().equals(country)) {\n                return card.getCapital();\n            }\n        }\n        return null;\n    }\n\n    public String countryAt(int index) {\n        return this.cards.get(index).getCountry();\n    }\n\n    public int size() {\n        return this.cards.size();\n    }\n}\n\n// ==== Card.java ====\npublic class Card {\n    private String country;\n    private String capital;\n\n    public Card(String country, String capital) {\n        this.country = country;\n        this.capital = capital;\n    }\n\n    public String getCountry() {\n        return this.country;\n    }\n\n    public String getCapital() {\n        return this.capital;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        CardBox box = new CardBox();\n        box.add(\"Peru\", \"Lima\");\n        box.add(\"Kenya\", \"Nairobi\");\n        PracticeRound round = new PracticeRound(box);\n        round.answer(\"Cusco\");\n        round.answer(\"Nairobi\");\n        round.answer(\"Arequipa\");\n        System.out.println(round.missed());\n    }\n}\n","hints":["Add an instance variable `private ArrayList<String> missed;`, create the list in the constructor, and import `java.util.ArrayList`.","In `answer`, in the branch of a wrong answer, add the country only `if (!this.missed.contains(country))`. `missed()` returns the list."],"tests":[{"name":"Test 1","stdin":"","call":"CardBox box = new CardBox();\nbox.add(\"Peru\", \"Lima\");\nbox.add(\"Kenya\", \"Nairobi\");\nPracticeRound round = new PracticeRound(box);\nround.answer(\"Cusco\");\nround.answer(\"Nairobi\");\nround.answer(\"Arequipa\");\nSystem.out.println(round.missed());\n","expect":"[Peru]","hidden":false},{"name":"Test 2","stdin":"","call":"CardBox box = new CardBox();\nPracticeRound round = new PracticeRound(box);\nround.answer(\"Paris\");\nSystem.out.println(round.missed());\nbox.add(\"Japan\", \"Tokyo\");\nbox.add(\"Chile\", \"Santiago\");\nbox.add(\"Egypt\", \"Cairo\");\nround.answer(\"Tokyo\");\nround.answer(\"Lima\");\nround.answer(\"Luxor\");\nround.answer(\"Kyoto\");\nround.answer(\"Valparaiso\");\nround.answer(\"Cairo\");\nSystem.out.println(round.missed());\nSystem.out.println(round.getRight() + \" \" + round.getWrong());\n","expect":"[]\n[Chile, Egypt, Japan]\n2 4","hidden":true}],"require":[],"forbid":[]},{"task":"The card box and the round together, with a card added in the middle of the training. What does the program print? `CardBox` is the class of this step's text, and `PracticeRound` the one from the first task.\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        CardBox box = new CardBox();\n        box.add(\"Spain\", \"Madrid\");\n        box.add(\"Ghana\", \"Accra\");\n        PracticeRound round = new PracticeRound(box);\n        System.out.println(round.answer(\"Barcelona\") + \" \" + round.question());\n        round.answer(\"accra\");\n        box.add(\"Spain\", \"Seville\");\n        box.add(\"Cuba\", \"Havana\");\n        System.out.println(round.answer(\" MADRID \") + \" \" + round.question());\n        round.answer(\"Havana\");\n        System.out.println(round.question() + \" \" + round.getRight() + \" \" + round.getWrong());\n    }\n}\n// ==== CardBox.java ====\nimport java.util.ArrayList;\n\npublic class CardBox {\n    private ArrayList<Card> cards;\n\n    public CardBox() {\n        this.cards = new ArrayList<>();\n    }\n\n    public boolean add(String country, String capital) {\n        String name = country.trim();\n        String city = capital.trim();\n        if (name.isEmpty() || city.isEmpty() || this.capitalOf(name) != null) {\n            return false;\n        }\n        this.cards.add(new Card(name, city));\n        return true;\n    }\n\n    public String capitalOf(String country) {\n        for (Card card : this.cards) {\n            if (card.getCountry().equals(country)) {\n                return card.getCapital();\n            }\n        }\n        return null;\n    }\n\n    public String countryAt(int index) {\n        return this.cards.get(index).getCountry();\n    }\n\n    public int size() {\n        return this.cards.size();\n    }\n}\n// ==== Card.java ====\npublic class Card {\n    private String country;\n    private String capital;\n\n    public Card(String country, String capital) {\n        this.country = country;\n        this.capital = capital;\n    }\n\n    public String getCountry() {\n        return this.country;\n    }\n\n    public String getCapital() {\n        return this.capital;\n    }\n}\n// ==== PracticeRound.java ====\npublic class PracticeRound {\n    private CardBox box;\n    private int next;\n    private int right;\n    private int wrong;\n\n    public PracticeRound(CardBox box) {\n        this.box = box;\n    }\n\n    public String question() {\n        if (this.box.size() == 0) {\n            return null;\n        }\n        return this.box.countryAt(this.next);\n    }\n\n    public boolean answer(String text) {\n        String country = this.question();\n        if (country == null) {\n            return false;\n        }\n        boolean correct = text.trim().equalsIgnoreCase(this.box.capitalOf(country));\n        if (correct) {\n            this.right++;\n        } else {\n            this.wrong++;\n        }\n        this.next++;\n        if (this.next >= this.box.size()) {\n            this.next = 0;\n        }\n        return correct;\n    }\n\n    public int getRight() {\n        return this.right;\n    }\n\n    public int getWrong() {\n        return this.wrong;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        CardBox box = new CardBox();\n        box.add(\"Spain\", \"Madrid\");\n        box.add(\"Ghana\", \"Accra\");\n        PracticeRound round = new PracticeRound(box);\n        System.out.println(round.answer(\"Barcelona\") + \" \" + round.question());\n        round.answer(\"accra\");\n        box.add(\"Spain\", \"Seville\");\n        box.add(\"Cuba\", \"Havana\");\n        System.out.println(round.answer(\" MADRID \") + \" \" + round.question());\n        round.answer(\"Havana\");\n        System.out.println(round.question() + \" \" + round.getRight() + \" \" + round.getWrong());\n    }\n}\n// ==== CardBox.java ====\nimport java.util.ArrayList;\n\npublic class CardBox {\n    private ArrayList<Card> cards;\n\n    public CardBox() {\n        this.cards = new ArrayList<>();\n    }\n\n    public boolean add(String country, String capital) {\n        String name = country.trim();\n        String city = capital.trim();\n        if (name.isEmpty() || city.isEmpty() || this.capitalOf(name) != null) {\n            return false;\n        }\n        this.cards.add(new Card(name, city));\n        return true;\n    }\n\n    public String capitalOf(String country) {\n        for (Card card : this.cards) {\n            if (card.getCountry().equals(country)) {\n                return card.getCapital();\n            }\n        }\n        return null;\n    }\n\n    public String countryAt(int index) {\n        return this.cards.get(index).getCountry();\n    }\n\n    public int size() {\n        return this.cards.size();\n    }\n}\n// ==== Card.java ====\npublic class Card {\n    private String country;\n    private String capital;\n\n    public Card(String country, String capital) {\n        this.country = country;\n        this.capital = capital;\n    }\n\n    public String getCountry() {\n        return this.country;\n    }\n\n    public String getCapital() {\n        return this.capital;\n    }\n}\n// ==== PracticeRound.java ====\npublic class PracticeRound {\n    private CardBox box;\n    private int next;\n    private int right;\n    private int wrong;\n\n    public PracticeRound(CardBox box) {\n        this.box = box;\n    }\n\n    public String question() {\n        if (this.box.size() == 0) {\n            return null;\n        }\n        return this.box.countryAt(this.next);\n    }\n\n    public boolean answer(String text) {\n        String country = this.question();\n        if (country == null) {\n            return false;\n        }\n        boolean correct = text.trim().equalsIgnoreCase(this.box.capitalOf(country));\n        if (correct) {\n            this.right++;\n        } else {\n            this.wrong++;\n        }\n        this.next++;\n        if (this.next >= this.box.size()) {\n            this.next = 0;\n        }\n        return correct;\n    }\n\n    public int getRight() {\n        return this.right;\n    }\n\n    public int getWrong() {\n        return this.wrong;\n    }\n}\n","hints":["After two answers the turn has gone past Ghana, the last card at that time, so it's back at Spain. Adding Spain a second time is refused, so Spain's capital is still Madrid; Cuba joins the box as its third card.","`answer` trims the text and ignores upper and lower case, so `\" MADRID \"` is right. Then the turn moves to Ghana, and after the answer about Ghana to Cuba."],"tests":[{"name":"Output","stdin":"","expect":"false Ghana\ntrue Ghana\nCuba 2 2","hidden":false}],"require":[],"forbid":[],"lines":["false Ghana","true Ghana","Cuba 2 2"]}]}