matty #20 AI
HTML
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<title>matty #20 - easy as 1-2-3</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="matty: play math games in your browser">
<meta name="keywords" content="Math, Math games, math games in browser, HTML, CSS, JavaScript">
<meta name="format-detection" content="telephone=no">
<style>
body {
font-family: Tahoma, sans-serif;
text-align: center;
background-color: white;
color: black;
margin: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
}
h1 {
text-transform: lowercase;
margin: 5px 0;
}
.container {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 5px;
width: 90%;
max-width: 450px;
margin: 10px auto;
}
.ball {
width: 100%;
padding-top: 100%;
position: relative;
background-color: black;
border-radius: 50%;
font-size: 2vw;
color: white;
cursor: pointer;
user-select: none;
transition: transform 0.5s ease;
}
.ball::after {
content: attr(data-number);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.ball.selected {
background-color: lightgray;
}
.ball.empty {
background-color: transparent;
}
.ball.empty::after {
content: '';
}
@keyframes fall {
...
JavaScript
function enumerateMoves(grid) {
let moves = [];
function addMove(r1, c1, r2, c2, r3, c3) {
moves.push([[r1, c1], [r2, c2], [r3, c3]]);
}
function find3(r1, c1, r2, c2) {
if (r2 > 0 && grid[r2 - 1][c2] === 3) addMove(r1, c1, r2, c2, r2 - 1, c2);
if (c2 > 0 && grid[r2][c2 - 1] === 3) addMove(r1, c1, r2, c2, r2, c2 - 1);
if (r2 < 6 && grid[r2 + 1][c2] === 3) addMove(r1, c1, r2, c2, r2 + 1, c2);
if (c2 < 6 && grid[r2][c2 + 1] === 3) addMove(r1, c1, r2, c2, r2, c2 + 1);
}
function find2(r1, c1) {
if (r1 > 0 && grid[r1 - 1][c1] === 2) find3(r1, c1, r1 - 1, c1);
if (c1 > 0 && grid[r1][c1 - 1] === 2) find3(r1, c1, r1, c1 - 1);
if (r1 < 6 && grid[r1 + 1][c1] === 2) find3(r1, c1, r1 + 1, c1);
if (c1 < 6 && grid[r1][c1 + 1] === 2) find3(r1, c1, r1, c1 + 1);
}
for (let r = 0; r < 7; ++r) {
for (let c = 0; c < 7; ++c) {
if (grid[r][c] === 1) find2(r, c);
}
}
return moves;
}
function selectRandomMove(moves) {
return moves[Math.floor(Math.random() * moves.length)];
}
function executeMove(grid, move) {
grid = structuredClone(grid);
for (const [r, c] of move) {
grid[r][c] = 0;
}
for (let c = 0; c < 7; ++c) {
var r2 = 6;
for (let r = 6; r >= 0; --r) {
if (grid[r][c] > 0) grid[r2--][c] = grid[r][c];
}
while (r2 >= 0) grid[r2--][c] = 0;
}
return grid;
}
function selectBestMove(grid, moves) {
function search(grid, depthLeft) {
if (depthLeft === 0) {
//return enumerateMoves(grid).length;
//return calculateFitness(grid);
return calculateFitness2(grid);
}
var bestScore = -Infinity;
for (let move of enumerateMoves(grid)) {
bestScore = Math.max(bestScore, search(executeMove(grid, move), depthLeft - 1));
}
return bestScore;
}
var bestMoves = [];
var bestScore = -Infinity;
for (let move of moves) {
var newGrid = executeMove(grid, move);
var score = search(newGrid, 3);
if (score > bestScore) {
...