Skip to content

Instantly share code, notes, and snippets.

@roehrdor
Created June 23, 2018 13:24
Show Gist options
  • Save roehrdor/30ce5c61c4e11e48a7c47ac655be04e0 to your computer and use it in GitHub Desktop.
Save roehrdor/30ce5c61c4e11e48a7c47ac655be04e0 to your computer and use it in GitHub Desktop.
(function (window) {
'use strict';
var App = window.App || {};
class ConnectFour {
constructor() {
this.settings = {
displayDump: false
};
this.gameOver = false;
this.current = 0;
this.colHeight = [0, 0, 0, 0, 0, 0, 0];
this.field = [
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]
];
this.tokens = { 0: '.', 1: '1', 2: '2' };
this.color = { 0: "lightgrey", 1: "green", 2: "yellow"};
this.winmsg = {
2: ["Server wins!", "THe Server has won the game!"],
1: ["You win!", "You have won the game!"]
};
this.generateBoard();
}
// Reset the field to play again without reloading the tab
reset() {
this.field.forEach(row => row.fill(0));
this.colHeight.fill(0);
this.current = 0;
this.gameOver = false;
this.updateBoard();
}
// Start a new Game by calling the restful endpoint
startNewGame() {
this.reset();
$.get('https://www2.hs-esslingen.de/~dbenin/connectfour/', {"command":"start"}, (data) => {
$('#statusline').append(JSON.parse(data).statusmsg + "<br/>");
});
}
// Generate the output for a cell in the debug field
genFieldText(cell) {
return ` <span style=color:${this.color[cell]}>${this.tokens[cell]}</span> `;
}
// Dump the field to the debug div by calling `genFieldText` per cell
dumpField() {
if (!this.settings.displayDump) return;
const textField = document.getElementById('debug');
textField.innerHTML = "<p id=\"debug-title\">Debug Environment</p>";
this.field.forEach(row => {
row.forEach(cell => textField.innerHTML += this.genFieldText(cell));
textField.innerHTML += '<br/>';
});
}
// Return true if the field is completely filled
isFieldFull() {
return this.colHeight.find(e => e < 6) === undefined;
}
// Return the row a token in the `col` column would be placed at
freePosForCol(col) {
return this.colHeight[col];
}
// Update the board by drawing the tokens
updateBoard() {
const board = $("#board");
this.dumpField();
this.field.forEach((row, ri) => {
row.forEach((_, ci) => {
const cell = board.find(`[data-row="${ri}"][data-column="${ci}"]`);
cell.css("background-color", this.color[this.field[ri][ci]]);
});
});
}
// Return true if any player has won
hasLineOfFour() {
return this.gameOver;
}
// Return true if its the turn of `tok`'s player
playerMove(tok) {
return this.current !== tok && !this.hasLineOfFour();
}
// Display the winning message
displayIfWon() {
if(this.hasLineOfFour()){
setTimeout(() => {
alert(this.winmsg[this.current][0]);
}, 10);
$('#statusline').append(this.winmsg[this.current][1]);
return true;
}
return false;
}
// Request the move from the server
requestServerMove(col) {
return new Promise((resolve, reject) => {
$.get("https://www2.hs-esslingen.de/~dbenin/connectfour/",
{ "command":"move", "x": col, "matrnr": 123456 },
(data) => resolve(JSON.parse(data).x));
});
}
// Request the server to move in response to selecting the column `col`
async serverMove(col) {
while(!this.insertTokenInCol(await this.requestServerMove(col), 2));
}
// Return true if the last move won the game
checkWinAfterInsert(col, row) {
var cols = 1;
var rows = 1;
var diag1 = 1;
var diag2 = 1;
const token = this.field[5 - row][col];
row = 5 - row;
for (var c = col; cols < 4 && --c >= 0 && this.field[row][c] === token; ++cols);
for (var c = col; cols < 4 && ++c < 7 && this.field[row][c] === token; ++cols);
if (cols > 3) { this.gameOver = true; return; }
for (var r = row; rows < 4 && ++r < 6 && this.field[r][col] === token; ++rows);
if (rows > 3) { this.gameOver = true; return; }
for (var r = row, c = col; diag1 < 4 && --c >= 0 && --r >= 0 && this.field[r][c] === token; ++diag1);
for (var r = row, c = col; diag1 < 4 && ++c < 7 && ++r < 6 && this.field[r][c] === token; ++diag1);
if (diag1 > 3) { this.gameOver = true; return; }
for (var r = row, c = col; diag2 < 4 && ++c < 7 && --r >= 0 && this.field[r][c] === token; ++diag2);
for (var r = row, c = col; diag2 < 5 && --c >= 0 && ++r < 6 && this.field[r][c] === token; ++diag2);
if (diag2 > 3) { this.gameOver = true; return; }
}
// Inser the `token` into the column
// Return true if inserted or not the players turn
// Return false if the column is already filled
insertTokenInCol(col, token) {
if (!this.playerMove(token))
return true;
const row = this.freePosForCol(col);
if (this.colHeight[col] > 5)
return false;
this.current = token;
this.field[5 - row][col] = token;
this.updateBoard();
this.checkWinAfterInsert(col, this.colHeight[col]++);
this.displayIfWon();
return true;
}
// Generate the board
generateBoard() {
for(var i = 0; i < 7; ++i) {
let column = $('<div class="column"></div>').appendTo('#board');
column.attr('data-column', i);
column.on('click', (event) => {
const col = parseInt($(event.currentTarget).attr('data-column'));
this.insertTokenInCol(col, 1);
this.serverMove(col);
});
for (var j = 0; j < 6; ++j) {
let cell = $('<div class="cell"></div>').appendTo(column);
cell.attr('data-row', j);
cell.attr('data-column', i);
}
}
}
}
App.ConnectFour = ConnectFour;
window.App = App;
})(window);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment