{
  "id": "P032",
  "slug": "vending-machine",
  "key": "P032-vending-machine",
  "title": "Vending machine",
  "summary": "Six products with stock and prices; coins of 5 to 200 cents go in, and change comes out with the fewest coins the machine actually holds - found by dynamic programming over a limited coin box, where taking the biggest coin first can fail. If it cannot make the change the sale is refused and the coins come back. Staff restock products and refill the coin box.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P032 - Vending machine\n\nSix products in slots A1 to B3, each with a price and up to 10 in stock.\nCoins of 5, 10, 20, 50, 100 and 200 cents go in one at a time; once enough is\nin, the product comes out with the change. The change is made from the coins\nthe machine actually holds, with as few coins as possible - and when those\ncoins cannot make it, the sale is refused and the coins put in come back.\nStaff can restock a product and refill the coin box.\n\n- `main.eml` - the menu, the products on screen, buying, restocking,\n  refilling and the machine status\n- `change.eml` - the coin values, amounts shown as money, and the fewest\n  coins that make an amount from a limited coin box\n\nHow each part works:\n\n- The coins put in join the box before the change is worked out, so the\n  change can use them.\n- With an endless supply of every coin, taking the biggest coin that fits\n  always gives the fewest coins for these six values. With the coins a\n  machine really holds it can fail: for 0.60 from a box with one 50, one 5\n  and four 20s it takes the 50, then has only the one 5 for the 10 left and\n  gets stuck, although 20 + 20 + 20 works. So the change is found with the\n  table of the corpus case `coin-change-dp` - the fewest coins for every\n  amount up to the change - built one coin value at a time, each used at\n  most as many times as the box holds it. On a tie the bigger coins are\n  used.\n- When no combination of the coins in the box makes the change, nothing is\n  sold: the coins put in are handed back as they went in.\n- A sale takes one from the stock and adds the price to the takings; the\n  status shows every coin in the box, the money it holds and what was sold.\n\nWhat is checked: a slot from A1 to B3, in either case; only the six coin\nvalues (anything else is refused and asked for again); 0 or an empty answer\nwhile paying gives back the coins put in; at most 10 of a product and at\nmost 50 of each coin; a count as a whole number in the room left. An empty\nanswer cancels.\n\nSessions: `sessions/basic.in` buys a Cola with a 200 coin - the 0.60 change\nis 20 + 20 + 20, where the biggest coin first gets stuck - and a Gum with\n50 and 20 (0.05 back); a Juice paid with two 100s is refused, because the\nbox has no 5 or 10 for the 0.25 change, and the coins come back; after\nrefilling 5s and 10s the same Juice goes through (20 + 5 back); then it pays\na Water exactly, buys a Chocolate with 200 (20 + 20 + 5 back), shows the\nstatus and restocks the Cola. `sessions/bad-input.in` gives menu choices 0\nand x, an unknown slot, coins of 25 and abc, 0 with nothing put in and with\n20 put in, buys the last two Chocolates and asks for a third, restocks with\n11 and 0 before 10, restocks a full slot, cancels a restock and a refill\nwith an empty answer, refills with a coin of 3 and with 50 coins of 200\nwhere 49 fit, then tries the full 200s once more.\n\nBuilt on the verified corpus cases `vending-machine-simulator` (a product\nlist, coins adding up to a balance, and a sale with change or a shortfall)\nand `coin-change-dp` (the fewest coins for an amount from a table, where\nthe biggest coin first is not always right).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P032 vending machine: six products with stock, coins in, change out with the\n# fewest coins the machine actually holds - and if it cannot make the change,\n# the sale is refused and the coins come back. Staff can restock products and\n# refill the coin box.\nimport change\n\n[\"A1\", \"A2\", \"A3\", \"B1\", \"B2\", \"B3\"] => codes\n[\"Water\", \"Cola\", \"Juice\", \"Chips\", \"Chocolate\", \"Gum\"] => names\n[90, 140, 175, 120, 155, 65] => prices\n10 => most_stock\n50 => most_coins\n\ndef trim(s):\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 upper(s):\n    \"abcdefghijklmnopqrstuvwxyz\" => small\n    \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\" => big\n    \"\" => out\n    for c in s:\n        0 => k\n        while k < 26 and small[k] != c:\n            k + 1 => k\n        if k < 26:\n            out + big[k] => out\n        else:\n            out + c => out\n    return out\n\ndef whole_number(s):\n    trim(s) => s\n    if s == \"\" or len(s) > 3:\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 ask_code():\n    # A slot's index, or -1 when the answer is empty.\n    while True:\n        upper(trim(input(\"slot> \"))) => answer\n        if answer == \"\":\n            return 0 - 1\n        for i in [0:len(codes) - 1]:\n            if codes[i] == answer:\n                return i\n        \"Type a slot from A1 to B3.\" ^0\n\ndef show_products(stock):\n    for i in [0:len(codes) - 1]:\n        names[i] => name\n        while len(name) < 10:\n            name + \" \" => name\n        change.money(prices[i]) => price\n        while len(price) < 5:\n            \" \" + price => price\n        \"sold out\" => left\n        if stock[i] > 0:\n            str(stock[i]) + \" left\" => left\n        (\"  \" + codes[i] + \"  \" + name + \"  \" + price + \"  \" + left) ^0\n\ndef buy(state):\n    # state is [stock, coin box, items sold, takings]; returns the new state.\n    state[0] => stock\n    state[1] => box\n    ask_code() => i\n    if i == 0 - 1:\n        \"Cancelled.\" ^0\n        return state\n    if stock[i] == 0:\n        (codes[i] + \" \" + names[i] + \" is sold out.\") ^0\n        return state\n    prices[i] => price\n    (names[i] + \" costs \" + change.money(price) + \". Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\") ^0\n    [] => inserted\n    0 => paid\n    while paid < price:\n        trim(input(\"coin> \")) => answer\n        whole_number(answer) => v\n        if answer == \"\" or v == 0:\n            if len(inserted) == 0:\n                \"Nothing was put in.\" ^0\n            else:\n                (\"Returned: \" + listed_coins(inserted) + \".\") ^0\n            return state\n        if change.coin_index(v) == 0 - 1:\n            \"This machine takes coins of 5, 10, 20, 50, 100 and 200 cents.\" ^0\n        else:\n            inserted + [v] => inserted\n            paid + v => paid\n            if paid < price:\n                (change.money(paid) + \" in, \" + change.money(price - paid) + \" to go.\") ^0\n            else:\n                (change.money(paid) + \" in.\") ^0\n    # the coins put in join the box, and the change can use them\n    [] => after\n    for k in [0:len(change.values) - 1]:\n        box[k] => n\n        for v in inserted:\n            if v == change.values[k]:\n                n + 1 => n\n        after + [n] => after\n    paid - price => owed\n    [0, 0, 0, 0, 0, 0] => used\n    if owed > 0:\n        change.fewest(owed, after) => used\n        if len(used) == 0:\n            (\"Sorry - the machine cannot make \" + change.money(owed) + \" in change from the coins it holds. Returned: \" + listed_coins(inserted) + \".\") ^0\n            return state\n        for k in [0:len(change.values) - 1]:\n            after[k] - used[k] => after[k]\n    stock[0:i] + [stock[i] - 1] + stock[i + 1:len(stock)] => stock\n    if owed == 0:\n        (\"Here is your \" + names[i] + \".\") ^0\n    else:\n        (\"Here is your \" + names[i] + \", with \" + change.money(owed) + \" in change: \" + change.coins_text(used) + \".\") ^0\n    return [stock, after, state[2] + 1, state[3] + price]\n\ndef listed_coins(coins):\n    \"\" => out\n    for v in coins:\n        if out != \"\":\n            out + \", \" => out\n        out + str(v) => out\n    return out\n\ndef restock(state):\n    state[0] => stock\n    ask_code() => i\n    if i == 0 - 1:\n        \"Cancelled.\" ^0\n        return state\n    most_stock - stock[i] => room\n    if room == 0:\n        (codes[i] + \" \" + names[i] + \" is full (\" + str(most_stock) + \").\") ^0\n        return state\n    while True:\n        input(\"add how many (1 to \" + str(room) + \")> \") => answer\n        if trim(answer) == \"\":\n            \"Cancelled.\" ^0\n            return state\n        whole_number(answer) => n\n        if n >= 1 and n <= room:\n            stock[0:i] + [stock[i] + n] + stock[i + 1:len(stock)] => stock\n            (codes[i] + \" \" + names[i] + \": \" + str(stock[i]) + \" now.\") ^0\n            return [stock, state[1], state[2], state[3]]\n        (\"Type a number from 1 to \" + str(room) + \".\") ^0\n\ndef refill(state):\n    state[1] => box\n    0 - 1 => k\n    while k == 0 - 1:\n        trim(input(\"coin (5, 10, 20, 50, 100 or 200)> \")) => answer\n        if answer == \"\":\n            \"Cancelled.\" ^0\n            return state\n        change.coin_index(whole_number(answer)) => k\n        if k == 0 - 1:\n            \"Type one of 5, 10, 20, 50, 100 and 200.\" ^0\n    most_coins - box[k] => room\n    if room == 0:\n        (\"The box is full of \" + str(change.values[k]) + \"s (\" + str(most_coins) + \").\") ^0\n        return state\n    while True:\n        input(\"add how many (1 to \" + str(room) + \")> \") => answer\n        if trim(answer) == \"\":\n            \"Cancelled.\" ^0\n            return state\n        whole_number(answer) => n\n        if n >= 1 and n <= room:\n            box[0:k] + [box[k] + n] + box[k + 1:len(box)] => box\n            (\"The box now has \" + str(box[k]) + \" of \" + str(change.values[k]) + \".\") ^0\n            return [state[0], box, state[2], state[3]]\n        (\"Type a number from 1 to \" + str(room) + \".\") ^0\n\ndef status(state):\n    state[1] => box\n    \"\" => parts\n    0 => total\n    for k in [0:len(change.values) - 1]:\n        if parts != \"\":\n            parts + \", \" => parts\n        parts + str(change.values[k]) + \" x \" + str(box[k]) => parts\n        total + change.values[k] * box[k] => total\n    (\"Coin box: \" + parts + \" - \" + change.money(total) + \" in all.\") ^0\n    if state[2] == 1:\n        (\"Sold 1 item for \" + change.money(state[3]) + \".\") ^0\n    else:\n        (\"Sold \" + str(state[2]) + \" items for \" + change.money(state[3]) + \".\") ^0\n\n\"== Vending machine ==\" ^0\n[[5, 5, 3, 4, 2, 6], [1, 0, 4, 1, 2, 0], 0, 0] => state\nTrue => running\nwhile running:\n    \"\" ^0\n    show_products(state[0])\n    \"1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    if choice == \"1\":\n        buy(state) => state\n    elif choice == \"2\":\n        restock(state) => state\n    elif choice == \"3\":\n        refill(state) => state\n    elif choice == \"4\":\n        status(state)\n    elif choice == \"5\":\n        False => running\n    else:\n        \"Pick a number from 1 to 5.\" ^0\n\"Bye.\" ^0\n",
      "python": "import change\ncodes = [\"A1\", \"A2\", \"A3\", \"B1\", \"B2\", \"B3\"]\nnames = [\"Water\", \"Cola\", \"Juice\", \"Chips\", \"Chocolate\", \"Gum\"]\nprices = [90, 140, 175, 120, 155, 65]\nmost_stock = 10\nmost_coins = 50\n\ndef 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 upper(s):\n    small = \"abcdefghijklmnopqrstuvwxyz\"\n    big = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n    out = \"\"\n    for c in s:\n        k = 0\n        while k < 26 and small[k] != c:\n            k = k + 1\n        if k < 26:\n            out = out + big[k]\n        else:\n            out = out + c\n    return out\n\ndef whole_number(s):\n    s = trim(s)\n    if s == \"\" or len(s) > 3:\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 ask_code():\n    while True:\n        answer = upper(trim(input(\"slot> \")))\n        if answer == \"\":\n            return 0 - 1\n        for i in range(0, len(codes)):\n            if codes[i] == answer:\n                return i\n        print(\"Type a slot from A1 to B3.\")\n\ndef show_products(stock):\n    for i in range(0, len(codes)):\n        name = names[i]\n        while len(name) < 10:\n            name = name + \" \"\n        price = change.money(prices[i])\n        while len(price) < 5:\n            price = \" \" + price\n        left = \"sold out\"\n        if stock[i] > 0:\n            left = str(stock[i]) + \" left\"\n        print(\"  \" + codes[i] + \"  \" + name + \"  \" + price + \"  \" + left)\n\ndef buy(state):\n    stock = state[0]\n    box = state[1]\n    i = ask_code()\n    if i == 0 - 1:\n        print(\"Cancelled.\")\n        return state\n    if stock[i] == 0:\n        print(codes[i] + \" \" + names[i] + \" is sold out.\")\n        return state\n    price = prices[i]\n    print(names[i] + \" costs \" + change.money(price) + \". Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\")\n    inserted = []\n    paid = 0\n    while paid < price:\n        answer = trim(input(\"coin> \"))\n        v = whole_number(answer)\n        if answer == \"\" or v == 0:\n            if len(inserted) == 0:\n                print(\"Nothing was put in.\")\n            else:\n                print(\"Returned: \" + listed_coins(inserted) + \".\")\n            return state\n        if change.coin_index(v) == 0 - 1:\n            print(\"This machine takes coins of 5, 10, 20, 50, 100 and 200 cents.\")\n        else:\n            inserted = inserted + [v]\n            paid = paid + v\n            if paid < price:\n                print(change.money(paid) + \" in, \" + change.money(price - paid) + \" to go.\")\n            else:\n                print(change.money(paid) + \" in.\")\n    after = []\n    for k in range(0, len(change.values)):\n        n = box[k]\n        for v in inserted:\n            if v == change.values[k]:\n                n = n + 1\n        after = after + [n]\n    owed = paid - price\n    used = [0, 0, 0, 0, 0, 0]\n    if owed > 0:\n        used = change.fewest(owed, after)\n        if len(used) == 0:\n            print(\"Sorry - the machine cannot make \" + change.money(owed) + \" in change from the coins it holds. Returned: \" + listed_coins(inserted) + \".\")\n            return state\n        for k in range(0, len(change.values)):\n            after[k] = after[k] - used[k]\n    stock = stock[0:i] + [stock[i] - 1] + stock[i + 1:len(stock)]\n    if owed == 0:\n        print(\"Here is your \" + names[i] + \".\")\n    else:\n        print(\"Here is your \" + names[i] + \", with \" + change.money(owed) + \" in change: \" + change.coins_text(used) + \".\")\n    return [stock, after, state[2] + 1, state[3] + price]\n\ndef listed_coins(coins):\n    out = \"\"\n    for v in coins:\n        if out != \"\":\n            out = out + \", \"\n        out = out + str(v)\n    return out\n\ndef restock(state):\n    stock = state[0]\n    i = ask_code()\n    if i == 0 - 1:\n        print(\"Cancelled.\")\n        return state\n    room = most_stock - stock[i]\n    if room == 0:\n        print(codes[i] + \" \" + names[i] + \" is full (\" + str(most_stock) + \").\")\n        return state\n    while True:\n        answer = input(\"add how many (1 to \" + str(room) + \")> \")\n        if trim(answer) == \"\":\n            print(\"Cancelled.\")\n            return state\n        n = whole_number(answer)\n        if n >= 1 and n <= room:\n            stock = stock[0:i] + [stock[i] + n] + stock[i + 1:len(stock)]\n            print(codes[i] + \" \" + names[i] + \": \" + str(stock[i]) + \" now.\")\n            return [stock, state[1], state[2], state[3]]\n        print(\"Type a number from 1 to \" + str(room) + \".\")\n\ndef refill(state):\n    box = state[1]\n    k = 0 - 1\n    while k == 0 - 1:\n        answer = trim(input(\"coin (5, 10, 20, 50, 100 or 200)> \"))\n        if answer == \"\":\n            print(\"Cancelled.\")\n            return state\n        k = change.coin_index(whole_number(answer))\n        if k == 0 - 1:\n            print(\"Type one of 5, 10, 20, 50, 100 and 200.\")\n    room = most_coins - box[k]\n    if room == 0:\n        print(\"The box is full of \" + str(change.values[k]) + \"s (\" + str(most_coins) + \").\")\n        return state\n    while True:\n        answer = input(\"add how many (1 to \" + str(room) + \")> \")\n        if trim(answer) == \"\":\n            print(\"Cancelled.\")\n            return state\n        n = whole_number(answer)\n        if n >= 1 and n <= room:\n            box = box[0:k] + [box[k] + n] + box[k + 1:len(box)]\n            print(\"The box now has \" + str(box[k]) + \" of \" + str(change.values[k]) + \".\")\n            return [state[0], box, state[2], state[3]]\n        print(\"Type a number from 1 to \" + str(room) + \".\")\n\ndef status(state):\n    box = state[1]\n    parts = \"\"\n    total = 0\n    for k in range(0, len(change.values)):\n        if parts != \"\":\n            parts = parts + \", \"\n        parts = parts + str(change.values[k]) + \" x \" + str(box[k])\n        total = total + change.values[k] * box[k]\n    print(\"Coin box: \" + parts + \" - \" + change.money(total) + \" in all.\")\n    if state[2] == 1:\n        print(\"Sold 1 item for \" + change.money(state[3]) + \".\")\n    else:\n        print(\"Sold \" + str(state[2]) + \" items for \" + change.money(state[3]) + \".\")\n\nprint(\"== Vending machine ==\")\nstate = [[5, 5, 3, 4, 2, 6], [1, 0, 4, 1, 2, 0], 0, 0]\nrunning = True\nwhile running:\n    print(\"\")\n    show_products(state[0])\n    print(\"1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\")\n    choice = trim(input(\"choice> \"))\n    if choice == \"1\":\n        state = buy(state)\n    elif choice == \"2\":\n        state = restock(state)\n    elif choice == \"3\":\n        state = refill(state)\n    elif choice == \"4\":\n        status(state)\n    elif choice == \"5\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 5.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "change.eml",
      "eml": "# P032 vending machine - coins and change. Amounts are whole cents.\n#\n# Change is made from the coins actually in the machine, so the number of\n# each coin is limited. With limited coins \"always take the biggest coin\"\n# can fail even where it never fails with an endless supply (60 cents from\n# 50, 20, 20, 20 is 20 + 20 + 20, not 50 + something), so the fewest coins\n# are found with the dynamic-programming table of the corpus case\n# coin-change-dp, one coin value at a time, each used at most as many times\n# as the machine holds it.\n\n[5, 10, 20, 50, 100, 200] => values\n\ndef quotient(a, b):\n    return int((a - a % b) / b)\n\ndef money(cents):\n    # 140 as \"1.40\".\n    str(cents % 100) => c\n    if len(c) < 2:\n        \"0\" + c => c\n    return str(quotient(cents, 100)) + \".\" + c\n\ndef coin_index(cents):\n    for i in [0:len(values) - 1]:\n        if values[i] == cents:\n            return i\n    return 0 - 1\n\ndef fewest(amount, counts):\n    # How many of each coin value make `amount` with the fewest coins, using\n    # at most counts[i] of values[i]; [] when no combination makes it. On a\n    # tie the bigger coins are used: the table takes as many of each value\n    # as it can while staying optimal, from the biggest down.\n    1000000 => none\n    [0] + [none] * amount => best\n    [] => took\n    for i in [0:len(values) - 1]:\n        values[i] => v\n        [none] * (amount + 1) => now\n        [0] * (amount + 1) => k_at\n        for a in [0:amount]:\n            quotient(a, v) => most\n            if counts[i] < most:\n                counts[i] => most\n            for k in [0:most]:\n                if best[a - k * v] + k <= now[a] and best[a - k * v] < none:\n                    best[a - k * v] + k => now[a]\n                    k => k_at[a]\n        now => best\n        took + [k_at] => took\n    if best[amount] >= none:\n        return []\n    [0] * len(values) => out\n    amount => a\n    len(values) - 1 => i\n    while i >= 0:\n        took[i][a] => k\n        k => out[i]\n        a - k * values[i] => a\n        i - 1 => i\n    return out\n\ndef coins_text(used):\n    # [0, 1, 0, 1, 0, 0] as \"50 + 10\", biggest first.\n    \"\" => out\n    len(values) - 1 => i\n    while i >= 0:\n        for n in [1:used[i]]:\n            if out != \"\":\n                out + \" + \" => out\n            out + str(values[i]) => out\n        i - 1 => i\n    return out\n",
      "python": "values = [5, 10, 20, 50, 100, 200]\n\ndef quotient(a, b):\n    return int((a - a % b) / b)\n\ndef money(cents):\n    c = str(cents % 100)\n    if len(c) < 2:\n        c = \"0\" + c\n    return str(quotient(cents, 100)) + \".\" + c\n\ndef coin_index(cents):\n    for i in range(0, len(values)):\n        if values[i] == cents:\n            return i\n    return 0 - 1\n\ndef fewest(amount, counts):\n    none = 1000000\n    best = [0] + [none] * amount\n    took = []\n    for i in range(0, len(values)):\n        v = values[i]\n        now = [none] * (amount + 1)\n        k_at = [0] * (amount + 1)\n        for a in range(0, amount+1):\n            most = quotient(a, v)\n            if counts[i] < most:\n                most = counts[i]\n            for k in range(0, most+1):\n                if best[a - k * v] + k <= now[a] and best[a - k * v] < none:\n                    now[a] = best[a - k * v] + k\n                    k_at[a] = k\n        best = now\n        took = took + [k_at]\n    if best[amount] >= none:\n        return []\n    out = [0] * len(values)\n    a = amount\n    i = len(values) - 1\n    while i >= 0:\n        k = took[i][a]\n        out[i] = k\n        a = a - k * values[i]\n        i = i - 1\n    return out\n\ndef coins_text(used):\n    out = \"\"\n    i = len(values) - 1\n    while i >= 0:\n        for n in range(1, used[i]+1):\n            if out != \"\":\n                out = out + \" + \"\n            out = out + str(values[i])\n        i = i - 1\n    return out\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n1\nC1\n\n1\nB3\n25\nabc\n0\n1\nB3\n20\n0\n1\nB2\n100\n50\n5\n1\nB2\n200\n1\nB2\n2\nB2\n11\n0\n10\n2\nb2\n2\nA1\n\n3\n\n3\n3\n200\n50\n49\n3\n200\n4\n5\n",
      "screen": "== Vending machine ==\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 0\nPick a number from 1 to 5.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> x\nPick a number from 1 to 5.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> C1\nType a slot from A1 to B3.\nslot> \nCancelled.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> B3\nGum costs 0.65. Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\ncoin> 25\nThis machine takes coins of 5, 10, 20, 50, 100 and 200 cents.\ncoin> abc\nThis machine takes coins of 5, 10, 20, 50, 100 and 200 cents.\ncoin> 0\nNothing was put in.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> B3\nGum costs 0.65. Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\ncoin> 20\n0.20 in, 0.45 to go.\ncoin> 0\nReturned: 20.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> B2\nChocolate costs 1.55. Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\ncoin> 100\n1.00 in, 0.55 to go.\ncoin> 50\n1.50 in, 0.05 to go.\ncoin> 5\n1.55 in.\nHere is your Chocolate.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  1 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> B2\nChocolate costs 1.55. Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\ncoin> 200\n2.00 in.\nHere is your Chocolate, with 0.45 in change: 20 + 20 + 5.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  sold out\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> B2\nB2 Chocolate is sold out.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  sold out\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 2\nslot> B2\nadd how many (1 to 10)> 11\nType a number from 1 to 10.\nadd how many (1 to 10)> 0\nType a number from 1 to 10.\nadd how many (1 to 10)> 10\nB2 Chocolate: 10 now.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  10 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 2\nslot> b2\nB2 Chocolate is full (10).\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  10 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 2\nslot> A1\nadd how many (1 to 5)> \nCancelled.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  10 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 3\ncoin (5, 10, 20, 50, 100 or 200)> \nCancelled.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  10 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 3\ncoin (5, 10, 20, 50, 100 or 200)> 3\nType one of 5, 10, 20, 50, 100 and 200.\ncoin (5, 10, 20, 50, 100 or 200)> 200\nadd how many (1 to 49)> 50\nType a number from 1 to 49.\nadd how many (1 to 49)> 49\nThe box now has 50 of 200.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  10 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 3\ncoin (5, 10, 20, 50, 100 or 200)> 200\nThe box is full of 200s (50).\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  10 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 4\nCoin box: 5 x 1, 10 x 0, 20 x 2, 50 x 2, 100 x 3, 200 x 50 - 104.45 in all.\nSold 2 items for 3.10.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  10 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "1\nA2\n200\n1\nb3\n50\n20\n1\nA3\n100\n100\n3\n5\n10\n3\n10\n20\n1\nA3\n100\n100\n1\nA1\n50\n20\n20\n1\nB2\n200\n4\n2\nA2\n5\n5\n",
      "screen": "== Vending machine ==\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  5 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> A2\nCola costs 1.40. Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\ncoin> 200\n2.00 in.\nHere is your Cola, with 0.60 in change: 20 + 20 + 20.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  4 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  6 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> b3\nGum costs 0.65. Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\ncoin> 50\n0.50 in, 0.15 to go.\ncoin> 20\n0.70 in.\nHere is your Gum, with 0.05 in change: 5.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  4 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  5 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> A3\nJuice costs 1.75. Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\ncoin> 100\n1.00 in, 0.75 to go.\ncoin> 100\n2.00 in.\nSorry - the machine cannot make 0.25 in change from the coins it holds. Returned: 100, 100.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  4 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  5 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 3\ncoin (5, 10, 20, 50, 100 or 200)> 5\nadd how many (1 to 50)> 10\nThe box now has 10 of 5.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  4 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  5 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 3\ncoin (5, 10, 20, 50, 100 or 200)> 10\nadd how many (1 to 50)> 20\nThe box now has 20 of 10.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  4 left\n  A3  Juice        1.75  3 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  5 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> A3\nJuice costs 1.75. Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\ncoin> 100\n1.00 in, 0.75 to go.\ncoin> 100\n2.00 in.\nHere is your Juice, with 0.25 in change: 20 + 5.\n\n  A1  Water        0.90  5 left\n  A2  Cola         1.40  4 left\n  A3  Juice        1.75  2 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  5 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> A1\nWater costs 0.90. Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\ncoin> 50\n0.50 in, 0.40 to go.\ncoin> 20\n0.70 in, 0.20 to go.\ncoin> 20\n0.90 in.\nHere is your Water.\n\n  A1  Water        0.90  4 left\n  A2  Cola         1.40  4 left\n  A3  Juice        1.75  2 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  2 left\n  B3  Gum          0.65  5 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 1\nslot> B2\nChocolate costs 1.55. Insert coins: 5, 10, 20, 50, 100 or 200 cents; 0 gives them back.\ncoin> 200\n2.00 in.\nHere is your Chocolate, with 0.45 in change: 20 + 20 + 5.\n\n  A1  Water        0.90  4 left\n  A2  Cola         1.40  4 left\n  A3  Juice        1.75  2 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  1 left\n  B3  Gum          0.65  5 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 4\nCoin box: 5 x 8, 10 x 20, 20 x 1, 50 x 3, 100 x 4, 200 x 2 - 12.10 in all.\nSold 5 items for 6.25.\n\n  A1  Water        0.90  4 left\n  A2  Cola         1.40  4 left\n  A3  Juice        1.75  2 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  1 left\n  B3  Gum          0.65  5 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 2\nslot> A2\nadd how many (1 to 6)> 5\nA2 Cola: 9 now.\n\n  A1  Water        0.90  4 left\n  A2  Cola         1.40  9 left\n  A3  Juice        1.75  2 left\n  B1  Chips        1.20  4 left\n  B2  Chocolate    1.55  1 left\n  B3  Gum          0.65  5 left\n1) buy  2) restock a product  3) refill coins  4) machine status  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "vending-machine-simulator",
      "caseId": "064-vending-machine-simulator",
      "title": "Vending machine simulator"
    },
    {
      "slug": "coin-change-dp",
      "caseId": "082-coin-change-dp",
      "title": "Coin change (dynamic programming)"
    }
  ],
  "updated": "2026-10-06"
}
