{
  "id": "P020",
  "slug": "text-adventure",
  "key": "P020-text-adventure",
  "title": "Text adventure",
  "summary": "Explore an old house of eight rooms on a grid - go, take, drop and use things, light a lamp for the dark cellar, unlock a door with the key found there - and carry the crown out to the garden to win; a map shows the rooms you know, and a path command finds a route through them by backtracking.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P020 - Text adventure\n\nA small text adventure in an old house of eight rooms. Somewhere inside is a\ngolden crown; carry it out to the garden to win. Commands are typed as words\n- go north (or just n), take lamp, use key - and the game keeps what you\ncarry, where each thing lies, which doors are locked and which rooms you\nknow.\n\n- `main.eml` - reading commands, the game rules, and the descriptions\n- `world.eml` - the rooms on a grid, the doors between them, and the things\n  at the start\n- `route.eml` - the map of the rooms you know, and finding a route between\n  rooms by backtracking\n- `text.eml` - lower case, words, and lists like \"a lamp, a key and a book\"\n\nThe house is a three-by-three grid of positions holding eight rooms, each\nwith a column and a row. The way to the crown takes four things in order:\nthe oil lamp from the kitchen, lit, for the cellar, which is pitch dark\nwithout it (a lit lamp lights a room whether you carry it or put it down);\nthe iron key the cellar hides; the key used in the hall to unlock the study\ndoor; and the crown, carried out to the garden. The book in the library gives\na hint. The game counts your moves.\n\n`map` draws the grid with the rooms you have been in by name (* marks where\nyou are) and the others as ?; from the tower you can see the whole house, so\nthe map shows every room after you climb it. `path` finds a way to a room you\nhave been in, through rooms you have been in and doors that are open: it\ntries each door in turn - north, east, south, west - goes deeper, and steps\nback when a way leads nowhere. The house has no loops, so the way it finds\nis the only one, and so the shortest.\n\nCommands: look, go north/east/south/west (or n, e, s, w), take (or get),\ndrop and use a thing, inventory (i), map, path to a room, help, quit.\nAnything else is answered with a hint to type help.\n\nSessions: `sessions/basic.in` plays the whole game - the lamp and the book,\nthe dark cellar lit up, the key, a path back to the hall, the locked study\nopened, the crown, the tower and its full map - and wins in 13 moves;\n`sessions/bad-input.in` types an unknown command, nothing, a direction that\nis not one, a locked door, two directions at once, things that are not there\nor not carried, paths to rooms that do not exist or are not known yet, walks\ninto the garden without the crown, leaves the lamp behind before the cellar,\nlights it, puts it down inside the cellar and still sees, tries the key\nwhere there is no lock, and quits.\n\nBuilt on the verified corpus cases `maze-solver-backtracking` (a way through\na grid found by trying each direction and stepping back) and\n`grid-coordinate-map` (places kept by their grid coordinates).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P020 text adventure: explore an old house, find the crown and carry it out\n# to the garden. Commands are typed as words - go north (or just n), take\n# lamp, use key - and the game keeps what you carry, where each thing lies,\n# which doors are locked and which rooms you know.\nimport world\nimport route\nimport text\n\ndef can_see(here, where, lamp_lit):\n    # A dark room can be seen only with the lit lamp in it.\n    if not world.rooms[here][4]:\n        return True\n    world.thing_named(\"lamp\") => lamp\n    return lamp_lit and (where[lamp] == 0 - 1 or where[lamp] == here)\n\ndef describe(here, where, locked, lamp_lit):\n    \"\" ^0\n    (\"-- \" + world.rooms[here][0] + \" --\") ^0\n    if can_see(here, where, lamp_lit):\n        world.rooms[here][3] ^0\n        [] => seen\n        for i in [0:len(world.things) - 1]:\n            if where[i] == here:\n                seen + [world.things[i][1]] => seen\n        if len(seen) > 0:\n            (\"You see \" + text.listed(seen) + \".\") ^0\n    else:\n        \"It is pitch dark. You cannot see a thing.\" ^0\n    [] => ways\n    for d in world.directions:\n        world.door_from(here, d) => door\n        if door != None:\n            if locked[door[0]]:\n                ways + [d + \" (locked)\"] => ways\n            else:\n                ways + [d] => ways\n    (\"Exits: \" + text.listed(ways) + \".\") ^0\n\ndef direction(word):\n    # The full direction for north/n, east/e, south/s, west/w, or \"\".\n    for d in world.directions:\n        if word == d or word == d[0:1]:\n            return d\n    return \"\"\n\ndef plural(n, word):\n    if n == 1:\n        return \"1 \" + word\n    return str(n) + \" \" + word + \"s\"\n\nworld.start_room => here\n[] => where\nfor t in world.things:\n    where + [t[2]] => where\n[] => locked\nfor d in world.doors:\n    locked + [False] => locked\nTrue => locked[world.study_door]\n[] => visited\n[] => known\nfor r in world.rooms:\n    visited + [False] => visited\n    known + [False] => known\nTrue => visited[here]\nTrue => known[here]\nFalse => lamp_lit\n0 => moves\nFalse => won\nTrue => playing\n\n\"An old house. Somewhere inside is a golden crown: carry it out to the garden to win.\" ^0\n\"Type help for the commands.\" ^0\ndescribe(here, where, locked, lamp_lit)\nwhile playing:\n    \"\" ^0\n    text.words(text.lower(input(\"> \"))) => ws\n    \"\" => verb\n    \"\" => rest\n    if len(ws) > 0:\n        ws[0] => verb\n        text.joined(ws[1:len(ws)]) => rest\n    if direction(verb) != \"\" and rest == \"\":\n        \"go\" => verb\n        direction(ws[0]) => rest\n    if verb == \"\":\n        \"Type a command, or help.\" ^0\n    elif verb == \"go\":\n        direction(rest) => d\n        if d == \"\":\n            \"Go where? North, east, south or west.\" ^0\n        elif world.door_from(here, d) == None:\n            (\"You cannot go \" + d + \" from here.\") ^0\n        elif locked[world.door_from(here, d)[0]]:\n            \"The door is locked.\" ^0\n        else:\n            world.door_from(here, d)[1] => here\n            moves + 1 => moves\n            True => visited[here]\n            True => known[here]\n            if world.rooms[here][0] == \"Tower\":\n                for i in [0:len(known) - 1]:\n                    True => known[i]\n            describe(here, where, locked, lamp_lit)\n            if here == world.goal_room and where[world.thing_named(\"crown\")] == 0 - 1:\n                \"\"^0\n                (\"You carry the crown out into the garden. You have won, in \" + plural(moves, \"move\") + \"!\") ^0\n                True => won\n                False => playing\n    elif verb == \"look\" or verb == \"l\":\n        describe(here, where, locked, lamp_lit)\n    elif verb == \"take\" or verb == \"get\" or verb == \"drop\" or verb == \"use\":\n        0 - 1 => t\n        if rest != \"\":\n            text.words(rest) => names\n            world.thing_named(names[len(names) - 1]) => t\n        if rest == \"\":\n            (\"What do you want to \" + verb + \"?\") ^0\n        elif verb == \"take\" or verb == \"get\":\n            if not can_see(here, where, lamp_lit):\n                \"It is too dark to see anything here.\" ^0\n            elif t == 0 - 1 or where[t] != here:\n                (\"There is no \" + rest + \" here.\") ^0\n            else:\n                0 - 1 => where[t]\n                (\"You take \" + world.things[t][1] + \".\") ^0\n        elif t == 0 - 1 or where[t] != 0 - 1:\n            (\"You do not have the \" + rest + \".\") ^0\n        elif verb == \"drop\":\n            here => where[t]\n            (\"You drop \" + world.things[t][1] + \".\") ^0\n        elif world.things[t][0] == \"lamp\":\n            if lamp_lit:\n                \"The lamp is already lit.\" ^0\n            else:\n                True => lamp_lit\n                \"You light the lamp.\" ^0\n                if world.rooms[here][4]:\n                    describe(here, where, locked, lamp_lit)\n        elif world.things[t][0] == \"key\":\n            if world.doors[world.study_door][0] != here:\n                \"There is nothing here to unlock.\" ^0\n            elif locked[world.study_door]:\n                False => locked[world.study_door]\n                \"You unlock the study door with the iron key.\" ^0\n            else:\n                \"The study door is already unlocked.\" ^0\n        elif world.things[t][0] == \"book\":\n            \"You open the book. A note in the margin says: the crown is kept in the study, and the study key is kept below the kitchen.\" ^0\n        else:\n            \"It is too precious to wear. Carry it out to the garden.\" ^0\n    elif verb == \"inventory\" or verb == \"i\":\n        [] => mine\n        for i in [0:len(world.things) - 1]:\n            if where[i] == 0 - 1:\n                mine + [world.things[i][1]] => mine\n        if len(mine) == 0:\n            \"You are carrying nothing.\" ^0\n        else:\n            (\"You are carrying \" + text.listed(mine) + \".\") ^0\n    elif verb == \"map\":\n        for line in route.map_lines(here, known):\n            line ^0\n        \"(* is where you are; ? is a room you have not seen.)\" ^0\n    elif verb == \"path\":\n        0 - 1 => goal\n        for i in [0:len(world.rooms) - 1]:\n            if text.lower(world.rooms[i][0]) == rest:\n                i => goal\n        if rest == \"\":\n            \"A path to which room?\" ^0\n        elif goal == 0 - 1:\n            (\"There is no room called \" + rest + \".\") ^0\n        elif goal == here:\n            (\"You are already in the \" + world.rooms[here][0] + \".\") ^0\n        elif not visited[goal]:\n            (\"You have not been to the \" + world.rooms[goal][0] + \" yet.\") ^0\n        else:\n            route.route(here, goal, locked, visited) => steps\n            if steps == None:\n                \"There is no way there through the rooms you have been in.\" ^0\n            else:\n                \"\" => line\n                for i in [0:len(steps) - 1]:\n                    if i > 0:\n                        line + \", then \" => line\n                    line + steps[i] => line\n                (\"From the \" + world.rooms[here][0] + \" to the \" + world.rooms[goal][0] + \": \" + line + \".\") ^0\n    elif verb == \"help\":\n        \"Commands: look, go north/east/south/west (or n, e, s, w), take, drop and use a thing,\" ^0\n        \"inventory (i), map, path to a room you have been in (path kitchen), quit.\" ^0\n    elif verb == \"quit\":\n        \"You leave the house without the crown.\" ^0\n        False => playing\n    else:\n        \"I do not understand that. Type help for the commands.\" ^0\n\"Bye.\" ^0\n",
      "python": "import world\nimport route\nimport text\n\ndef can_see(here, where, lamp_lit):\n    if not world.rooms[here][4]:\n        return True\n    lamp = world.thing_named(\"lamp\")\n    return lamp_lit and (where[lamp] == 0 - 1 or where[lamp] == here)\n\ndef describe(here, where, locked, lamp_lit):\n    print(\"\")\n    print(\"-- \" + world.rooms[here][0] + \" --\")\n    if can_see(here, where, lamp_lit):\n        print(world.rooms[here][3])\n        seen = []\n        for i in range(0, len(world.things)):\n            if where[i] == here:\n                seen = seen + [world.things[i][1]]\n        if len(seen) > 0:\n            print(\"You see \" + text.listed(seen) + \".\")\n    else:\n        print(\"It is pitch dark. You cannot see a thing.\")\n    ways = []\n    for d in world.directions:\n        door = world.door_from(here, d)\n        if door != None:\n            if locked[door[0]]:\n                ways = ways + [d + \" (locked)\"]\n            else:\n                ways = ways + [d]\n    print(\"Exits: \" + text.listed(ways) + \".\")\n\ndef direction(word):\n    for d in world.directions:\n        if word == d or word == d[0:1]:\n            return d\n    return \"\"\n\ndef plural(n, word):\n    if n == 1:\n        return \"1 \" + word\n    return str(n) + \" \" + word + \"s\"\n\nhere = world.start_room\nwhere = []\nfor t in world.things:\n    where = where + [t[2]]\nlocked = []\nfor d in world.doors:\n    locked = locked + [False]\nlocked[world.study_door] = True\nvisited = []\nknown = []\nfor r in world.rooms:\n    visited = visited + [False]\n    known = known + [False]\nvisited[here] = True\nknown[here] = True\nlamp_lit = False\nmoves = 0\nwon = False\nplaying = True\nprint(\"An old house. Somewhere inside is a golden crown: carry it out to the garden to win.\")\nprint(\"Type help for the commands.\")\ndescribe(here, where, locked, lamp_lit)\nwhile playing:\n    print(\"\")\n    ws = text.words(text.lower(input(\"> \")))\n    verb = \"\"\n    rest = \"\"\n    if len(ws) > 0:\n        verb = ws[0]\n        rest = text.joined(ws[1:len(ws)])\n    if direction(verb) != \"\" and rest == \"\":\n        verb = \"go\"\n        rest = direction(ws[0])\n    if verb == \"\":\n        print(\"Type a command, or help.\")\n    elif verb == \"go\":\n        d = direction(rest)\n        if d == \"\":\n            print(\"Go where? North, east, south or west.\")\n        elif world.door_from(here, d) == None:\n            print(\"You cannot go \" + d + \" from here.\")\n        elif locked[world.door_from(here, d)[0]]:\n            print(\"The door is locked.\")\n        else:\n            here = world.door_from(here, d)[1]\n            moves = moves + 1\n            visited[here] = True\n            known[here] = True\n            if world.rooms[here][0] == \"Tower\":\n                for i in range(0, len(known)):\n                    known[i] = True\n            describe(here, where, locked, lamp_lit)\n            if here == world.goal_room and where[world.thing_named(\"crown\")] == 0 - 1:\n                print(\"\")\n                print(\"You carry the crown out into the garden. You have won, in \" + plural(moves, \"move\") + \"!\")\n                won = True\n                playing = False\n    elif verb == \"look\" or verb == \"l\":\n        describe(here, where, locked, lamp_lit)\n    elif verb == \"take\" or verb == \"get\" or verb == \"drop\" or verb == \"use\":\n        t = 0 - 1\n        if rest != \"\":\n            names = text.words(rest)\n            t = world.thing_named(names[len(names) - 1])\n        if rest == \"\":\n            print(\"What do you want to \" + verb + \"?\")\n        elif verb == \"take\" or verb == \"get\":\n            if not can_see(here, where, lamp_lit):\n                print(\"It is too dark to see anything here.\")\n            elif t == 0 - 1 or where[t] != here:\n                print(\"There is no \" + rest + \" here.\")\n            else:\n                where[t] = 0 - 1\n                print(\"You take \" + world.things[t][1] + \".\")\n        elif t == 0 - 1 or where[t] != 0 - 1:\n            print(\"You do not have the \" + rest + \".\")\n        elif verb == \"drop\":\n            where[t] = here\n            print(\"You drop \" + world.things[t][1] + \".\")\n        elif world.things[t][0] == \"lamp\":\n            if lamp_lit:\n                print(\"The lamp is already lit.\")\n            else:\n                lamp_lit = True\n                print(\"You light the lamp.\")\n                if world.rooms[here][4]:\n                    describe(here, where, locked, lamp_lit)\n        elif world.things[t][0] == \"key\":\n            if world.doors[world.study_door][0] != here:\n                print(\"There is nothing here to unlock.\")\n            elif locked[world.study_door]:\n                locked[world.study_door] = False\n                print(\"You unlock the study door with the iron key.\")\n            else:\n                print(\"The study door is already unlocked.\")\n        elif world.things[t][0] == \"book\":\n            print(\"You open the book. A note in the margin says: the crown is kept in the study, and the study key is kept below the kitchen.\")\n        else:\n            print(\"It is too precious to wear. Carry it out to the garden.\")\n    elif verb == \"inventory\" or verb == \"i\":\n        mine = []\n        for i in range(0, len(world.things)):\n            if where[i] == 0 - 1:\n                mine = mine + [world.things[i][1]]\n        if len(mine) == 0:\n            print(\"You are carrying nothing.\")\n        else:\n            print(\"You are carrying \" + text.listed(mine) + \".\")\n    elif verb == \"map\":\n        for line in route.map_lines(here, known):\n            print(line)\n        print(\"(* is where you are; ? is a room you have not seen.)\")\n    elif verb == \"path\":\n        goal = 0 - 1\n        for i in range(0, len(world.rooms)):\n            if text.lower(world.rooms[i][0]) == rest:\n                goal = i\n        if rest == \"\":\n            print(\"A path to which room?\")\n        elif goal == 0 - 1:\n            print(\"There is no room called \" + rest + \".\")\n        elif goal == here:\n            print(\"You are already in the \" + world.rooms[here][0] + \".\")\n        elif not visited[goal]:\n            print(\"You have not been to the \" + world.rooms[goal][0] + \" yet.\")\n        else:\n            steps = route.route(here, goal, locked, visited)\n            if steps == None:\n                print(\"There is no way there through the rooms you have been in.\")\n            else:\n                line = \"\"\n                for i in range(0, len(steps)):\n                    if i > 0:\n                        line = line + \", then \"\n                    line = line + steps[i]\n                print(\"From the \" + world.rooms[here][0] + \" to the \" + world.rooms[goal][0] + \": \" + line + \".\")\n    elif verb == \"help\":\n        print(\"Commands: look, go north/east/south/west (or n, e, s, w), take, drop and use a thing,\")\n        print(\"inventory (i), map, path to a room you have been in (path kitchen), quit.\")\n    elif verb == \"quit\":\n        print(\"You leave the house without the crown.\")\n        playing = False\n    else:\n        print(\"I do not understand that. Type help for the commands.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "world.eml",
      "eml": "# P020 text adventure - the house: rooms on a grid, the doors between them,\n# and the things in it at the start. A room is [name, column, row,\n# description, dark]; a door is [room, direction, room] and works both ways;\n# a thing is [name, description, starting room].\n\n[\n    [\"Library\", 0, 0, \"Shelves of dusty books reach up to the ceiling.\", False],\n    [\"Study\", 1, 0, \"A quiet study with a heavy oak desk.\", False],\n    [\"Tower\", 2, 0, \"A narrow room at the top of the tower. From its window you can see the whole house.\", False],\n    [\"Kitchen\", 0, 1, \"A cold kitchen. Pots hang from hooks above the stove.\", False],\n    [\"Hall\", 1, 1, \"A wide hall with a stone floor. Doors lead off in every direction.\", False],\n    [\"Gallery\", 2, 1, \"Old portraits watch you from the walls.\", False],\n    [\"Cellar\", 0, 2, \"A low cellar that smells of earth.\", True],\n    [\"Garden\", 1, 2, \"An overgrown garden behind the house, with a gate to the road.\", False],\n] => rooms\n\n[\"north\", \"east\", \"south\", \"west\"] => directions\n\n[\n    [4, \"north\", 1],\n    [4, \"west\", 3],\n    [4, \"east\", 5],\n    [4, \"south\", 7],\n    [3, \"north\", 0],\n    [3, \"south\", 6],\n    [5, \"north\", 2],\n] => doors\n\n# The door from the hall to the study (door 0) is locked at the start.\n0 => study_door\n\n[\n    [\"lamp\", \"an oil lamp\", 3],\n    [\"key\", \"an iron key\", 6],\n    [\"crown\", \"a golden crown\", 1],\n    [\"book\", \"an old book\", 0],\n] => things\n\n4 => start_room\n7 => goal_room\n\ndef opposite(d):\n    if d == \"north\":\n        return \"south\"\n    if d == \"south\":\n        return \"north\"\n    if d == \"east\":\n        return \"west\"\n    return \"east\"\n\ndef door_from(room, d):\n    # [door number, the room it leads to] for the door going d from room, or\n    # None if there is no door that way.\n    for k in [0:len(doors) - 1]:\n        if doors[k][0] == room and doors[k][1] == d:\n            return [k, doors[k][2]]\n        if doors[k][2] == room and opposite(doors[k][1]) == d:\n            return [k, doors[k][0]]\n    return None\n\ndef room_at(column, row):\n    # The room at a grid position, or -1 if there is none.\n    for i in [0:len(rooms) - 1]:\n        if rooms[i][1] == column and rooms[i][2] == row:\n            return i\n    return 0 - 1\n\ndef thing_named(name):\n    # The thing called name, or -1.\n    for i in [0:len(things) - 1]:\n        if things[i][0] == name:\n            return i\n    return 0 - 1\n",
      "python": "rooms = [[\"Library\", 0, 0, \"Shelves of dusty books reach up to the ceiling.\", False], [\"Study\", 1, 0, \"A quiet study with a heavy oak desk.\", False], [\"Tower\", 2, 0, \"A narrow room at the top of the tower. From its window you can see the whole house.\", False], [\"Kitchen\", 0, 1, \"A cold kitchen. Pots hang from hooks above the stove.\", False], [\"Hall\", 1, 1, \"A wide hall with a stone floor. Doors lead off in every direction.\", False], [\"Gallery\", 2, 1, \"Old portraits watch you from the walls.\", False], [\"Cellar\", 0, 2, \"A low cellar that smells of earth.\", True], [\"Garden\", 1, 2, \"An overgrown garden behind the house, with a gate to the road.\", False]]\ndirections = [\"north\", \"east\", \"south\", \"west\"]\ndoors = [[4, \"north\", 1], [4, \"west\", 3], [4, \"east\", 5], [4, \"south\", 7], [3, \"north\", 0], [3, \"south\", 6], [5, \"north\", 2]]\nstudy_door = 0\nthings = [[\"lamp\", \"an oil lamp\", 3], [\"key\", \"an iron key\", 6], [\"crown\", \"a golden crown\", 1], [\"book\", \"an old book\", 0]]\nstart_room = 4\ngoal_room = 7\n\ndef opposite(d):\n    if d == \"north\":\n        return \"south\"\n    if d == \"south\":\n        return \"north\"\n    if d == \"east\":\n        return \"west\"\n    return \"east\"\n\ndef door_from(room, d):\n    for k in range(0, len(doors)):\n        if doors[k][0] == room and doors[k][1] == d:\n            return [k, doors[k][2]]\n        if doors[k][2] == room and opposite(doors[k][1]) == d:\n            return [k, doors[k][0]]\n    return None\n\ndef room_at(column, row):\n    for i in range(0, len(rooms)):\n        if rooms[i][1] == column and rooms[i][2] == row:\n            return i\n    return 0 - 1\n\ndef thing_named(name):\n    for i in range(0, len(things)):\n        if things[i][0] == name:\n            return i\n    return 0 - 1\n"
    },
    {
      "name": "route.eml",
      "eml": "# P020 text adventure - the map of the rooms you know, and a route between\n# rooms by backtracking: try each open door in turn (north, east, south,\n# west) into a room you have been in and not yet on this route, go deeper,\n# and step back when a way leads nowhere. The house has no loops, so the\n# route found is the only one.\nimport world\n\ndef search(here, goal, on_route, locked, visited):\n    # The directions from here to goal, or None if there is no way.\n    if here == goal:\n        return []\n    True => on_route[here]\n    for d in world.directions:\n        world.door_from(here, d) => door\n        if door != None and not locked[door[0]] and visited[door[1]] and not on_route[door[1]]:\n            search(door[1], goal, on_route, locked, visited) => rest\n            if rest != None:\n                return [d] + rest\n    False => on_route[here]\n    return None\n\ndef route(here, goal, locked, visited):\n    [] => on_route\n    for r in world.rooms:\n        on_route + [False] => on_route\n    return search(here, goal, on_route, locked, visited)\n\ndef map_lines(here, known):\n    # The house as a grid: a room you know by name (* where you are), one you\n    # do not as ?, and nothing where there is no room.\n    [] => lines\n    for row in [0:2]:\n        \"  \" => line\n        for column in [0:2]:\n            world.room_at(column, row) => r\n            \"\" => cell\n            if r != 0 - 1 and known[r]:\n                world.rooms[r][0] => cell\n                if r == here:\n                    cell + \"*\" => cell\n            elif r != 0 - 1:\n                \"?\" => cell\n            line + (\"%-10s\" % cell) => line\n        len(line) => j\n        while j > 0 and line[j - 1] == \" \":\n            j - 1 => j\n        lines + [line[0:j]] => lines\n    return lines\n",
      "python": "import world\n\ndef search(here, goal, on_route, locked, visited):\n    if here == goal:\n        return []\n    on_route[here] = True\n    for d in world.directions:\n        door = world.door_from(here, d)\n        if door != None and not locked[door[0]] and visited[door[1]] and not on_route[door[1]]:\n            rest = search(door[1], goal, on_route, locked, visited)\n            if rest != None:\n                return [d] + rest\n    on_route[here] = False\n    return None\n\ndef route(here, goal, locked, visited):\n    on_route = []\n    for r in world.rooms:\n        on_route = on_route + [False]\n    return search(here, goal, on_route, locked, visited)\n\ndef map_lines(here, known):\n    lines = []\n    for row in range(0, 3):\n        line = \"  \"\n        for column in range(0, 3):\n            r = world.room_at(column, row)\n            cell = \"\"\n            if r != 0 - 1 and known[r]:\n                cell = world.rooms[r][0]\n                if r == here:\n                    cell = cell + \"*\"\n            elif r != 0 - 1:\n                cell = \"?\"\n            line = line + \"%-10s\" % cell\n        j = len(line)\n        while j > 0 and line[j - 1] == \" \":\n            j = j - 1\n        lines = lines + [line[0:j]]\n    return lines\n"
    },
    {
      "name": "text.eml",
      "eml": "# P020 text adventure - reading commands. The interpreter that checks every\n# session does not run string methods yet, so the text handling is written\n# out here.\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 words(s):\n    # The words of s, split at spaces.\n    [] => out\n    \"\" => word\n    for c in s + \" \":\n        if c == \" \":\n            if word != \"\":\n                out + [word] => out\n            \"\" => word\n        else:\n            word + c => word\n    return out\n\ndef joined(ws):\n    # Words put back together with single spaces.\n    \"\" => out\n    for w in ws:\n        if out != \"\":\n            out + \" \" => out\n        out + w => out\n    return out\n\ndef listed(items):\n    # \"a lamp\", \"a lamp and a key\", \"a lamp, a key and a book\".\n    if len(items) == 1:\n        return items[0]\n    \"\" => out\n    for i in [0:len(items) - 2]:\n        if i > 0:\n            out + \", \" => out\n        out + items[i] => out\n    return out + \" and \" + items[len(items) - 1]\n",
      "python": "def 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 words(s):\n    out = []\n    word = \"\"\n    for c in s + \" \":\n        if c == \" \":\n            if word != \"\":\n                out = out + [word]\n            word = \"\"\n        else:\n            word = word + c\n    return out\n\ndef joined(ws):\n    out = \"\"\n    for w in ws:\n        if out != \"\":\n            out = out + \" \"\n        out = out + w\n    return out\n\ndef listed(items):\n    if len(items) == 1:\n        return items[0]\n    out = \"\"\n    for i in range(0, len(items) - 2+1):\n        if i > 0:\n            out = out + \", \"\n        out = out + items[i]\n    return out + \" and \" + items[len(items) - 1]\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "dance\n\ngo\ngo up\nn\nnorth east\ntake\ntake sword\ndrop lamp\nuse key\ni\npath cellar\npath attic\npath hall\npath\ns\nn\nw\ntake lamp\ndrop lamp\ns\ntake key\nuse lamp\nn\ntake lamp\nuse lamp\nuse lamp\ns\ndrop lamp\ntake key\nuse key\nn\nmap\nquit\n",
      "screen": "An old house. Somewhere inside is a golden crown: carry it out to the garden to win.\nType help for the commands.\n\n-- Hall --\nA wide hall with a stone floor. Doors lead off in every direction.\nExits: north (locked), east, south and west.\n\n> dance\nI do not understand that. Type help for the commands.\n\n> \nType a command, or help.\n\n> go\nGo where? North, east, south or west.\n\n> go up\nGo where? North, east, south or west.\n\n> n\nThe door is locked.\n\n> north east\nI do not understand that. Type help for the commands.\n\n> take\nWhat do you want to take?\n\n> take sword\nThere is no sword here.\n\n> drop lamp\nYou do not have the lamp.\n\n> use key\nYou do not have the key.\n\n> i\nYou are carrying nothing.\n\n> path cellar\nYou have not been to the Cellar yet.\n\n> path attic\nThere is no room called attic.\n\n> path hall\nYou are already in the Hall.\n\n> path\nA path to which room?\n\n> s\n\n-- Garden --\nAn overgrown garden behind the house, with a gate to the road.\nExits: north.\n\n> n\n\n-- Hall --\nA wide hall with a stone floor. Doors lead off in every direction.\nExits: north (locked), east, south and west.\n\n> w\n\n-- Kitchen --\nA cold kitchen. Pots hang from hooks above the stove.\nYou see an oil lamp.\nExits: north, east and south.\n\n> take lamp\nYou take an oil lamp.\n\n> drop lamp\nYou drop an oil lamp.\n\n> s\n\n-- Cellar --\nIt is pitch dark. You cannot see a thing.\nExits: north.\n\n> take key\nIt is too dark to see anything here.\n\n> use lamp\nYou do not have the lamp.\n\n> n\n\n-- Kitchen --\nA cold kitchen. Pots hang from hooks above the stove.\nYou see an oil lamp.\nExits: north, east and south.\n\n> take lamp\nYou take an oil lamp.\n\n> use lamp\nYou light the lamp.\n\n> use lamp\nThe lamp is already lit.\n\n> s\n\n-- Cellar --\nA low cellar that smells of earth.\nYou see an iron key.\nExits: north.\n\n> drop lamp\nYou drop an oil lamp.\n\n> take key\nYou take an iron key.\n\n> use key\nThere is nothing here to unlock.\n\n> n\n\n-- Kitchen --\nA cold kitchen. Pots hang from hooks above the stove.\nExits: north, east and south.\n\n> map\n  ?         ?         ?\n  Kitchen*  Hall      ?\n  Cellar    Garden\n(* is where you are; ? is a room you have not seen.)\n\n> quit\nYou leave the house without the crown.\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "look\nmap\nw\ntake lamp\nn\ntake book\nuse book\ns\ns\ntake key\nuse lamp\ntake key\ni\npath hall\nn\ne\nn\nuse key\nn\ntake crown\ns\ne\nn\nmap\ns\nw\ns\n",
      "screen": "An old house. Somewhere inside is a golden crown: carry it out to the garden to win.\nType help for the commands.\n\n-- Hall --\nA wide hall with a stone floor. Doors lead off in every direction.\nExits: north (locked), east, south and west.\n\n> look\n\n-- Hall --\nA wide hall with a stone floor. Doors lead off in every direction.\nExits: north (locked), east, south and west.\n\n> map\n  ?         ?         ?\n  ?         Hall*     ?\n  ?         ?\n(* is where you are; ? is a room you have not seen.)\n\n> w\n\n-- Kitchen --\nA cold kitchen. Pots hang from hooks above the stove.\nYou see an oil lamp.\nExits: north, east and south.\n\n> take lamp\nYou take an oil lamp.\n\n> n\n\n-- Library --\nShelves of dusty books reach up to the ceiling.\nYou see an old book.\nExits: south.\n\n> take book\nYou take an old book.\n\n> use book\nYou open the book. A note in the margin says: the crown is kept in the study, and the study key is kept below the kitchen.\n\n> s\n\n-- Kitchen --\nA cold kitchen. Pots hang from hooks above the stove.\nExits: north, east and south.\n\n> s\n\n-- Cellar --\nIt is pitch dark. You cannot see a thing.\nExits: north.\n\n> take key\nIt is too dark to see anything here.\n\n> use lamp\nYou light the lamp.\n\n-- Cellar --\nA low cellar that smells of earth.\nYou see an iron key.\nExits: north.\n\n> take key\nYou take an iron key.\n\n> i\nYou are carrying an oil lamp, an iron key and an old book.\n\n> path hall\nFrom the Cellar to the Hall: north, then east.\n\n> n\n\n-- Kitchen --\nA cold kitchen. Pots hang from hooks above the stove.\nExits: north, east and south.\n\n> e\n\n-- Hall --\nA wide hall with a stone floor. Doors lead off in every direction.\nExits: north (locked), east, south and west.\n\n> n\nThe door is locked.\n\n> use key\nYou unlock the study door with the iron key.\n\n> n\n\n-- Study --\nA quiet study with a heavy oak desk.\nYou see a golden crown.\nExits: south.\n\n> take crown\nYou take a golden crown.\n\n> s\n\n-- Hall --\nA wide hall with a stone floor. Doors lead off in every direction.\nExits: north, east, south and west.\n\n> e\n\n-- Gallery --\nOld portraits watch you from the walls.\nExits: north and west.\n\n> n\n\n-- Tower --\nA narrow room at the top of the tower. From its window you can see the whole house.\nExits: south.\n\n> map\n  Library   Study     Tower*\n  Kitchen   Hall      Gallery\n  Cellar    Garden\n(* is where you are; ? is a room you have not seen.)\n\n> s\n\n-- Gallery --\nOld portraits watch you from the walls.\nExits: north and west.\n\n> w\n\n-- Hall --\nA wide hall with a stone floor. Doors lead off in every direction.\nExits: north, east, south and west.\n\n> s\n\n-- Garden --\nAn overgrown garden behind the house, with a gate to the road.\nExits: north.\n\nYou carry the crown out into the garden. You have won, in 13 moves!\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "maze-solver-backtracking",
      "caseId": "116-maze-solver-backtracking",
      "title": "Maze solver (backtracking)"
    },
    {
      "slug": "grid-coordinate-map",
      "caseId": "172-grid-coordinate-map",
      "title": "A grid keyed by (row, col)"
    }
  ],
  "updated": "2026-10-03"
}
