Skip to content

Commit

Permalink
implement minimax alpha-beta
Browse files Browse the repository at this point in the history
  • Loading branch information
CortezSMz committed Apr 12, 2022
1 parent 53340e6 commit fc5f088
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 52 deletions.
8 changes: 5 additions & 3 deletions src/components/Controls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@
min="1"
max="8"
thumb-label="always"
ticks="always"
tick-size="4"
persistent-hint
:hint="difficultHint"
>
Expand Down Expand Up @@ -122,9 +124,9 @@ import { Watch } from "vue-property-decorator";
7: "tougher",
8: "tougher",
};
return `AI will test ${
this.$parent.manager.minimax.depth
} plays in the future. (${
return `AI ${
this.$parent.manager.state.finished ? "was testing" : "will test"
} ${this.$parent.manager.minimax.depth} plays in the future. (${
difficult[this.$parent.manager.minimax.depth]
})`;
},
Expand Down
8 changes: 5 additions & 3 deletions src/engine/GameManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,13 @@ export default class GameManager {
});

if (color === "RED") {
const best = this.minimax.getBestMove();
const move = this.minimax.getBestMove();

this.dropping = false;

setTimeout(() => {
this.drop(best.move.x);
}, 500);
this.drop(move[0] || (move as unknown as number));
}, 100);
}

setTimeout(() => {
Expand Down
85 changes: 39 additions & 46 deletions src/engine/Minimax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,47 @@ export class Minimax {

this.depth = 5;
}

public getBestMove() {
const { moves, bestScore } = this.getMoves();

const bestMoves = moves.filter((m) => m.score === bestScore);

return bestMoves[(bestMoves.length * Math.random()) | 0];
}
const [moves, bestScore] = this.getMoves();

private getMoves(depth: number = this.depth) {
const board = [...this.manager.board.grid];
let bestScore = -Infinity;
const moves: { score: number; move: GridSlot }[] = [];
const bestMoves = (moves as number[][]).filter(
(move) => move[1] === bestScore
);

const validMoves = this.manager.board.allValidLocations(board);
if (bestMoves.length === 1) return bestMoves[0];

for (const { row, col, x, z } of validMoves) {
board[row][col].disc = {
dropped: false,
color: "YELLOW",
id: -1,
x,
z,
};
const randomBestMove =
bestMoves[Math.floor(Math.random() * bestMoves.length)];

const score = this.minimax(board, depth, false);
return randomBestMove;
}

board[row][col].disc = null;
public getMoves(depth: number = this.depth) {
const board = [...this.manager.board.grid];

moves.push({ score, move: { row, col, x, z, disc: null } });
const moves = this.minimax(board, depth, -Infinity, Infinity, true);

if (score > bestScore) {
bestScore = score;
}
}

return { moves, bestScore };
return moves;
}

private minimax(
board: GridSlot[][],
depth: number,
alpha: number,
beta: number,
playing: boolean
): number {
): (number | number[][])[] {
const res = this.manager.check(board);
if (res.result != null || depth === 0) {
if (res.result === "RED") return -1;
else if (res.result === "YELLOW") return 1;
return 0;
if (res.result === "RED") return [[], -1];
else if (res.result === "YELLOW") return [[], 1];
return [[], 0];
}

if (playing) {
let bestScore = -Infinity;
const max: (number | number[][])[] = [[], alpha];
const validMoves = this.manager.board.allValidLocations(board);

for (const { row, col, x, z } of validMoves) {
board[row][col].disc = {
dropped: false,
Expand All @@ -73,16 +60,21 @@ export class Minimax {
x,
z,
};
const score = this.minimax(board, depth - 1, false);
const nextMove = this.minimax(board, depth - 1, alpha, beta, false);
board[row][col].disc = null;
if (score > bestScore) {
bestScore = score;
(max[0] as (number | number[])[]).push([x, nextMove[1] as number]);
if ((nextMove as number[])[1] > (max as number[])[1]) {
max[1] = nextMove[1];
alpha = nextMove[1] as number;
}
if ((alpha as number) >= (beta as number)) return max;
}
return bestScore;
} else if (!playing) {
let bestScore = Infinity;

return max;
} else {
const min: (number | number[][])[] = [[], beta];
const validMoves = this.manager.board.allValidLocations(board);

for (const { row, col, x, z } of validMoves) {
board[row][col].disc = {
dropped: false,
Expand All @@ -91,15 +83,16 @@ export class Minimax {
x,
z,
};
const score = this.minimax(board, depth - 1, true);
const nextMove = this.minimax(board, depth - 1, alpha, beta, true);
board[row][col].disc = null;
if (score < bestScore) {
bestScore = score;
(min[0] as (number | number[])[]).push([x, nextMove[1] as number]);
if ((nextMove as number[])[1] < (min as number[])[1]) {
min[1] = nextMove[1];
beta = nextMove[1] as number;
}
}
return bestScore;
}

return 0;
return min;
}
}
}

0 comments on commit fc5f088

Please sign in to comment.