{
  "id": "P048",
  "slug": "2048",
  "key": "P048-2048",
  "title": "2048",
  "summary": "Slide the tiles of a 4 x 4 board - or 3 x 3 to 6 x 6 - up, down, left or right: two equal tiles that meet join into one with their sum, each tile once a move, and every move that changes the board brings a new 2 or 4. Reach the goal tile and keep going until no move is left; the same seed brings the same tiles.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P048 - 2048\n\nSlide every tile on the board up, down, left or right. Two equal tiles that\nmeet join into one tile holding their sum, and the sum is added to your\nscore. Every move that changes the board brings a new tile. Try to reach the\ngoal tile - 2048, unless a new game sets another - and keep going until no\nmove is left.\n\n- `main.eml` - the menu, the moves and their messages, and a new game with\n  its size, goal and seed\n- `board.eml` - the board: sliding a row, turning the board for the other\n  directions, the new tiles, and whether a move is left\n- `rng.eml` - random numbers written in EML, the generator of P008\n\nHow each part works:\n\n- A row slides left in two steps. First the tiles close up. Then two equal\n  tiles side by side join, taken from the left, and a tile joins at most\n  once a move: `2 2 2 2` becomes `4 4`, not `8`.\n- The other directions reuse the left slide on a turned board, and turn the\n  result back. Right reverses each row; up transposes the board, as in the\n  corpus case `matrix-transpose-manual`; down transposes it and reverses\n  each row. So the tiles join from the side they move towards.\n- A move that changes nothing is not a move: no new tile comes, and the\n  move count stays the same. Otherwise a new tile appears on an empty cell,\n  every empty cell equally likely: a 2 nine times in ten, a 4 otherwise. The\n  random numbers come from EML code, so a seed brings the same tiles on\n  every machine.\n- A move is left while a cell is empty or two equal tiles touch, side by\n  side or one above the other. When none is left the game is over, and its\n  score is shown.\n\nWhat is checked: moves as w, a, s and d, or as up, left, down and right;\nn for a new game, q to quit. A new game takes a size from 3 to 6, a goal\nthat is a power of two from 8 to 65536, and a seed from 0 to 999999999. An\nempty answer cancels.\n\nSessions: `sessions/basic.in` makes eight moves on the default board (seed\n2026). The second move lines up `2 2 2 2` along the top, and the third turns\nit into `4 4` for 8 points. A down move joins `2 2` near the top of a\ncolumn whose bottom tiles do not join. Then a new 3 x 3 game with goal 32\n(seed 318) runs to the end. A left move joins three rows at once, 4 + 8 +\n32 points, and makes the goal on move 21. The board is full after 26 moves,\nwith no two equal tiles touching, and the score is 152.\n\n`sessions/bad-input.in` gives:\n- the moves x and an empty one;\n- moves written as up and left;\n- up when nothing can move up;\n- a new game that first gets sizes 2, 7 and x, goals 4, 12 (not a power of\n  two) and 100000, and seed abc. It then runs a 3 x 3 game with goal 8\n  (seed 261) to the end: the goal is made on move 5, and the game is over\n  after 18 moves with a score of 72;\n- a move after that;\n- a new game cancelled at each of its three questions.\n\nBuilt on the verified corpus case `matrix-transpose-manual` (a list of\nlists transposed by hand, column by column).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P048 2048: slide the tiles; two equal tiles that meet join into one with\n# their sum, and every move brings a new tile. Reach the goal tile - 2048\n# unless a new game sets another - and keep going until no move is left.\nimport board\nimport rng\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 number(s):\n    if s == \"\" or len(s) > 9:\n        return -1\n    0 => n\n    for c in s:\n        if not (c in \"0123456789\"):\n            return -1\n        n * 10 + int(c) => n\n    return n\n\ndef show(game):\n    for line in board.drawn(game[0]):\n        line ^0\n    (\"Score \" + str(game[2]) + \", moves \" + str(game[3]) + \", largest tile \" + str(board.largest(game[0])) + \".\") ^0\n\ndef start(size, goal, seed):\n    (\"A board of \" + str(size) + \" x \" + str(size) + \", goal \" + str(goal) + \", seed \" + str(seed) + \".\") ^0\n    # [board, the generator, score, moves, goal, goal reached, over]\n    [board.empty_board(size), rng.Rng(seed), 0, 0, goal, False, False] => game\n    board.add_tile(game[0], game[1])\n    board.add_tile(game[0], game[1])\n    show(game)\n    return game\n\ndef play(game, direction):\n    if game[6]:\n        \"No move is left - start a new game.\" ^0\n        return game\n    board.moved(game[0], direction) => res\n    if res[0] == game[0]:\n        (\"Nothing moves \" + direction + \".\") ^0\n        return game\n    res[0] => game[0]\n    game[2] + res[1] => game[2]\n    game[3] + 1 => game[3]\n    board.add_tile(game[0], game[1])\n    show(game)\n    if not game[5] and board.largest(game[0]) >= game[4]:\n        True => game[5]\n        (\"You made \" + str(game[4]) + \" in \" + str(game[3]) + \" moves - keep going if you like.\") ^0\n    if not board.can_move(game[0]):\n        True => game[6]\n        (\"No move is left. Game over: score \" + str(game[2]) + \", largest tile \" + str(board.largest(game[0])) + \", \" + str(game[3]) + \" moves.\") ^0\n    return game\n\ndef ask_number(prompt, low, high):\n    while True:\n        trim(input(prompt + \" (\" + str(low) + \" to \" + str(high) + \")> \")) => answer\n        if answer == \"\":\n            return -1\n        number(answer) => n\n        if n >= low and n <= high:\n            return n\n        (\"Type a number from \" + str(low) + \" to \" + str(high) + \".\") ^0\n\ndef power_of_two(n):\n    while n > 1 and n % 2 == 0:\n        int(n / 2) => n\n    return n == 1\n\ndef new_game(game):\n    ask_number(\"size\", 3, 6) => size\n    if size == -1:\n        \"Cancelled.\" ^0\n        return game\n    -1 => goal\n    while goal == -1:\n        ask_number(\"goal\", 8, 65536) => goal\n        if goal == -1:\n            \"Cancelled.\" ^0\n            return game\n        if not power_of_two(goal):\n            \"The goal is a tile, so a power of two: 8, 16, 32 and so on.\" ^0\n            -1 => goal\n    ask_number(\"seed\", 0, 999999999) => seed\n    if seed == -1:\n        \"Cancelled.\" ^0\n        return game\n    return start(size, goal, seed)\n\n\"== 2048 ==\" ^0\n\"Slide the tiles: two equal tiles that meet join into one. Every move brings a new tile.\" ^0\nstart(4, 2048, 2026) => game\nTrue => running\nwhile running:\n    \"\" ^0\n    \"w) up  a) left  s) down  d) right  n) new game  q) quit\" ^0\n    trim(input(\"move> \")) => choice\n    if choice == \"w\" or choice == \"up\":\n        play(game, \"up\") => game\n    elif choice == \"a\" or choice == \"left\":\n        play(game, \"left\") => game\n    elif choice == \"s\" or choice == \"down\":\n        play(game, \"down\") => game\n    elif choice == \"d\" or choice == \"right\":\n        play(game, \"right\") => game\n    elif choice == \"n\":\n        new_game(game) => game\n    elif choice == \"q\":\n        False => running\n    else:\n        \"Type w, a, s or d to move, n for a new game or q to quit.\" ^0\n\"Bye.\" ^0\n",
      "python": "import board\nimport rng\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 number(s):\n    if s == \"\" or len(s) > 9:\n        return -1\n    n = 0\n    for c in s:\n        if not c in \"0123456789\":\n            return -1\n        n = n * 10 + int(c)\n    return n\n\ndef show(game):\n    for line in board.drawn(game[0]):\n        print(line)\n    print(\"Score \" + str(game[2]) + \", moves \" + str(game[3]) + \", largest tile \" + str(board.largest(game[0])) + \".\")\n\ndef start(size, goal, seed):\n    print(\"A board of \" + str(size) + \" x \" + str(size) + \", goal \" + str(goal) + \", seed \" + str(seed) + \".\")\n    game = [board.empty_board(size), rng.Rng(seed), 0, 0, goal, False, False]\n    board.add_tile(game[0], game[1])\n    board.add_tile(game[0], game[1])\n    show(game)\n    return game\n\ndef play(game, direction):\n    if game[6]:\n        print(\"No move is left - start a new game.\")\n        return game\n    res = board.moved(game[0], direction)\n    if res[0] == game[0]:\n        print(\"Nothing moves \" + direction + \".\")\n        return game\n    game[0] = res[0]\n    game[2] = game[2] + res[1]\n    game[3] = game[3] + 1\n    board.add_tile(game[0], game[1])\n    show(game)\n    if not game[5] and board.largest(game[0]) >= game[4]:\n        game[5] = True\n        print(\"You made \" + str(game[4]) + \" in \" + str(game[3]) + \" moves - keep going if you like.\")\n    if not board.can_move(game[0]):\n        game[6] = True\n        print(\"No move is left. Game over: score \" + str(game[2]) + \", largest tile \" + str(board.largest(game[0])) + \", \" + str(game[3]) + \" moves.\")\n    return game\n\ndef ask_number(prompt, low, high):\n    while True:\n        answer = trim(input(prompt + \" (\" + str(low) + \" to \" + str(high) + \")> \"))\n        if answer == \"\":\n            return -1\n        n = number(answer)\n        if n >= low and n <= high:\n            return n\n        print(\"Type a number from \" + str(low) + \" to \" + str(high) + \".\")\n\ndef power_of_two(n):\n    while n > 1 and n % 2 == 0:\n        n = int(n / 2)\n    return n == 1\n\ndef new_game(game):\n    size = ask_number(\"size\", 3, 6)\n    if size == -1:\n        print(\"Cancelled.\")\n        return game\n    goal = -1\n    while goal == -1:\n        goal = ask_number(\"goal\", 8, 65536)\n        if goal == -1:\n            print(\"Cancelled.\")\n            return game\n        if not power_of_two(goal):\n            print(\"The goal is a tile, so a power of two: 8, 16, 32 and so on.\")\n            goal = -1\n    seed = ask_number(\"seed\", 0, 999999999)\n    if seed == -1:\n        print(\"Cancelled.\")\n        return game\n    return start(size, goal, seed)\n\nprint(\"== 2048 ==\")\nprint(\"Slide the tiles: two equal tiles that meet join into one. Every move brings a new tile.\")\ngame = start(4, 2048, 2026)\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"w) up  a) left  s) down  d) right  n) new game  q) quit\")\n    choice = trim(input(\"move> \"))\n    if choice == \"w\" or choice == \"up\":\n        game = play(game, \"up\")\n    elif choice == \"a\" or choice == \"left\":\n        game = play(game, \"left\")\n    elif choice == \"s\" or choice == \"down\":\n        game = play(game, \"down\")\n    elif choice == \"d\" or choice == \"right\":\n        game = play(game, \"right\")\n    elif choice == \"n\":\n        game = new_game(game)\n    elif choice == \"q\":\n        running = False\n    else:\n        print(\"Type w, a, s or d to move, n for a new game or q to quit.\")\nprint(\"Bye.\")\n"
    },
    {
      "name": "board.eml",
      "eml": "# P048 2048 - the board: a list of rows of numbers, 0 for an empty cell.\n\ndef empty_board(size):\n    [] => b\n    for r in [1:size]:\n        b + [[0] * size] => b\n    return b\n\ndef slid_left(row):\n    # One row pushed to the left. The tiles close up, then two equal tiles\n    # side by side join into one, taken from the left, and a tile joins at\n    # most once a move: 2 2 2 2 gives 4 4, not 8. Returns [the row, the\n    # points gained - the value of every joined tile].\n    [] => tiles\n    for x in row:\n        if x != 0:\n            tiles + [x] => tiles\n    [] => out\n    0 => gained\n    0 => i\n    while i < len(tiles):\n        if i + 1 < len(tiles) and tiles[i] == tiles[i + 1]:\n            out + [tiles[i] * 2] => out\n            gained + tiles[i] * 2 => gained\n            i + 2 => i\n        else:\n            out + [tiles[i]] => out\n            i + 1 => i\n    while len(out) < len(row):\n        out + [0] => out\n    return [out, gained]\n\ndef reversed_rows(b):\n    [] => out\n    for row in b:\n        [] => r\n        for x in row:\n            [x] + r => r\n        out + [r] => out\n    return out\n\ndef transposed(b):\n    # The corpus case matrix-transpose-manual: row j of the result is column\n    # j of the board.\n    [] => out\n    for j in [0:len(b[0]) - 1]:\n        [] => new_row\n        for i in [0:len(b) - 1]:\n            new_row + [b[i][j]] => new_row\n        out + [new_row] => out\n    return out\n\ndef moved(b, direction):\n    # Every move is a slide to the left on a turned board, turned back: right\n    # reverses each row, up transposes the board, down transposes it and\n    # reverses each row. Returns [the new board, the points gained].\n    b => t\n    if direction == \"right\":\n        reversed_rows(b) => t\n    elif direction == \"up\":\n        transposed(b) => t\n    elif direction == \"down\":\n        reversed_rows(transposed(b)) => t\n    [] => slid\n    0 => gained\n    for row in t:\n        slid_left(row) => res\n        slid + [res[0]] => slid\n        gained + res[1] => gained\n    slid => out\n    if direction == \"right\":\n        reversed_rows(slid) => out\n    elif direction == \"up\":\n        transposed(slid) => out\n    elif direction == \"down\":\n        transposed(reversed_rows(slid)) => out\n    return [out, gained]\n\ndef empty_cells(b):\n    [] => out\n    for r in [0:len(b) - 1]:\n        for c in [0:len(b) - 1]:\n            if b[r][c] == 0:\n                out + [[r, c]] => out\n    return out\n\ndef add_tile(b, rng):\n    # A new tile on an empty cell, every empty cell equally likely: a 2 nine\n    # times in ten, otherwise a 4. Returns [row, column, value], or [] when\n    # no cell is empty.\n    empty_cells(b) => cells\n    if len(cells) == 0:\n        return []\n    cells[rng.below(len(cells))] => cell\n    2 => value\n    if rng.below(10) == 0:\n        4 => value\n    value => b[cell[0]][cell[1]]\n    return [cell[0], cell[1], value]\n\ndef can_move(b):\n    # Some move changes the board while a cell is empty or two equal tiles\n    # touch, side by side or one above the other. (A board in play always\n    # holds a tile; on an empty one nothing would move.)\n    len(b) => n\n    for r in [0:n - 1]:\n        for c in [0:n - 1]:\n            if b[r][c] == 0:\n                return True\n            if c + 1 < n and b[r][c] == b[r][c + 1]:\n                return True\n            if r + 1 < n and b[r][c] == b[r + 1][c]:\n                return True\n    return False\n\ndef largest(b):\n    0 => top\n    for row in b:\n        for x in row:\n            if x > top:\n                x => top\n    return top\n\ndef drawn(b):\n    # Each cell five characters wide, a dot for an empty one.\n    [] => lines\n    for row in b:\n        \"\" => line\n        for x in row:\n            \".\" => s\n            if x != 0:\n                str(x) => s\n            while len(s) < 5:\n                \" \" + s => s\n            line + \" \" + s => line\n        lines + [line] => lines\n    return lines\n",
      "python": "def empty_board(size):\n    b = []\n    for r in range(1, size+1):\n        b = b + [[0] * size]\n    return b\n\ndef slid_left(row):\n    tiles = []\n    for x in row:\n        if x != 0:\n            tiles = tiles + [x]\n    out = []\n    gained = 0\n    i = 0\n    while i < len(tiles):\n        if i + 1 < len(tiles) and tiles[i] == tiles[i + 1]:\n            out = out + [tiles[i] * 2]\n            gained = gained + tiles[i] * 2\n            i = i + 2\n        else:\n            out = out + [tiles[i]]\n            i = i + 1\n    while len(out) < len(row):\n        out = out + [0]\n    return [out, gained]\n\ndef reversed_rows(b):\n    out = []\n    for row in b:\n        r = []\n        for x in row:\n            r = [x] + r\n        out = out + [r]\n    return out\n\ndef transposed(b):\n    out = []\n    for j in range(0, len(b[0])):\n        new_row = []\n        for i in range(0, len(b)):\n            new_row = new_row + [b[i][j]]\n        out = out + [new_row]\n    return out\n\ndef moved(b, direction):\n    t = b\n    if direction == \"right\":\n        t = reversed_rows(b)\n    elif direction == \"up\":\n        t = transposed(b)\n    elif direction == \"down\":\n        t = reversed_rows(transposed(b))\n    slid = []\n    gained = 0\n    for row in t:\n        res = slid_left(row)\n        slid = slid + [res[0]]\n        gained = gained + res[1]\n    out = slid\n    if direction == \"right\":\n        out = reversed_rows(slid)\n    elif direction == \"up\":\n        out = transposed(slid)\n    elif direction == \"down\":\n        out = transposed(reversed_rows(slid))\n    return [out, gained]\n\ndef empty_cells(b):\n    out = []\n    for r in range(0, len(b)):\n        for c in range(0, len(b)):\n            if b[r][c] == 0:\n                out = out + [[r, c]]\n    return out\n\ndef add_tile(b, rng):\n    cells = empty_cells(b)\n    if len(cells) == 0:\n        return []\n    cell = cells[rng.below(len(cells))]\n    value = 2\n    if rng.below(10) == 0:\n        value = 4\n    b[cell[0]][cell[1]] = value\n    return [cell[0], cell[1], value]\n\ndef can_move(b):\n    n = len(b)\n    for r in range(0, n):\n        for c in range(0, n):\n            if b[r][c] == 0:\n                return True\n            if c + 1 < n and b[r][c] == b[r][c + 1]:\n                return True\n            if r + 1 < n and b[r][c] == b[r + 1][c]:\n                return True\n    return False\n\ndef largest(b):\n    top = 0\n    for row in b:\n        for x in row:\n            if x > top:\n                top = x\n    return top\n\ndef drawn(b):\n    lines = []\n    for row in b:\n        line = \"\"\n        for x in row:\n            s = \".\"\n            if x != 0:\n                s = str(x)\n            while len(s) < 5:\n                s = \" \" + s\n            line = line + \" \" + s\n        lines = lines + [line]\n    return lines\n"
    },
    {
      "name": "rng.eml",
      "eml": "# P048 2048 - random numbers written in EML: the linear congruential\n# generator of P008 (number guessing), with the constants of the C\n# standard's example rand(). Python's random module is not used, so a seed\n# gives the same tiles on every machine, and the interpreter can check a\n# whole session byte for byte.\n\nclass Rng:\n    def __init__(self, seed):\n        seed % 2147483648 => self.state\n\n    def step(self):\n        (1103515245 * self.state + 12345) % 2147483648 => self.state\n        return self.state\n\n    def below(self, n):\n        # A number from 0 to n - 1, taken from the high bits of the state: the\n        # low bits of this generator repeat with short periods. Dividing by\n        # 65536 is exact in a float for a state below 2^31.\n        return int(self.step() / 65536) % n\n",
      "python": "class Rng:\n    def __init__(self, seed):\n        self.state = seed % 2147483648\n    def step(self):\n        self.state = (1103515245 * self.state + 12345) % 2147483648\n        return self.state\n    def below(self, n):\n        return int(self.step() / 65536) % n\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "x\n\nup\nw\nleft\nw\nn\n2\n7\nx\n3\n4\n12\n100000\n8\nabc\n261\ns\ns\ns\ns\ns\na\ns\ns\ns\ns\ns\na\ns\ns\ns\ns\ns\ns\na\nn\n\nn\n3\n\nn\n3\n16\n\nq\n",
      "screen": "== 2048 ==\nSlide the tiles: two equal tiles that meet join into one. Every move brings a new tile.\nA board of 4 x 4, goal 2048, seed 2026.\n     .     .     .     .\n     .     .     .     2\n     2     .     .     .\n     .     .     .     .\nScore 0, moves 0, largest tile 2.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> x\nType w, a, s or d to move, n for a new game or q to quit.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> \nType w, a, s or d to move, n for a new game or q to quit.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> up\n     2     .     .     2\n     .     .     2     .\n     .     .     .     .\n     .     .     .     .\nScore 0, moves 1, largest tile 2.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> w\n     2     2     2     2\n     .     .     .     .\n     .     .     .     .\n     .     .     .     .\nScore 0, moves 2, largest tile 2.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> left\n     4     4     .     .\n     .     2     .     .\n     .     .     .     .\n     .     .     .     .\nScore 8, moves 3, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> w\nNothing moves up.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> n\nsize (3 to 6)> 2\nType a number from 3 to 6.\nsize (3 to 6)> 7\nType a number from 3 to 6.\nsize (3 to 6)> x\nType a number from 3 to 6.\nsize (3 to 6)> 3\ngoal (8 to 65536)> 4\nType a number from 8 to 65536.\ngoal (8 to 65536)> 12\nThe goal is a tile, so a power of two: 8, 16, 32 and so on.\ngoal (8 to 65536)> 100000\nType a number from 8 to 65536.\ngoal (8 to 65536)> 8\nseed (0 to 999999999)> abc\nType a number from 0 to 999999999.\nseed (0 to 999999999)> 261\nA board of 3 x 3, goal 8, seed 261.\n     .     .     .\n     .     .     2\n     .     2     .\nScore 0, moves 0, largest tile 2.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     .     .     2\n     .     .     .\n     .     2     2\nScore 0, moves 1, largest tile 2.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     .     .     .\n     4     .     .\n     .     2     4\nScore 4, moves 2, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     .     .     2\n     .     .     .\n     4     2     4\nScore 4, moves 3, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     4     .     .\n     .     .     2\n     4     2     4\nScore 4, moves 4, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     .     .     .\n     .     4     2\n     8     2     4\nScore 12, moves 5, largest tile 8.\nYou made 8 in 5 moves - keep going if you like.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\n     2     .     .\n     4     2     .\n     8     2     4\nScore 12, moves 6, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     .\n     4     4     .\n     8     4     4\nScore 16, moves 7, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     2     .\n     4     .     .\n     8     8     4\nScore 24, moves 8, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     2     .\n     4     2     .\n     8     8     4\nScore 24, moves 9, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     2\n     4     4     .\n     8     8     4\nScore 28, moves 10, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     4\n     4     4     2\n     8     8     4\nScore 28, moves 11, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\n     2     4     .\n     8     2     2\n    16     4     .\nScore 52, moves 12, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     4     .\n     8     2     2\n    16     4     2\nScore 52, moves 13, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     4     2\n     8     2     .\n    16     4     4\nScore 56, moves 14, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     4     2\n     8     2     2\n    16     4     4\nScore 56, moves 15, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     4     2\n     8     2     4\n    16     4     4\nScore 60, moves 16, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     4     2\n     8     2     2\n    16     4     8\nScore 68, moves 17, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     4     2\n     8     2     4\n    16     4     8\nScore 72, moves 18, largest tile 16.\nNo move is left. Game over: score 72, largest tile 16, 18 moves.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\nNo move is left - start a new game.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> n\nsize (3 to 6)> \nCancelled.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> n\nsize (3 to 6)> 3\ngoal (8 to 65536)> \nCancelled.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> n\nsize (3 to 6)> 3\ngoal (8 to 65536)> 16\nseed (0 to 999999999)> \nCancelled.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> q\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "w\nw\na\ns\nd\ns\na\ns\nn\n3\n32\n318\ns\nw\ns\na\ns\ns\na\ns\ns\ns\ns\na\ns\ns\ns\ns\ns\na\nd\ns\na\ns\na\nd\ns\ns\nq\n",
      "screen": "== 2048 ==\nSlide the tiles: two equal tiles that meet join into one. Every move brings a new tile.\nA board of 4 x 4, goal 2048, seed 2026.\n     .     .     .     .\n     .     .     .     2\n     2     .     .     .\n     .     .     .     .\nScore 0, moves 0, largest tile 2.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> w\n     2     .     .     2\n     .     .     2     .\n     .     .     .     .\n     .     .     .     .\nScore 0, moves 1, largest tile 2.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> w\n     2     2     2     2\n     .     .     .     .\n     .     .     .     .\n     .     .     .     .\nScore 0, moves 2, largest tile 2.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\n     4     4     .     .\n     .     2     .     .\n     .     .     .     .\n     .     .     .     .\nScore 8, moves 3, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     .     .     .     .\n     .     2     .     .\n     .     4     .     .\n     4     2     .     .\nScore 8, moves 4, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> d\n     2     .     .     .\n     .     .     .     2\n     .     .     .     4\n     .     .     4     2\nScore 8, moves 5, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     .     .     .     2\n     .     .     .     2\n     .     .     .     4\n     2     .     4     2\nScore 8, moves 6, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\n     2     2     .     .\n     2     .     .     .\n     4     .     .     .\n     2     4     2     .\nScore 8, moves 7, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     .     .     2     .\n     4     .     .     .\n     4     2     .     .\n     2     4     2     .\nScore 12, moves 8, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> n\nsize (3 to 6)> 3\ngoal (8 to 65536)> 32\nseed (0 to 999999999)> 318\nA board of 3 x 3, goal 32, seed 318.\n     .     .     .\n     .     4     2\n     .     .     .\nScore 0, moves 0, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     .     .     .\n     .     .     .\n     2     4     2\nScore 0, moves 1, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> w\n     2     4     2\n     .     .     .\n     .     2     .\nScore 0, moves 2, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     .     2     .\n     .     4     .\n     2     2     2\nScore 0, moves 3, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\n     2     .     .\n     4     .     .\n     4     2     2\nScore 4, moves 4, largest tile 4.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     .\n     2     .     .\n     8     2     2\nScore 12, moves 5, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     .\n     4     .     .\n     8     2     2\nScore 16, moves 6, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\n     2     2     .\n     4     .     .\n     8     4     .\nScore 20, moves 7, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     2     .\n     4     2     .\n     8     4     .\nScore 20, moves 8, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     2\n     4     4     .\n     8     4     .\nScore 24, moves 9, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     2\n     4     .     .\n     8     8     2\nScore 32, moves 10, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     .\n     4     .     2\n     8     8     4\nScore 36, moves 11, largest tile 8.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\n     2     2     .\n     4     2     .\n    16     4     .\nScore 52, moves 12, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     .\n     4     4     .\n    16     4     2\nScore 56, moves 13, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     4\n     4     .     .\n    16     8     2\nScore 64, moves 14, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     2     .\n     4     .     4\n    16     8     2\nScore 64, moves 15, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     2     .\n     4     2     4\n    16     8     2\nScore 64, moves 16, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     .     2\n     4     4     4\n    16     8     2\nScore 68, moves 17, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\n     4     2     .\n     8     4     .\n    16     8     2\nScore 80, moves 18, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> d\n     2     4     2\n     .     8     4\n    16     8     2\nScore 80, moves 19, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     .     2     2\n     2     4     4\n    16    16     2\nScore 96, moves 20, largest tile 16.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\n     4     .     .\n     2     8     2\n    32     2     .\nScore 140, moves 21, largest tile 32.\nYou made 32 in 21 moves - keep going if you like.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     4     4     .\n     2     8     .\n    32     2     2\nScore 140, moves 22, largest tile 32.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> a\n     8     2     .\n     2     8     .\n    32     4     .\nScore 152, moves 23, largest tile 32.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> d\n     2     8     2\n     .     2     8\n     .    32     4\nScore 152, moves 24, largest tile 32.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     4     8     2\n     .     2     8\n     2    32     4\nScore 152, moves 25, largest tile 32.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> s\n     2     8     2\n     4     2     8\n     2    32     4\nScore 152, moves 26, largest tile 32.\nNo move is left. Game over: score 152, largest tile 32, 26 moves.\n\nw) up  a) left  s) down  d) right  n) new game  q) quit\nmove> q\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "matrix-transpose-manual",
      "caseId": "029-matrix-transpose-manual",
      "title": "Matrix transpose (manual)"
    }
  ],
  "updated": "2026-10-10"
}
