patternsqlMinor
Tic-tac-toe in SQL with optimal AI
Viewed 0 times
optimalwithsqltoetictac
Problem
The simplest introduction to this code is to play it! Here's an SQL Fiddle. However, to enjoy it fully, you'll need a more interactive environment, like the
Capabilities
-
Manually make a move for player
-
See the AI analysis for player
```
psql=> SELECT * FROM strategy WHERE sym = 'O';
sym | row | col | offense_reason | offense_score | defense_reason | defense_score | corner_center_response | corner_fork_defense | opposite_corner_offense | corner_offense | priority
-----+-----+-----+----------------+---------------+----------------+---------------+------------------------+---------------------+-------------------------+----------------+----------
O | 3 | 1 | | 0 | {"row 3"} | 1 | f | f | | t | 1
O | 3 | 3 | | 0 | {"row 3"} | 1 | f | f | | t | 1
O | 1 | 2 | | 0 | {"col 2"} | 1 | f | f | f | f | 3
O | 2 | 2 | | 0 | {"col 2"} | 1 | f | f | f | f | 3
O | 1 | 3 | | 0 | | 0 | f | f | | t | 5
O | 1 | 1 | | 0 |
psql command prompt. If you don't have PostgreSQL installed already, this may be the killer app that makes you want to install it.Capabilities
-
Manually make a move for player
X, then view the board:psql=> INSERT INTO tictactoe VALUES ('X', 3, 2);
INSERT 0 1
psql=> SELECT * FROM board;
row | 1 | 2 | 3
-----+---+---+---
1 | | |
2 | | |
3 | | X |
(3 rows)-
See the AI analysis for player
O:```
psql=> SELECT * FROM strategy WHERE sym = 'O';
sym | row | col | offense_reason | offense_score | defense_reason | defense_score | corner_center_response | corner_fork_defense | opposite_corner_offense | corner_offense | priority
-----+-----+-----+----------------+---------------+----------------+---------------+------------------------+---------------------+-------------------------+----------------+----------
O | 3 | 1 | | 0 | {"row 3"} | 1 | f | f | | t | 1
O | 3 | 3 | | 0 | {"row 3"} | 1 | f | f | | t | 1
O | 1 | 2 | | 0 | {"col 2"} | 1 | f | f | f | f | 3
O | 2 | 2 | | 0 | {"col 2"} | 1 | f | f | f | f | 3
O | 1 | 3 | | 0 | | 0 | f | f | | t | 5
O | 1 | 1 | | 0 |
Solution
In general, I have to say: "fascinating". I'm not the best SQL coder out there, but I'm pretty good at games, so I'm going to dare respond to at least one of your questions.
You asked about scaling some of the heuristics. One thing I did not see in your code is a move tree. With 3x3, you can calculate all possible positions and find out which moves would not lose and give your opponent a chance to lose. That sort of construct should scale to larger boards easier (although it may be slower to calculate, it would be trivially fast to play), and gets rid of the heuristics that are artifacts of the 3x3 game.
With 3x3 (and maybe 4x4), you may be able to think about what chess calls an endgame database as well. You may have to put in the concept of rotation and mirrored boards to get the 4x4 down to a reasonable size (I think I came up with 8 million rows). by the time you get to 5x5, you are playing a variation of gomoku, and the first player to move basically wins. You may be interested in Connect6 for something a bit more fair.
Another thought that may be interesting is the concept of "optimal". In drawish games like this, it may not be optimal to play the same sequence that you have played before against the same opponent if the opponent has already drawn the game. For example, there is still a 6x6 Othello/Reversi championship, even though the game has been "solved" by computers. However, since most top players know the "optimal" lines, the key to winning is sometimes making an "inferior" (but perhaps still winning) move, to get the other player into a line that you know more about then your opponent. Top chess players do something similar.
Therefore, the suggestion is to either put a small random factor among the moves that still give you a chance to win without risking losing, or, perhaps better, remember what lines were played previously and go down a different path. You do want to stay within "potentially winning" lines that have no chance of losing, though.
You asked about scaling some of the heuristics. One thing I did not see in your code is a move tree. With 3x3, you can calculate all possible positions and find out which moves would not lose and give your opponent a chance to lose. That sort of construct should scale to larger boards easier (although it may be slower to calculate, it would be trivially fast to play), and gets rid of the heuristics that are artifacts of the 3x3 game.
With 3x3 (and maybe 4x4), you may be able to think about what chess calls an endgame database as well. You may have to put in the concept of rotation and mirrored boards to get the 4x4 down to a reasonable size (I think I came up with 8 million rows). by the time you get to 5x5, you are playing a variation of gomoku, and the first player to move basically wins. You may be interested in Connect6 for something a bit more fair.
Another thought that may be interesting is the concept of "optimal". In drawish games like this, it may not be optimal to play the same sequence that you have played before against the same opponent if the opponent has already drawn the game. For example, there is still a 6x6 Othello/Reversi championship, even though the game has been "solved" by computers. However, since most top players know the "optimal" lines, the key to winning is sometimes making an "inferior" (but perhaps still winning) move, to get the other player into a line that you know more about then your opponent. Top chess players do something similar.
Therefore, the suggestion is to either put a small random factor among the moves that still give you a chance to win without risking losing, or, perhaps better, remember what lines were played previously and go down a different path. You do want to stay within "potentially winning" lines that have no chance of losing, though.
Context
StackExchange Code Review Q#55014, answer score: 3
Revisions (0)
No revisions yet.