{
  "id": "P017",
  "slug": "flashcards",
  "key": "P017-flashcards",
  "title": "Flashcards",
  "summary": "Practise decks of flashcards with Leitner boxes: a card answered right the first time moves up a box, a wrong one goes back to box 1 and comes again at the end of the practice; box k is due every 2^(k-1) practices. Two decks to start, new decks and cards, and a progress chart per deck - from a text menu.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P017 - Flashcards\n\nPractise decks of flashcards the Leitner way. Two decks come with the\nprogram - eight capitals and eight Spanish words - and you can add decks and\ncards. A practice asks the cards that are due; a progress chart shows how\nmany cards sit in each box and what the next practice will ask. Everything\nlives while the program runs.\n\n- `main.eml` - the menu and its questions, the practice itself (a queue of\n  cards), and what the screen shows\n- `leitner.eml` - the boxes: which are due in which practice, the cards due,\n  the count in each box, moving a card up or back\n- `text.eml` - trimming, lower case, whole numbers, and comparing answers\n\nThe Leitner rules: there are five boxes and new cards start in box 1. A card\nanswered right the first time in a practice moves up one box (box 5 is the\ntop); a card answered wrong goes back to box 1. Box k is due in every\npractice whose number is a multiple of 2^(k-1) - box 1 every time, box 2\nevery second time, box 3 every fourth, box 4 every eighth, box 5 every\nsixteenth - so a card that keeps being right is asked less and less often.\n\nA practice puts the due cards in a queue, lowest box first and in the deck's\norder inside a box. A card answered wrongly goes to the back of the queue\nand comes again until it is answered right, but only the first answer of a\npractice moves a card between boxes. Answers are compared without regard to\ncase or the spaces around them. Typing q stops a practice: the cards not yet\nanswered stay where they were, and a practice stopped before any answer does\nnot count.\n\nWhat is checked: a deck number is one that exists; a deck name has at most\n20 characters and is not already taken in any case; a card's front and back\nhave at most 40 characters each and the front is not already in the deck.\nAnything else asks again; nothing cancels.\n\nSessions: `sessions/basic.in` lists the decks, practises the capitals three\ntimes - two wrong answers in the first practice come back at the end; in the\nsecond, boxes 1 and 2 are due and one card falls back to box 1; the third\nasks box 1 alone - with the progress chart after the first and the third, then\nadds a card to the Spanish deck, makes a new deck and adds a card to it;\n`sessions/bad-input.in` types deck numbers that do not exist, deck names that\nare empty, too long or taken, practises an empty deck, adds cards with an\nempty, repeated or too long front and an empty back, stops one practice after\none answer and another before any.\n\nBuilt on the verified corpus case `simple-queue` (a first-in, first-out queue\nin a class: put at the back, take from the front).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P017 flashcards: practise decks of cards with Leitner boxes. A practice\n# asks the cards that are due, in a queue; a card answered wrongly goes to\n# the back of the queue and comes again until it is answered right, but only\n# the first answer of a practice moves a card between boxes.\nimport leitner\nimport text\n\nclass Queue:\n    # First in, first out.\n    def __init__(self):\n        [] => self.items\n\n    def put(self, item):\n        self.items + [item] => self.items\n\n    def take(self):\n        self.items[0] => front\n        self.items[1:len(self.items)] => self.items\n        return front\n\n    def is_empty(self):\n        return len(self.items) == 0\n\ndef plural(n, word):\n    if n == 1:\n        return \"1 \" + word\n    return str(n) + \" \" + word + \"s\"\n\ndef boxes_text(bs):\n    # \"box 1\", \"boxes 1 and 2\", \"boxes 1, 2 and 3\".\n    if len(bs) == 1:\n        return \"box \" + str(bs[0])\n    \"boxes \" => out\n    for i in [0:len(bs) - 2]:\n        if i > 0:\n            out + \", \" => out\n        out + str(bs[i]) => out\n    return out + \" and \" + str(bs[len(bs) - 1])\n\ndef practices_text(deck):\n    if deck[2] == 0:\n        return \"no practice yet\"\n    return plural(deck[2], \"practice\") + \" done\"\n\ndef ask_deck(decks):\n    # A deck, asked again until a good number is typed; None cancels.\n    while True:\n        text.trim(input(\"deck> \")) => answer\n        if answer == \"\":\n            return None\n        text.number(answer) => n\n        if n >= 1 and n <= len(decks):\n            return decks[n - 1]\n        (\"Type a deck number from 1 to \" + str(len(decks)) + \", or nothing to cancel.\") ^0\n\ndef ask_text(prompt, longest):\n    # Text of at most longest characters, asked again until it fits; \"\" cancels.\n    while True:\n        text.trim(input(prompt)) => answer\n        if len(answer) <= longest:\n            return answer\n        (\"At most \" + str(longest) + \" characters.\") ^0\n\ndef show_decks(decks):\n    \"\" ^0\n    \"-- decks --\" ^0\n    for i in [0:len(decks) - 1]:\n        (\"  \" + str(i + 1) + \") \" + (\"%-21s\" % decks[i][0]) + (\"%-10s\" % plural(len(decks[i][1]), \"card\")) + practices_text(decks[i])) ^0\n\ndef bar(n):\n    # Two spaces and one # per card, or nothing for an empty box.\n    if n == 0:\n        return \"\"\n    return \"  \" + (\"#\" * n)\n\ndef show_progress(deck):\n    leitner.box_counts(deck) => counts\n    deck[2] + 1 => coming\n    \"\" ^0\n    (\"-- \" + deck[0] + \": \" + plural(len(deck[1]), \"card\") + \", \" + practices_text(deck) + \" --\") ^0\n    for b in [1:leitner.boxes]:\n        (\"  box \" + str(b) + (\"%4d\" % counts[b - 1]) + bar(counts[b - 1])) ^0\n    (\"  next practice (\" + str(coming) + \"): \" + boxes_text(leitner.due_boxes(coming)) + \" - \" + plural(len(leitner.due_cards(deck, coming)), \"card\")) ^0\n\ndef practice(deck):\n    deck[2] + 1 => n\n    leitner.due_cards(deck, n) => due\n    if len(deck[1]) == 0:\n        \"No cards in this deck yet.\" ^0\n        return\n    (\"Practice \" + str(n) + \" of \" + deck[0] + \": \" + boxes_text(leitner.due_boxes(n)) + \" - \" + plural(len(due), \"card\") + \".\") ^0\n    if len(due) == 0:\n        \"Nothing is due this time.\" ^0\n        n => deck[2]\n        return\n    \"Type the answer, or q to stop.\" ^0\n    Queue() => queue\n    for c in due:\n        queue.put([c, True])\n    0 => answered\n    0 => right\n    while not queue.is_empty():\n        queue.take() => item\n        item[0] => card\n        \"\" ^0\n        (card[0] + \"   (box \" + str(card[2]) + \")\") ^0\n        text.trim(input(\"answer> \")) => answer\n        if answer == \"q\" or answer == \"Q\":\n            if answered == 0:\n                \"Stopped before any answer; this practice does not count.\" ^0\n                return\n            n => deck[2]\n            (\"Stopped: \" + str(right) + \" of \" + str(answered) + \" right the first time; the other cards stay where they were.\") ^0\n            return\n        if text.same(answer, card[1]):\n            if item[1]:\n                leitner.promote(card)\n                answered + 1 => answered\n                right + 1 => right\n                (\"Right - now in box \" + str(card[2]) + \".\") ^0\n            else:\n                \"Right.\" ^0\n        else:\n            if item[1]:\n                leitner.demote(card)\n                answered + 1 => answered\n                (\"No - it is \" + card[1] + \". Back to box 1; it comes again at the end.\") ^0\n            else:\n                (\"No - it is \" + card[1] + \". It comes again at the end.\") ^0\n            queue.put([card, False])\n    n => deck[2]\n    \"\" ^0\n    (\"Practice \" + str(n) + \" done: \" + str(right) + \" of \" + str(len(due)) + \" right the first time.\") ^0\n\n[\n    [\"Capitals\", [[\"France\", \"Paris\", 1], [\"Japan\", \"Tokyo\", 1], [\"Kenya\", \"Nairobi\", 1], [\"Peru\", \"Lima\", 1],\n                  [\"Canada\", \"Ottawa\", 1], [\"Egypt\", \"Cairo\", 1], [\"Norway\", \"Oslo\", 1], [\"Chile\", \"Santiago\", 1]], 0],\n    [\"Spanish\", [[\"dog\", \"perro\", 1], [\"cat\", \"gato\", 1], [\"house\", \"casa\", 1], [\"water\", \"agua\", 1],\n                 [\"red\", \"rojo\", 1], [\"bread\", \"pan\", 1], [\"friend\", \"amigo\", 1], [\"green\", \"verde\", 1]], 0],\n] => decks\nTrue => running\nwhile running:\n    \"\" ^0\n    \"== Flashcards ==\" ^0\n    \"1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\" ^0\n    text.trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        show_decks(decks)\n    elif choice == \"2\":\n        ask_deck(decks) => deck\n        if deck == None:\n            \"Cancelled.\" ^0\n        else:\n            practice(deck)\n    elif choice == \"3\":\n        ask_deck(decks) => deck\n        if deck == None:\n            \"Cancelled.\" ^0\n        else:\n            show_progress(deck)\n    elif choice == \"4\":\n        ask_deck(decks) => deck\n        \"\" => front\n        if deck != None:\n            while True:\n                ask_text(\"front> \", 40) => front\n                None => clash\n                for c in deck[1]:\n                    if front != \"\" and text.same(c[0], front):\n                        c => clash\n                if clash == None:\n                    break\n                (\"There is already a card \" + clash[0] + \" in \" + deck[0] + \".\") ^0\n        \"\" => back\n        if front != \"\":\n            ask_text(\"back> \", 40) => back\n        if back == \"\":\n            \"Cancelled.\" ^0\n        else:\n            deck[1] + [[front, back, 1]] => deck[1]\n            (\"Added to \" + deck[0] + \": \" + front + \" = \" + back + \" (box 1).\") ^0\n    elif choice == \"5\":\n        while True:\n            ask_text(\"deck name> \", 20) => name\n            None => clash\n            for d in decks:\n                if name != \"\" and text.same(d[0], name):\n                    d => clash\n            if clash == None:\n                break\n            (\"There is already a deck called \" + clash[0] + \".\") ^0\n        if name == \"\":\n            \"Cancelled.\" ^0\n        else:\n            decks + [[name, [], 0]] => decks\n            (\"Deck \" + str(len(decks)) + \": \" + name + \".\") ^0\n    elif choice == \"6\":\n        False => running\n    else:\n        \"Pick a number from 1 to 6.\" ^0\n\"Bye.\" ^0\n",
      "python": "import leitner\nimport text\n\nclass Queue:\n    def __init__(self):\n        self.items = []\n    def put(self, item):\n        self.items = self.items + [item]\n    def take(self):\n        front = self.items[0]\n        self.items = self.items[1:len(self.items)]\n        return front\n    def is_empty(self):\n        return len(self.items) == 0\n\ndef plural(n, word):\n    if n == 1:\n        return \"1 \" + word\n    return str(n) + \" \" + word + \"s\"\n\ndef boxes_text(bs):\n    if len(bs) == 1:\n        return \"box \" + str(bs[0])\n    out = \"boxes \"\n    for i in range(0, len(bs) - 2+1):\n        if i > 0:\n            out = out + \", \"\n        out = out + str(bs[i])\n    return out + \" and \" + str(bs[len(bs) - 1])\n\ndef practices_text(deck):\n    if deck[2] == 0:\n        return \"no practice yet\"\n    return plural(deck[2], \"practice\") + \" done\"\n\ndef ask_deck(decks):\n    while True:\n        answer = text.trim(input(\"deck> \"))\n        if answer == \"\":\n            return None\n        n = text.number(answer)\n        if n >= 1 and n <= len(decks):\n            return decks[n - 1]\n        print(\"Type a deck number from 1 to \" + str(len(decks)) + \", or nothing to cancel.\")\n\ndef ask_text(prompt, longest):\n    while True:\n        answer = text.trim(input(prompt))\n        if len(answer) <= longest:\n            return answer\n        print(\"At most \" + str(longest) + \" characters.\")\n\ndef show_decks(decks):\n    print(\"\")\n    print(\"-- decks --\")\n    for i in range(0, len(decks)):\n        print(\"  \" + str(i + 1) + \") \" + \"%-21s\" % decks[i][0] + \"%-10s\" % plural(len(decks[i][1]), \"card\") + practices_text(decks[i]))\n\ndef bar(n):\n    if n == 0:\n        return \"\"\n    return \"  \" + \"#\" * n\n\ndef show_progress(deck):\n    counts = leitner.box_counts(deck)\n    coming = deck[2] + 1\n    print(\"\")\n    print(\"-- \" + deck[0] + \": \" + plural(len(deck[1]), \"card\") + \", \" + practices_text(deck) + \" --\")\n    for b in range(1, leitner.boxes+1):\n        print(\"  box \" + str(b) + \"%4d\" % counts[b - 1] + bar(counts[b - 1]))\n    print(\"  next practice (\" + str(coming) + \"): \" + boxes_text(leitner.due_boxes(coming)) + \" - \" + plural(len(leitner.due_cards(deck, coming)), \"card\"))\n\ndef practice(deck):\n    n = deck[2] + 1\n    due = leitner.due_cards(deck, n)\n    if len(deck[1]) == 0:\n        print(\"No cards in this deck yet.\")\n        return\n    print(\"Practice \" + str(n) + \" of \" + deck[0] + \": \" + boxes_text(leitner.due_boxes(n)) + \" - \" + plural(len(due), \"card\") + \".\")\n    if len(due) == 0:\n        print(\"Nothing is due this time.\")\n        deck[2] = n\n        return\n    print(\"Type the answer, or q to stop.\")\n    queue = Queue()\n    for c in due:\n        queue.put([c, True])\n    answered = 0\n    right = 0\n    while not queue.is_empty():\n        item = queue.take()\n        card = item[0]\n        print(\"\")\n        print(card[0] + \"   (box \" + str(card[2]) + \")\")\n        answer = text.trim(input(\"answer> \"))\n        if answer == \"q\" or answer == \"Q\":\n            if answered == 0:\n                print(\"Stopped before any answer; this practice does not count.\")\n                return\n            deck[2] = n\n            print(\"Stopped: \" + str(right) + \" of \" + str(answered) + \" right the first time; the other cards stay where they were.\")\n            return\n        if text.same(answer, card[1]):\n            if item[1]:\n                leitner.promote(card)\n                answered = answered + 1\n                right = right + 1\n                print(\"Right - now in box \" + str(card[2]) + \".\")\n            else:\n                print(\"Right.\")\n        else:\n            if item[1]:\n                leitner.demote(card)\n                answered = answered + 1\n                print(\"No - it is \" + card[1] + \". Back to box 1; it comes again at the end.\")\n            else:\n                print(\"No - it is \" + card[1] + \". It comes again at the end.\")\n            queue.put([card, False])\n    deck[2] = n\n    print(\"\")\n    print(\"Practice \" + str(n) + \" done: \" + str(right) + \" of \" + str(len(due)) + \" right the first time.\")\n\ndecks = [[\"Capitals\", [[\"France\", \"Paris\", 1], [\"Japan\", \"Tokyo\", 1], [\"Kenya\", \"Nairobi\", 1], [\"Peru\", \"Lima\", 1], [\"Canada\", \"Ottawa\", 1], [\"Egypt\", \"Cairo\", 1], [\"Norway\", \"Oslo\", 1], [\"Chile\", \"Santiago\", 1]], 0], [\"Spanish\", [[\"dog\", \"perro\", 1], [\"cat\", \"gato\", 1], [\"house\", \"casa\", 1], [\"water\", \"agua\", 1], [\"red\", \"rojo\", 1], [\"bread\", \"pan\", 1], [\"friend\", \"amigo\", 1], [\"green\", \"verde\", 1]], 0]]\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"== Flashcards ==\")\n    print(\"1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\")\n    choice = text.trim(input(\"choice> \"))\n    if choice == \"1\":\n        show_decks(decks)\n    elif choice == \"2\":\n        deck = ask_deck(decks)\n        if deck == None:\n            print(\"Cancelled.\")\n        else:\n            practice(deck)\n    elif choice == \"3\":\n        deck = ask_deck(decks)\n        if deck == None:\n            print(\"Cancelled.\")\n        else:\n            show_progress(deck)\n    elif choice == \"4\":\n        deck = ask_deck(decks)\n        front = \"\"\n        if deck != None:\n            while True:\n                front = ask_text(\"front> \", 40)\n                clash = None\n                for c in deck[1]:\n                    if front != \"\" and text.same(c[0], front):\n                        clash = c\n                if clash == None:\n                    break\n                print(\"There is already a card \" + clash[0] + \" in \" + deck[0] + \".\")\n        back = \"\"\n        if front != \"\":\n            back = ask_text(\"back> \", 40)\n        if back == \"\":\n            print(\"Cancelled.\")\n        else:\n            deck[1] = deck[1] + [[front, back, 1]]\n            print(\"Added to \" + deck[0] + \": \" + front + \" = \" + back + \" (box 1).\")\n    elif choice == \"5\":\n        while True:\n            name = ask_text(\"deck name> \", 20)\n            clash = None\n            for d in decks:\n                if name != \"\" and text.same(d[0], name):\n                    clash = d\n            if clash == None:\n                break\n            print(\"There is already a deck called \" + clash[0] + \".\")\n        if name == \"\":\n            print(\"Cancelled.\")\n        else:\n            decks = decks + [[name, [], 0]]\n            print(\"Deck \" + str(len(decks)) + \": \" + name + \".\")\n    elif choice == \"6\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 6.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "leitner.eml",
      "eml": "# P017 flashcards - the Leitner system. A deck is [name, cards, practices\n# done] and a card is [front, back, box]. There are five boxes: new cards\n# start in box 1, a card answered right the first time in a practice moves up\n# one box (box 5 is the top), and a wrong one goes back to box 1. Box k is\n# due in every practice whose number is a multiple of 2^(k-1): box 1 every\n# time, box 2 every second time, box 3 every fourth, and so on.\n\n5 => boxes\n\ndef every(box):\n    # How often box is due: 2^(box - 1) practices.\n    1 => n\n    for i in [2:box]:\n        n * 2 => n\n    return n\n\ndef due_boxes(practice):\n    # The boxes due in practice number practice, lowest first.\n    [] => out\n    for b in [1:boxes]:\n        if practice % every(b) == 0:\n            out + [b] => out\n    return out\n\ndef due_cards(deck, practice):\n    # The cards due in practice number practice: box by box, lowest first,\n    # and in the deck's order inside a box.\n    [] => out\n    for b in due_boxes(practice):\n        for c in deck[1]:\n            if c[2] == b:\n                out + [c] => out\n    return out\n\ndef box_counts(deck):\n    # How many cards are in each box, box 1 first.\n    [] => out\n    for b in [1:boxes]:\n        0 => n\n        for c in deck[1]:\n            if c[2] == b:\n                n + 1 => n\n        out + [n] => out\n    return out\n\ndef promote(card):\n    # A first-time right answer: up one box, no higher than the top.\n    if card[2] < boxes:\n        card[2] + 1 => card[2]\n\ndef demote(card):\n    # A first-time wrong answer: back to box 1.\n    1 => card[2]\n",
      "python": "boxes = 5\n\ndef every(box):\n    n = 1\n    for i in range(2, box+1):\n        n = n * 2\n    return n\n\ndef due_boxes(practice):\n    out = []\n    for b in range(1, boxes+1):\n        if practice % every(b) == 0:\n            out = out + [b]\n    return out\n\ndef due_cards(deck, practice):\n    out = []\n    for b in due_boxes(practice):\n        for c in deck[1]:\n            if c[2] == b:\n                out = out + [c]\n    return out\n\ndef box_counts(deck):\n    out = []\n    for b in range(1, boxes+1):\n        n = 0\n        for c in deck[1]:\n            if c[2] == b:\n                n = n + 1\n        out = out + [n]\n    return out\n\ndef promote(card):\n    if card[2] < boxes:\n        card[2] = card[2] + 1\n\ndef demote(card):\n    card[2] = 1\n"
    },
    {
      "name": "text.eml",
      "eml": "# P017 flashcards - reading what is typed. The interpreter that checks every\n# session does not run string methods yet, so trimming and lower case are\n# written out here.\n\ndef trim(s):\n    # s without the spaces at either end.\n    0 => i\n    len(s) => j\n    while i < j and s[i] == \" \":\n        i + 1 => i\n    while j > i and s[j - 1] == \" \":\n        j - 1 => j\n    return s[i:j]\n\ndef lower(s):\n    # s with A-Z turned into a-z; everything else as it was.\n    \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\" => upper_letters\n    \"abcdefghijklmnopqrstuvwxyz\" => lower_letters\n    \"\" => out\n    for c in s:\n        c => d\n        for i in [0:25]:\n            if upper_letters[i] == c:\n                lower_letters[i] => d\n        out + d => out\n    return out\n\ndef number(s):\n    # The value of s if it is digits only (at least one), otherwise -1.\n    if s == \"\":\n        return 0 - 1\n    0 => n\n    for c in s:\n        if not (c in \"0123456789\"):\n            return 0 - 1\n        n * 10 + int(c) => n\n    return n\n\ndef same(a, b):\n    # a and b equal once trimmed and in lower case.\n    return lower(trim(a)) == lower(trim(b))\n",
      "python": "def trim(s):\n    i = 0\n    j = len(s)\n    while i < j and s[i] == \" \":\n        i = i + 1\n    while j > i and s[j - 1] == \" \":\n        j = j - 1\n    return s[i:j]\n\ndef lower(s):\n    upper_letters = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n    lower_letters = \"abcdefghijklmnopqrstuvwxyz\"\n    out = \"\"\n    for c in s:\n        d = c\n        for i in range(0, 26):\n            if upper_letters[i] == c:\n                d = lower_letters[i]\n        out = out + d\n    return out\n\ndef number(s):\n    if s == \"\":\n        return 0 - 1\n    n = 0\n    for c in s:\n        if not c in \"0123456789\":\n            return 0 - 1\n        n = n * 10 + int(c)\n    return n\n\ndef same(a, b):\n    return lower(trim(a)) == lower(trim(b))\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "7\n2\n0\nx\n\n5\n\n5\nA deck name far too long\ncapitals\nEmpty\n2\n3\n3\n3\n4\n9\n1\n\n4\n1\nfrance\nA front that is far too long for any card here\nItaly\n\n2\n1\nParis\nq\n3\n1\n2\n1\nq\n1\n6\n",
      "screen": "\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 7\nPick a number from 1 to 6.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 2\ndeck> 0\nType a deck number from 1 to 2, or nothing to cancel.\ndeck> x\nType a deck number from 1 to 2, or nothing to cancel.\ndeck> \nCancelled.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 5\ndeck name> \nCancelled.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 5\ndeck name> A deck name far too long\nAt most 20 characters.\ndeck name> capitals\nThere is already a deck called Capitals.\ndeck name> Empty\nDeck 3: Empty.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 2\ndeck> 3\nNo cards in this deck yet.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 3\ndeck> 3\n\n-- Empty: 0 cards, no practice yet --\n  box 1   0\n  box 2   0\n  box 3   0\n  box 4   0\n  box 5   0\n  next practice (1): box 1 - 0 cards\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 4\ndeck> 9\nType a deck number from 1 to 3, or nothing to cancel.\ndeck> 1\nfront> \nCancelled.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 4\ndeck> 1\nfront> france\nThere is already a card France in Capitals.\nfront> A front that is far too long for any card here\nAt most 40 characters.\nfront> Italy\nback> \nCancelled.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 2\ndeck> 1\nPractice 1 of Capitals: box 1 - 8 cards.\nType the answer, or q to stop.\n\nFrance   (box 1)\nanswer> Paris\nRight - now in box 2.\n\nJapan   (box 1)\nanswer> q\nStopped: 1 of 1 right the first time; the other cards stay where they were.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 3\ndeck> 1\n\n-- Capitals: 8 cards, 1 practice done --\n  box 1   7  #######\n  box 2   1  #\n  box 3   0\n  box 4   0\n  box 5   0\n  next practice (2): boxes 1 and 2 - 8 cards\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 2\ndeck> 1\nPractice 2 of Capitals: boxes 1 and 2 - 8 cards.\nType the answer, or q to stop.\n\nJapan   (box 1)\nanswer> q\nStopped before any answer; this practice does not count.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 1\n\n-- decks --\n  1) Capitals             8 cards   1 practice done\n  2) Spanish              8 cards   no practice yet\n  3) Empty                0 cards   no practice yet\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 6\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\n2\n1\nParis\nTokyo\nMombasa\nLima\nToronto\nCairo\nOslo\nSantiago\nNairobi\nottawa\n3\n1\n2\n1\nNairobi\nOttawa\nParis\nTokyo\nLima\nCairo\nBergen\nSantiago\nOslo\n2\n1\nOslo\n3\n1\n4\n2\nbook\nlibro\n5\nScience\n4\n3\nH2O\nwater\n1\n6\n",
      "screen": "\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 1\n\n-- decks --\n  1) Capitals             8 cards   no practice yet\n  2) Spanish              8 cards   no practice yet\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 2\ndeck> 1\nPractice 1 of Capitals: box 1 - 8 cards.\nType the answer, or q to stop.\n\nFrance   (box 1)\nanswer> Paris\nRight - now in box 2.\n\nJapan   (box 1)\nanswer> Tokyo\nRight - now in box 2.\n\nKenya   (box 1)\nanswer> Mombasa\nNo - it is Nairobi. Back to box 1; it comes again at the end.\n\nPeru   (box 1)\nanswer> Lima\nRight - now in box 2.\n\nCanada   (box 1)\nanswer> Toronto\nNo - it is Ottawa. Back to box 1; it comes again at the end.\n\nEgypt   (box 1)\nanswer> Cairo\nRight - now in box 2.\n\nNorway   (box 1)\nanswer> Oslo\nRight - now in box 2.\n\nChile   (box 1)\nanswer> Santiago\nRight - now in box 2.\n\nKenya   (box 1)\nanswer> Nairobi\nRight.\n\nCanada   (box 1)\nanswer> ottawa\nRight.\n\nPractice 1 done: 6 of 8 right the first time.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 3\ndeck> 1\n\n-- Capitals: 8 cards, 1 practice done --\n  box 1   2  ##\n  box 2   6  ######\n  box 3   0\n  box 4   0\n  box 5   0\n  next practice (2): boxes 1 and 2 - 8 cards\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 2\ndeck> 1\nPractice 2 of Capitals: boxes 1 and 2 - 8 cards.\nType the answer, or q to stop.\n\nKenya   (box 1)\nanswer> Nairobi\nRight - now in box 2.\n\nCanada   (box 1)\nanswer> Ottawa\nRight - now in box 2.\n\nFrance   (box 2)\nanswer> Paris\nRight - now in box 3.\n\nJapan   (box 2)\nanswer> Tokyo\nRight - now in box 3.\n\nPeru   (box 2)\nanswer> Lima\nRight - now in box 3.\n\nEgypt   (box 2)\nanswer> Cairo\nRight - now in box 3.\n\nNorway   (box 2)\nanswer> Bergen\nNo - it is Oslo. Back to box 1; it comes again at the end.\n\nChile   (box 2)\nanswer> Santiago\nRight - now in box 3.\n\nNorway   (box 1)\nanswer> Oslo\nRight.\n\nPractice 2 done: 7 of 8 right the first time.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 2\ndeck> 1\nPractice 3 of Capitals: box 1 - 1 card.\nType the answer, or q to stop.\n\nNorway   (box 1)\nanswer> Oslo\nRight - now in box 2.\n\nPractice 3 done: 1 of 1 right the first time.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 3\ndeck> 1\n\n-- Capitals: 8 cards, 3 practices done --\n  box 1   0\n  box 2   3  ###\n  box 3   5  #####\n  box 4   0\n  box 5   0\n  next practice (4): boxes 1, 2 and 3 - 8 cards\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 4\ndeck> 2\nfront> book\nback> libro\nAdded to Spanish: book = libro (box 1).\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 5\ndeck name> Science\nDeck 3: Science.\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 4\ndeck> 3\nfront> H2O\nback> water\nAdded to Science: H2O = water (box 1).\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 1\n\n-- decks --\n  1) Capitals             8 cards   3 practices done\n  2) Spanish              9 cards   no practice yet\n  3) Science              1 card    no practice yet\n\n== Flashcards ==\n1) decks  2) practice  3) progress  4) add card  5) new deck  6) quit\nchoice> 6\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "simple-queue",
      "caseId": "040-simple-queue",
      "title": "Case corpus: a self-authored FIFO queue"
    }
  ],
  "updated": "2026-10-03"
}
