{
  "id": "P050",
  "slug": "connect-four",
  "key": "P050-connect-four",
  "title": "Connect Four",
  "summary": "Drop discs into a grid of 7 columns and 6 rows and be the first with four in a row - across, down or diagonally. Play a friend, or the computer, going first or second: it wins when it can, blocks when it must, and looks one move ahead so as not to set up your win. A running score is kept.",
  "entry": "main.eml",
  "ui": "terminal",
  "readme": "# P050 - Connect Four\n\nTwo sides drop discs into a grid of 7 columns and 6 rows; a disc falls to\nthe lowest empty cell of its column. The first side with four discs in a\nrow - across, down or along a diagonal - wins, and a full grid is a draw.\nPlay a friend, or the computer, going first or second; a running score is\nkept.\n\n- `main.eml` - the menu, one game from the first disc to the last, the\n  messages and the score\n- `grid.eml` - the grid: where a disc lands, dropping and taking back a\n  disc, the line of four through a disc, and the drawing\n- `robot.eml` - the computer's choice of column\n\nHow each part works:\n\n- Only a line through the disc just dropped can be new, so after each\n  disc the game looks along the four directions through it - across, down\n  and both diagonals - and counts the same discs on both sides. When the\n  game is won, the discs of the winning line are drawn in lower case.\n- The computer picks, in this order: a column that wins at once; otherwise\n  a column where you would win next, to block it; otherwise it looks one\n  move ahead and keeps to columns after which you cannot win at once - not\n  right under the cell you need. Among those it takes the column nearest\n  the middle, since a disc there belongs to the most lines of four. This\n  is the tic-tac-toe player of P009 and the corpus case `mvp-tic-tac-toe`\n  with that look ahead added. There is no randomness, so the same moves\n  always get the same answers.\n- To try a column the computer drops a disc, looks, and takes it back out\n  again, so the grid it was given is left exactly as it was.\n\nWhat is checked: menu choices 1 to 5; a column from 1 to 7 that is not\nfull. An empty answer leaves the game, which then counts for no one.\n\nSessions: `sessions/basic.in` plays one game against the computer and one\nbetween two players, then shows the score. In the first game the computer\nblocks three in a row along the bottom, then passes over column 3: a disc\nthere would let you finish the diagonal from column 1 to column 4 on top\nof it, so it plays column 5. It blocks three in a column, and when you\nfill in column 3 yourself, it drops on top of that disc and wins along a\ndiagonal with disc 16. In the two-player game, X wins with disc 11 on the\ndiagonal from the bottom of column 1 to the fourth row of column 4.\n\n`sessions/bad-input.in` gives:\n- menu choices 0 and x;\n- columns 0, 8, x and 44;\n- column 1 filled to the top and tried once more;\n- a game left with an empty answer, both between two players and against\n  the computer, which plays first in column 4;\n- the score, where neither left game counts.\n\nBuilt on the verified corpus case `mvp-tic-tac-toe` (a real two-player\nboard game: moves, a taken square refused, and the lines that win).\n",
  "modules": [
    {
      "name": "main.eml",
      "eml": "# P050 Connect Four: drop discs into a grid of 7 columns and 6 rows and be\n# the first with four in a row - across, down or diagonally. Play a friend,\n# or the computer, which wins when it can, blocks when it must and does\n# not set up your win.\nimport grid\nimport robot\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 show(g, marked):\n    for line in grid.drawn(g, marked):\n        line ^0\n\ndef ask_column(g, who):\n    # A column from 0 to 6 with room in it, or -1 when the answer is empty.\n    while True:\n        trim(input(who + \", column (1 to 7)> \")) => answer\n        if answer == \"\":\n            return -1\n        if len(answer) == 1 and answer >= \"1\" and answer <= \"7\":\n            int(answer) - 1 => c\n            if grid.landing_row(g, c) >= 0:\n                return c\n            (\"Column \" + answer + \" is full.\") ^0\n        else:\n            \"Type a column from 1 to 7.\" ^0\n\ndef play(computer):\n    # One game; computer is \"\", \"O\" or \"X\" - the side the computer plays.\n    # Returns \"X\", \"O\", \"draw\", or \"\" when the game was left.\n    grid.empty_grid() => g\n    \"X\" => who\n    0 => discs\n    if computer == \"O\":\n        \"You play X and go first.\" ^0\n    elif computer == \"X\":\n        \"The computer plays X and goes first; you play O.\" ^0\n    while True:\n        \"O\" => other\n        if who == \"O\":\n            \"X\" => other\n        if who == computer:\n            robot.choose(g, who, other) => c\n            (\"The computer drops in column \" + str(c + 1) + \".\") ^0\n        else:\n            show(g, [])\n            ask_column(g, who) => c\n            if c < 0:\n                \"Game left.\" ^0\n                return \"\"\n        grid.drop(g, c, who) => r\n        discs + 1 => discs\n        grid.run_through(g, r, c) => line\n        if len(line) > 0:\n            show(g, line)\n            if computer == \"\":\n                (who + \" wins with disc \" + str(discs) + \" - the winning line is in lower case.\") ^0\n            elif who == computer:\n                (\"The computer wins with disc \" + str(discs) + \" - the winning line is in lower case.\") ^0\n            else:\n                (\"You win with disc \" + str(discs) + \" - the winning line is in lower case.\") ^0\n            return who\n        if grid.full(g):\n            show(g, [])\n            \"The grid is full: a draw.\" ^0\n            return \"draw\"\n        other => who\n\n\"== Connect Four ==\" ^0\n\"Drop discs into the columns; four in a row wins - across, down or diagonally.\" ^0\n[0, 0, 0] => score\nTrue => running\nwhile running:\n    \"\" ^0\n    \"1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\" ^0\n    trim(input(\"choice> \")) => choice\n    \"\" => result\n    if choice == \"1\":\n        play(\"\") => result\n    elif choice == \"2\":\n        play(\"O\") => result\n    elif choice == \"3\":\n        play(\"X\") => result\n    elif choice == \"4\":\n        (\"X wins: \" + str(score[0]) + \", O wins: \" + str(score[1]) + \", draws: \" + str(score[2]) + \".\") ^0\n    elif choice == \"5\":\n        False => running\n    else:\n        \"Pick a number from 1 to 5.\" ^0\n    if result == \"X\":\n        score[0] + 1 => score[0]\n    elif result == \"O\":\n        score[1] + 1 => score[1]\n    elif result == \"draw\":\n        score[2] + 1 => score[2]\n\"Bye.\" ^0\n",
      "python": "import grid\nimport robot\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 show(g, marked):\n    for line in grid.drawn(g, marked):\n        print(line)\n\ndef ask_column(g, who):\n    while True:\n        answer = trim(input(who + \", column (1 to 7)> \"))\n        if answer == \"\":\n            return -1\n        if len(answer) == 1 and answer >= \"1\" and answer <= \"7\":\n            c = int(answer) - 1\n            if grid.landing_row(g, c) >= 0:\n                return c\n            print(\"Column \" + answer + \" is full.\")\n        else:\n            print(\"Type a column from 1 to 7.\")\n\ndef play(computer):\n    g = grid.empty_grid()\n    who = \"X\"\n    discs = 0\n    if computer == \"O\":\n        print(\"You play X and go first.\")\n    elif computer == \"X\":\n        print(\"The computer plays X and goes first; you play O.\")\n    while True:\n        other = \"O\"\n        if who == \"O\":\n            other = \"X\"\n        if who == computer:\n            c = robot.choose(g, who, other)\n            print(\"The computer drops in column \" + str(c + 1) + \".\")\n        else:\n            show(g, [])\n            c = ask_column(g, who)\n            if c < 0:\n                print(\"Game left.\")\n                return \"\"\n        r = grid.drop(g, c, who)\n        discs = discs + 1\n        line = grid.run_through(g, r, c)\n        if len(line) > 0:\n            show(g, line)\n            if computer == \"\":\n                print(who + \" wins with disc \" + str(discs) + \" - the winning line is in lower case.\")\n            elif who == computer:\n                print(\"The computer wins with disc \" + str(discs) + \" - the winning line is in lower case.\")\n            else:\n                print(\"You win with disc \" + str(discs) + \" - the winning line is in lower case.\")\n            return who\n        if grid.full(g):\n            show(g, [])\n            print(\"The grid is full: a draw.\")\n            return \"draw\"\n        who = other\n\nprint(\"== Connect Four ==\")\nprint(\"Drop discs into the columns; four in a row wins - across, down or diagonally.\")\nscore = [0, 0, 0]\nrunning = True\nwhile running:\n    print(\"\")\n    print(\"1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\")\n    choice = trim(input(\"choice> \"))\n    result = \"\"\n    if choice == \"1\":\n        result = play(\"\")\n    elif choice == \"2\":\n        result = play(\"O\")\n    elif choice == \"3\":\n        result = play(\"X\")\n    elif choice == \"4\":\n        print(\"X wins: \" + str(score[0]) + \", O wins: \" + str(score[1]) + \", draws: \" + str(score[2]) + \".\")\n    elif choice == \"5\":\n        running = False\n    else:\n        print(\"Pick a number from 1 to 5.\")\n    if result == \"X\":\n        score[0] = score[0] + 1\n    elif result == \"O\":\n        score[1] = score[1] + 1\n    elif result == \"draw\":\n        score[2] = score[2] + 1\nprint(\"Bye.\")\n"
    },
    {
      "name": "grid.eml",
      "eml": "# P050 Connect Four - the grid: 6 rows of 7 cells, row 0 at the top, each\n# cell \".\", \"X\" or \"O\". A disc dropped into a column falls to the lowest\n# empty cell.\n\ndef empty_grid():\n    [] => g\n    for r in [1:6]:\n        g + [[\".\"] * 7] => g\n    return g\n\ndef landing_row(g, c):\n    # The row a disc dropped into column c would land in, or -1 when the\n    # column is full.\n    5 => r\n    while r >= 0 and g[r][c] != \".\":\n        r - 1 => r\n    return r\n\ndef drop(g, c, who):\n    landing_row(g, c) => r\n    if r >= 0:\n        who => g[r][c]\n    return r\n\ndef lift(g, c):\n    # Takes the top disc out of column c again - the computer tries a move\n    # and takes it back.\n    0 => r\n    while r < 6 and g[r][c] == \".\":\n        r + 1 => r\n    if r < 6:\n        \".\" => g[r][c]\n\ndef run_through(g, r, c):\n    # The cells of the longest line of four or more through (r, c) holding\n    # the same disc - across, down, or along either diagonal - or [] when\n    # there is none. Only lines through the last disc can be new, so this\n    # is all a move needs to check.\n    g[r][c] => who\n    for d in [[0, 1], [1, 0], [1, 1], [1, -1]]:\n        [[r, c]] => cells\n        for sign in [1, -1]:\n            r + sign * d[0] => y\n            c + sign * d[1] => x\n            while y >= 0 and y < 6 and x >= 0 and x < 7 and g[y][x] == who:\n                cells + [[y, x]] => cells\n                y + sign * d[0] => y\n                x + sign * d[1] => x\n        if len(cells) >= 4:\n            return cells\n    return []\n\ndef full(g):\n    for x in g[0]:\n        if x == \".\":\n            return False\n    return True\n\ndef drawn(g, marked):\n    # The grid with the column numbers on top; the discs of a winning line\n    # (the cells in marked) are drawn in lower case.\n    [\"  1 2 3 4 5 6 7\"] => lines\n    for r in [0:5]:\n        \" \" => line\n        for c in [0:6]:\n            g[r][c] => ch\n            for cell in marked:\n                if cell[0] == r and cell[1] == c:\n                    if ch == \"X\":\n                        \"x\" => ch\n                    else:\n                        \"o\" => ch\n            line + \" \" + ch => line\n        lines + [line] => lines\n    return lines\n",
      "python": "def empty_grid():\n    g = []\n    for r in range(1, 7):\n        g = g + [[\".\"] * 7]\n    return g\n\ndef landing_row(g, c):\n    r = 5\n    while r >= 0 and g[r][c] != \".\":\n        r = r - 1\n    return r\n\ndef drop(g, c, who):\n    r = landing_row(g, c)\n    if r >= 0:\n        g[r][c] = who\n    return r\n\ndef lift(g, c):\n    r = 0\n    while r < 6 and g[r][c] == \".\":\n        r = r + 1\n    if r < 6:\n        g[r][c] = \".\"\n\ndef run_through(g, r, c):\n    who = g[r][c]\n    for d in [[0, 1], [1, 0], [1, 1], [1, -1]]:\n        cells = [[r, c]]\n        for sign in [1, -1]:\n            y = r + sign * d[0]\n            x = c + sign * d[1]\n            while y >= 0 and y < 6 and x >= 0 and x < 7 and g[y][x] == who:\n                cells = cells + [[y, x]]\n                y = y + sign * d[0]\n                x = x + sign * d[1]\n        if len(cells) >= 4:\n            return cells\n    return []\n\ndef full(g):\n    for x in g[0]:\n        if x == \".\":\n            return False\n    return True\n\ndef drawn(g, marked):\n    lines = [\"  1 2 3 4 5 6 7\"]\n    for r in range(0, 6):\n        line = \" \"\n        for c in range(0, 7):\n            ch = g[r][c]\n            for cell in marked:\n                if cell[0] == r and cell[1] == c:\n                    if ch == \"X\":\n                        ch = \"x\"\n                    else:\n                        ch = \"o\"\n            line = line + \" \" + ch\n        lines = lines + [line]\n    return lines\n"
    },
    {
      "name": "robot.eml",
      "eml": "# P050 Connect Four - the computer's move, in order of preference:\n#  1. win now, if a column does it;\n#  2. otherwise block a column where the other player would win next;\n#  3. otherwise look one move ahead: keep to columns after which the other\n#     player cannot win at once (not under their winning cell);\n#  4. among what is left, the column nearest the middle - a disc there\n#     belongs to the most lines of four.\n# P009's tic-tac-toe player wins and blocks the same way; the look ahead\n# is new here. No randomness: the same moves always get the same answer.\nimport grid\n\ndef order():\n    return [3, 2, 4, 1, 5, 0, 6]\n\ndef winning_column(g, who):\n    # The first column, middle first, where a disc of who makes four, or -1.\n    for c in order():\n        grid.drop(g, c, who) => r\n        if r >= 0:\n            len(grid.run_through(g, r, c)) > 0 => wins\n            grid.lift(g, c)\n            if wins:\n                return c\n    return -1\n\ndef safe(g, c, me, other):\n    # After my disc in column c, can the other player win with their next\n    # disc? Safe when they cannot.\n    grid.drop(g, c, me)\n    winning_column(g, other) => reply\n    grid.lift(g, c)\n    return reply == -1\n\ndef choose(g, me, other):\n    winning_column(g, me) => c\n    if c >= 0:\n        return c\n    winning_column(g, other) => c\n    if c >= 0:\n        return c\n    -1 => fallback\n    for c in order():\n        if grid.landing_row(g, c) >= 0:\n            if fallback == -1:\n                c => fallback\n            if safe(g, c, me, other):\n                return c\n    # Every column lets the other player win next: take the middle-most.\n    return fallback\n",
      "python": "import grid\n\ndef order():\n    return [3, 2, 4, 1, 5, 0, 6]\n\ndef winning_column(g, who):\n    for c in order():\n        r = grid.drop(g, c, who)\n        if r >= 0:\n            wins = len(grid.run_through(g, r, c)) > 0\n            grid.lift(g, c)\n            if wins:\n                return c\n    return -1\n\ndef safe(g, c, me, other):\n    grid.drop(g, c, me)\n    reply = winning_column(g, other)\n    grid.lift(g, c)\n    return reply == -1\n\ndef choose(g, me, other):\n    c = winning_column(g, me)\n    if c >= 0:\n        return c\n    c = winning_column(g, other)\n    if c >= 0:\n        return c\n    fallback = -1\n    for c in order():\n        if grid.landing_row(g, c) >= 0:\n            if fallback == -1:\n                fallback = c\n            if safe(g, c, me, other):\n                return c\n    return fallback\n"
    }
  ],
  "sessions": [
    {
      "name": "bad-input",
      "input": "0\nx\n1\n0\n8\nx\n44\n1\n1\n1\n1\n1\n1\n1\n\n3\n\n4\n5\n",
      "screen": "== Connect Four ==\nDrop discs into the columns; four in a row wins - across, down or diagonally.\n\n1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\nchoice> 0\nPick a number from 1 to 5.\n\n1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\nchoice> x\nPick a number from 1 to 5.\n\n1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\nchoice> 1\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\nX, column (1 to 7)> 0\nType a column from 1 to 7.\nX, column (1 to 7)> 8\nType a column from 1 to 7.\nX, column (1 to 7)> x\nType a column from 1 to 7.\nX, column (1 to 7)> 44\nType a column from 1 to 7.\nX, column (1 to 7)> 1\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  X . . . . . .\nO, column (1 to 7)> 1\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  O . . . . . .\n  X . . . . . .\nX, column (1 to 7)> 1\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  X . . . . . .\n  O . . . . . .\n  X . . . . . .\nO, column (1 to 7)> 1\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  O . . . . . .\n  X . . . . . .\n  O . . . . . .\n  X . . . . . .\nX, column (1 to 7)> 1\n  1 2 3 4 5 6 7\n  . . . . . . .\n  X . . . . . .\n  O . . . . . .\n  X . . . . . .\n  O . . . . . .\n  X . . . . . .\nO, column (1 to 7)> 1\n  1 2 3 4 5 6 7\n  O . . . . . .\n  X . . . . . .\n  O . . . . . .\n  X . . . . . .\n  O . . . . . .\n  X . . . . . .\nX, column (1 to 7)> 1\nColumn 1 is full.\nX, column (1 to 7)> \nGame left.\n\n1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\nchoice> 3\nThe computer plays X and goes first; you play O.\nThe computer drops in column 4.\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . X . . .\nO, column (1 to 7)> \nGame left.\n\n1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\nchoice> 4\nX wins: 0, O wins: 0, draws: 0.\n\n1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    },
    {
      "name": "basic",
      "input": "2\n4\n2\n4\n2\n1\n6\n2\n3\n1\n1\n2\n2\n3\n3\n4\n3\n4\n7\n4\n4\n4\n5\n",
      "screen": "== Connect Four ==\nDrop discs into the columns; four in a row wins - across, down or diagonally.\n\n1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\nchoice> 2\nYou play X and go first.\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\nX, column (1 to 7)> 4\nThe computer drops in column 4.\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . O . . .\n  . . . X . . .\nX, column (1 to 7)> 2\nThe computer drops in column 4.\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . O . . .\n  . . . O . . .\n  . X . X . . .\nX, column (1 to 7)> 4\nThe computer drops in column 4.\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . O . . .\n  . . . X . . .\n  . . . O . . .\n  . . . O . . .\n  . X . X . . .\nX, column (1 to 7)> 2\nThe computer drops in column 4.\n  1 2 3 4 5 6 7\n  . . . O . . .\n  . . . O . . .\n  . . . X . . .\n  . . . O . . .\n  . X . O . . .\n  . X . X . . .\nX, column (1 to 7)> 1\nThe computer drops in column 3.\n  1 2 3 4 5 6 7\n  . . . O . . .\n  . . . O . . .\n  . . . X . . .\n  . . . O . . .\n  . X . O . . .\n  X X O X . . .\nX, column (1 to 7)> 6\nThe computer drops in column 5.\n  1 2 3 4 5 6 7\n  . . . O . . .\n  . . . O . . .\n  . . . X . . .\n  . . . O . . .\n  . X . O . . .\n  X X O X O X .\nX, column (1 to 7)> 2\nThe computer drops in column 2.\n  1 2 3 4 5 6 7\n  . . . O . . .\n  . . . O . . .\n  . O . X . . .\n  . X . O . . .\n  . X . O . . .\n  X X O X O X .\nX, column (1 to 7)> 3\nThe computer drops in column 3.\n  1 2 3 4 5 6 7\n  . . . O . . .\n  . . . O . . .\n  . o . X . . .\n  . X o O . . .\n  . X X o . . .\n  X X O X o X .\nThe computer wins with disc 16 - the winning line is in lower case.\n\n1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\nchoice> 1\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\nX, column (1 to 7)> 1\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  X . . . . . .\nO, column (1 to 7)> 2\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  X O . . . . .\nX, column (1 to 7)> 2\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . X . . . . .\n  X O . . . . .\nO, column (1 to 7)> 3\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . X . . . . .\n  X O O . . . .\nX, column (1 to 7)> 3\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . X X . . . .\n  X O O . . . .\nO, column (1 to 7)> 4\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . X X . . . .\n  X O O O . . .\nX, column (1 to 7)> 3\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . X . . . .\n  . X X . . . .\n  X O O O . . .\nO, column (1 to 7)> 4\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . X . . . .\n  . X X O . . .\n  X O O O . . .\nX, column (1 to 7)> 7\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . X . . . .\n  . X X O . . .\n  X O O O . . X\nO, column (1 to 7)> 4\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . . . . .\n  . . X O . . .\n  . X X O . . .\n  X O O O . . X\nX, column (1 to 7)> 4\n  1 2 3 4 5 6 7\n  . . . . . . .\n  . . . . . . .\n  . . . x . . .\n  . . x O . . .\n  . x X O . . .\n  x O O O . . X\nX wins with disc 11 - the winning line is in lower case.\n\n1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\nchoice> 4\nX wins: 1, O wins: 1, draws: 0.\n\n1) two players  2) you first against the computer  3) the computer first  4) score  5) quit\nchoice> 5\nBye.\n",
      "interpreter": "equal"
    }
  ],
  "builtOn": [
    {
      "slug": "mvp-tic-tac-toe",
      "caseId": "007-mvp-tic-tac-toe",
      "title": "MVP proof: a real, recognizable program ported to EML"
    }
  ],
  "updated": "2026-10-10"
}
