xxxxxxxxxx
363
const cols = 7;
const rows = 6;
const iheight = 70;
const fw = 70;
const buffer = 100;
const RED = 1;
const YELLOW = -1;
const TIE = 0;
const VOID = 3;
let recDepth = 2;
let grid;
let colState;
let player;
let running;
let round = 0;
let easy;
let medium;
let hard;
function setup() {
if (round == 0) {
createCanvas(cols * fw + buffer, rows * fw + buffer + iheight);
easy = createButton('Einfach').mousePressed(() => {
recDepth = 2;
easy.hide();
medium.show();
hard.show()
});
medium = createButton('Mittel').mousePressed(() => {
recDepth = 5;
easy.show();
medium.hide();
hard.show()
});
hard = createButton('Schwer').mousePressed(() => {
recDepth = 7;
easy.show();
medium.show();
hard.hide()
});
easy.hide();
}
grid = createGrid(cols, rows);
colState = createCol(cols);
player = round % 2 == 0 ? RED : YELLOW;
running = true;
textAlign(CENTER, CENTER);
round++;
}
function draw() {
if (running) {
drawGrid(grid);
info((player == RED ? "Rot" : "Gelb") + " ist dran");
let winner = checkWinner(grid, true);
if (winner != VOID) {
let msg = "Unentschieden";
if (winner == RED) {
msg = "Rot gewinnt";
}
if (winner == YELLOW) {
msg = "Gelb gewinnt";
}
info(msg);
running = false;
}
if (player == YELLOW) {
let next = findBestTurn(grid, colState, player, recDepth);
if (makeTurn(player, grid, colState, next.col)) {
player = nextPlayer(player);
}
}
}
}
function mousePressed() {
if (running && player == RED) {
if (mouseY < height-iheight) {
let col = int(map(mouseX, 0, width, 0, cols));
if (makeTurn(player, grid, colState, col)) {
player = nextPlayer(player);
} else {
return;
}
}
} else if (!running) {
setup();
}
}
function checkWinner(grid, draw) {
let hdist = width / cols;
let vdist = (height - iheight) / rows;
//verticals
for (let col = 0; col < grid.length; col++) {
for (let row = 0; row <= grid[0].length - 4; row++) {
if (areEqual(grid[col][row], grid[col][row + 1], grid[col][row + 2], grid[col][row + 3]) && grid[col][row] != VOID) {
if (draw) {
stroke(0);
strokeWeight(8);
line((col + 0.5) * hdist, (height - iheight) - (row + 0.5) * vdist, (col + 0.5) * hdist, (height - iheight) - (row + 3.5) * vdist);
}
return grid[col][row];
}
}
}
//horizontals
for (let row = 0; row < grid[0].length; row++) {
for (let col = 0; col <= grid.length - 4; col++) {
if (areEqual(grid[col][row], grid[col + 1][row], grid[col + 2][row], grid[col + 3][row]) && grid[col][row] != VOID) {
if (draw) {
stroke(0);
strokeWeight(8);
line((col + 0.5) * hdist, (height - iheight) - (row + 0.5) * vdist, (col + 3.5) * hdist, (height - iheight) - (row + 0.5) * vdist);
}
return grid[col][row];
}
}
}
//bottomleft-topright diagonals
for (let col = 0; col <= grid.length - 4; col++) {
for (let row = 0; row <= grid[0].length - 4; row++) {
if (areEqual(grid[col][row], grid[col + 1][row + 1], grid[col + 2][row + 2], grid[col + 3][row + 3]) && grid[col][row] != VOID) {
if (draw) {
stroke(0);
strokeWeight(8);
line((col + 0.5) * hdist, (height - iheight) - (row + 0.5) * vdist, (col + 3.5) * hdist, (height - iheight) - (row + 3.5) * vdist);
}
return grid[col][row];
}
}
}
//topleft-bottomright diagonals
for (let col = 0; col <= grid.length - 4; col++) {
for (let row = grid[0].length - 1; row >= 3; row--) {
if (areEqual(grid[col][row], grid[col + 1][row - 1], grid[col + 2][row - 2], grid[col + 3][row - 3]) && grid[col][row] != VOID) {
if (draw) {
stroke(0);
strokeWeight(8);
line((col + 0.5) * hdist, (height - iheight) - (row + 0.5) * vdist, (col + 3.5) * hdist, (height - iheight) - (row - 2.5) * vdist);
}
return grid[col][row];
}
}
}
//TIE and VOID
for (let col = 0; col < grid.length; col++) {
for (let row = 0; row < grid[0].length; row++) {
if (grid[col][row] == VOID) {
return VOID;
}
}
}
return TIE;
}
function makeTurn(player, grid, colState, col) {
if (colState[col] < grid[0].length) {
grid[col][colState[col]] = player;
colState[col]++;
return true;
}
return false;
}
function findBestTurn(g, cS, player, count) { //find best Turn for player wiht minimax
let grid = copy2DArray(g);
let colState = cS.slice();
let max = player == RED;
let best = [{
col: -1,
sc: 2,
c: count
}];
if (max) {
best[0].sc = -2;
}
for (let i = 0; i < grid.length; i++) {
if (makeTurn(player, grid, colState, i)) { //if no occupied => make that turn and score it
let scc = score(grid, colState, player, count);
let curr = {
col: i,
sc: scc.sc, //score of the turn 1: RED wins, -1: YELLOW wins, 0: tie
c: scc.c
};
if (curr.sc == best[0].sc && curr.c == best[0].c) {
best.push(curr);
} else {
if (max) { //if solving for best turn for X: we want maximum turn (so that RED wins)
if (curr.sc > best[0].sc || (curr.sc == best[0].sc && curr.c < best[0].c)) {
best = [curr];
}
} else { //if solving for best turn for O: we want minimum turn (so that YELLOW wins)
if (curr.sc < best[0].sc || (curr.sc == best[0].sc && curr.c < best[0].c)) {
best = [curr];
}
}
}
undoTurn(player, grid, colState, i);
}
}
return random(best);
}
function score(grid, colState, player, count) {
let winner = checkWinner(grid, false);
if (winner != VOID) {
return {
sc: winner,
c: recDepth - count
}
}
if (count <= 0) {
return {
sc: 0,
c: recDepth - count
}
}
let next = findBestTurn(grid, colState, nextPlayer(player), count - 1);
return {
sc: next.sc,
c: recDepth - next.c
}
}
function listAllTurns(g, cS, player, count) {
let turns = [];
let grid = copy2DArray(g);
let colState = cS.slice();
if (count <= 0) {
for (let i = 0; i < grid.length; i++) {
if (makeTurn(player, grid, colState, i)) {
turns.push({
p: player,
col: i,
c: count,
sc: score(grid, colState, player, count).sc
});
undoTurn(player, grid, colState, i);
}
}
return turns;
}
for (let i = 0; i < grid.length; i++) {
if (makeTurn(player, grid, colState, i)) {
if (checkWinner(grid, false) != VOID) {
turns.push({
p: player,
col: i,
c: count,
sc: checkWinner(grid, false),
next: null
});
} else {
turns.push({
p: player,
col: i,
c: count,
sc: score(grid, colState, player, count).sc,
next: listAllTurns(grid, colState, nextPlayer(player), count - 1)
});
}
undoTurn(player, grid, colState, i);
}
}
return turns;
}
function undoTurn(player, grid, colState, col) {
colState[col]--;
grid[col][colState[col]] = VOID;
}
function drawGrid(grid) {
background(20, 30, 180);
let hdist = width / cols;
let vdist = (height - iheight) / rows;
for (let i = 0; i < grid.length; i++) {
for (let j = 0; j < grid[0].length; j++) {
let c = color(255);
if (grid[i][j] == RED) {
c = color(180, 20, 10);
}
if (grid[i][j] == YELLOW) {
c = color(200, 200, 0);
}
noStroke();
fill(c);
ellipse((i + 0.5) * hdist, (height - iheight) - (j + 0.5) * vdist, fw, fw);
}
}
}
function info(msg) {
noStroke();
fill(20, 30, 180);
rect(0, height - iheight, width, iheight);
fill(0);
textSize(iheight / 3);
text(msg, width / 2, height - iheight / 2);
}
function nextPlayer(player) {
if (player == RED) {
return YELLOW;
}
return RED;
}
function createGrid(cols, rows) {
let grid = [];
for (let i = 0; i < cols; i++) {
let col = [];
for (let j = 0; j < rows; j++) {
col[j] = VOID;
}
grid[i] = col;
}
return grid;
}
function createCol(cols) {
let colState = [];
for (let i = 0; i < cols; i++) {
colState[i] = 0;
}
return colState;
}
function copy2DArray(arr) {
let cop = [];
for (var i = 0; i < arr.length; i++) {
cop[i] = arr[i].slice();
}
return cop;
}
function copyArray(arr) {
let cop = arr.slice();
return cop;
}
function areEqual(a, b, c, d) {
return a == b && a == c && a == d;
}