https://slides.com/artfuldev/gp101-tic-tac-toe/live
@artfuldev
Software development of video games
Software development of video games
Software development of video games
Software development of video games
What qualifies as a game?
Software development of video games
Software development of video games
Software development of video games
Software development of video games
What all is involved?
Simulation
Simulation
Computer Graphics
Simulation
Computer Graphics
Artificial Intelligence
Simulation
Computer Graphics
Artificial Intelligence
Physics
Simulation
Computer Graphics
Artificial Intelligence
Physics
Audio Programming
Simulation
Computer Graphics
Artificial Intelligence
Physics
Audio Programming
Input
Simulation
Computer Graphics
Artificial Intelligence
Physics
Audio Programming
Input
Network Programming
Simulation
Computer Graphics
Artificial Intelligence
Physics
Audio Programming
Input
Network Programming
Database Programming
Simulation
Computer Graphics
Artificial Intelligence
Physics
Audio Programming
Input
Network Programming
Database Programming
Artificial Intelligence
Game Programming
Artificial Intelligence
Game Programming
Artificial Intelligence
Game Programming
Game Programming
Expert System
Game Programming
Expert System
Game Programming
Expert System
Game Programming
Artificial Intelligence
Expert System
Game Programming
Artificial Intelligence
Expert System
Game Programming
Artificial Intelligence
Expert System
Game Programming
Game Programming
A program that analyses and provides feedback on the best possible move in a particular state of a game
A program that analyses and provides feedback on the best possible move in a particular state of a game
Example: Chess engines
Example: Chess engines
We can build them easily.
Example: Chess engines
We can build them easily.
Let's start with TicTacToe
Let's start with TicTacToe
As an AI environment
As an AI environment
How do we think?
function getBestMove(grid, currentPlayer) {
// ...
// calculate best move
// ...
return bestMove;
}
Occam's Razor
Occam's Razor
Occam's Razor
Occam's Razor
Occam's Razor
Occam's Razor
Occam's Razor
What is the simplest solution?
What is the simplest solution?
What is the simplest solution?
What is the simplest solution?
"Time travel is the solution to all problems."
"Time travel is the solution to all problems."
-Unknown
"Time travel is the solution to all problems."
-Unknown
"Time travel is the solution to all problems."
-Unknown
"Time travel is the solution to all problems."
-Unknown
Get all possible moves.
Get all possible moves.
Play all possible moves until the end of the game.
Get all possible moves.
Play all possible moves until the end of the game.
Pick the best possible move.
Get all possible moves.
Play all possible moves until the end of the game.
Pick the best possible move.
Return the best possible move.
Get all possible moves.
Play all possible moves until the end of the game.
Pick the best possible move.
Return the best possible move.
Get all possible moves.
Play all possible moves until the end of the game.
Pick the best possible move.
Return the best possible move.
Get all possible moves.
Play all possible moves until the end of the game.
Pick the best possible move.
Return the best possible move.
Get all possible moves.
Play all possible moves until the end of the game.
See the results of every move.
Return the best possible move.
Get all possible moves.
Play all possible moves until the end of the game.
See the results of every move.
Pick the move which results in least losses.
Return the best possible move.
Get all possible moves.
Play all possible moves until the end of the game.
See the results of every move.
Pick the move which results in least losses.
Return the best possible move.
Get all possible moves.
Play all possible moves until the end of the game.
See the results of every move.
Pick the move which results in least losses.
Return the best possible move.
Time to say hi...
Time to say hi...
...to
A directive graph whose nodes are positions in a game and whose edges are moves
A directive graph whose nodes are positions in a game and whose edges are moves
By the way,
we just stepped into Game Theory.
A directive graph whose nodes are positions in a game and whose edges are moves
A directive graph whose nodes are positions in a game and whose edges are moves
A directive graph whose nodes are positions in a game and whose edges are moves
A directive graph whose nodes are positions in a game and whose edges are moves
A directive graph whose nodes are positions in a game and whose edges are moves
A directive graph whose nodes are positions in a game and whose edges are moves
Traversal
A directive graph whose nodes are positions in a game and whose edges are moves
Traversal
Evaluation
A directive graph whose nodes are positions in a game and whose edges are moves
Traversal
Evaluation
A directive graph whose nodes are positions in a game and whose edges are moves
Traversal
Evaluation
And next we have...
A decision rule that minimizes possible loss for a worst case scenario.
Depends on the maximin score.
Depends on the maximin score.
Depends on the maximin score.
The largest value that the player can be sure to get without knowing the actions of the other players
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
How to find?
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
How to find?
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
How to find?
How?
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
How to find?
How?
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
How to find?
How?
How?
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
How to find?
How?
How?
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
Is game over?
How?
How?
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
Is game over?
How close is X to winning?
How?
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
Is game over?
How close is X to winning?
What are my next possible moves?
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
Is game over?
How close is X to winning?
What are my next possible moves?
function minimax(node, depth, maximizingPlayer) {
if (depth === 0 || isTerminalNode(node))
return evaluate(node);
if (maximizingPlayer)
return getChildren(node)
.reduce((best, child) =>
Math.max(best, minimax(child, depth - 1, false)),
-Infinity);
return getChildren(node)
.reduce((best, child) =>
Math.min(best, minimax(child, depth - 1, true)),
Infinity);
}
Optimizations
Optimizations
should we traverse the entire tree?
Optimizations
should we traverse the entire tree?
alpha-beta pruning
Optimizations
should we traverse the entire tree?
alpha-beta pruning
if(β ≤ α) break;
Optimizations
should we traverse the entire tree?
alpha-beta pruning
if(β ≤ α) break;
should we calculate min and max?
Optimizations
should we traverse the entire tree?
alpha-beta pruning
if(β ≤ α) break;
should we calculate min and max?
negamax
Optimizations
should we traverse the entire tree?
alpha-beta pruning
if(β ≤ α) break;
should we calculate min and max?
negamax
max(a,b) = -min(-a,-b);
Optimizations
should we traverse the entire tree?
alpha-beta pruning
if(β ≤ α) break;
should we calculate min and max?
negamax
max(a,b) = -min(-a,-b);
concurrency
Optimizations
should we traverse the entire tree?
alpha-beta pruning
if(β ≤ α) break;
should we calculate min and max?
negamax
max(a,b) = -min(-a,-b);
concurrency
simpler evaluation
Optimizations
should we traverse the entire tree?
alpha-beta pruning
if(β ≤ α) break;
should we calculate min and max?
negamax
max(a,b) = -min(-a,-b);
concurrency
simpler evaluation
Optimizations
should we traverse the entire tree?
alpha-beta pruning
if(β ≤ α) break;
should we calculate min and max?
negamax
max(a,b) = -min(-a,-b);
concurrency
simpler evaluation
evaluation
evaluation is the process of assigning a value to a node
evaluation is the process of assigning a value to a node
it is the heart of any engine, optimal moves can only be found with a sound evaluation function
for tic-tac-toe
function evaluateCells(cells) {
const length = cells.length;
if(length === 0) return 0;
const initial = { undefined: 0, true: 0, false: 0 };
const counts = cells.reduce((counts, cell) => increment(counts, cell), initial);
if (counts.undefined === length) return 0;
if (counts.true === length) return Infinity;
if (counts.false === length) return -Infinity;
if (counts.false === 0) return Math.pow(2, counts.true);
if (counts.true === 0) return -Math.pow(2, counts.false);
return 0;
}
function evaluate(grid) {
return evaluateRows(grid) + evaluateColumns(grid) + evaluateDiagonals(grid);
}
function getMoves(grid) {
return grid
.map((value, index) => value == undefined ? index : undefined)
.filter(value => value != undefined);
}
function getMoves(grid) {
return grid
.map((value, index) => value == undefined ? index : undefined)
.filter(value => value != undefined);
}
function hasGameEnded(grid) {
return hasXWon(grid) || hasOWon(grid) || isFull(grid);
}
Chess
Chess
2048
Chess
2048
Think of your own game to beat!
Chess
2048
Think of your own game to beat!
Chess
2048
Think of your own game to beat!
My favourite!
Chess
2048
Think of your own game to beat!
My favourite!