Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 80 additions & 12 deletions TikTakToe/TikTakToeGameModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,36 +26,104 @@ TikTakToeGameModel TikTakToeGameModel::gameModel;
void TikTakToeGameModel::playersMove(const std::string& player, int cellID) {
if (player == players[whosNext]) {
int cellValue = 0;
if(board[cellID] == 0){
if (player == "red") {
cellValue = 1;
} else if (player == "blue") {
cellValue = -1;
}
board[cellID] = cellValue;

checkIfGameCompleted();

if (player == "red") {
cellValue = 1;
} else if (player == "blue") {
cellValue = -1;
}

board[cellID] = cellValue;

if (whosNext >= 1) {
whosNext = 0;
} else {
whosNext += 1;
if (whosNext >= 1) {
whosNext = 0;
} else {
whosNext += 1;
}
}
}
}

void TikTakToeGameModel::resetBoard() {
whosNext = 0;
gameFinished= false;
for (int i = 0; i < 9; i++) {
board[i] = 0;
}
}

void TikTakToeGameModel::checkIfGameCompleted() {
//Check for a winner
if(checkForWinner()){
gameFinished = true;
winner = players[whosNext];
}

//Check for a draw
if(checkIfBoardFull() && !gameFinished) {
gameFinished = true;
draw = true;
}
}


bool TikTakToeGameModel::checkForWinner() {
//Vertical
for(int i = 0; i < 3; i++) {
if(board[i] != 0 && board[0 + i] == board [3 + i] && board[3 + i] == board[6 + i]){
return true;
}
}

//Horizontal
for(int i = 0; i < 3; i++) {
if(board[i * 3] != 0 && board[i * 3] == board [i * 3 + 1] && board[i * 3 + 1] == board[i * 3 + 2]){
return true;
}
}

//Diagonal left to right
if(board[0] != 0 && board[0] == board[4] && board[4] == board[8]) {
return true;
}

//Diagonal right to left
if(board[2] != 0 && board[2] == board[4] && board[4] == board[6]) {
return true;
}

return false;
}


bool TikTakToeGameModel::checkIfBoardFull() {
for(int i = 0; i < 9; i++) {
if(board[i] == 0) {
return false;
}
}
return true;
}


nlohmann::json TikTakToeGameModel::updateClientState() {
nlohmann::json message;

message["type"] = "update";
message["whosTurn"] = players[whosNext];
message["board"] = board;

if(gameFinished) {
if(draw) {
message["gameOver"] = "Nobody won, it's a draw!";
} else {
message["gameOver"] = "Congratulations, player " + winner + " won!";
}
}
else {
message["gameOver"] = false;
}

return message;
}
Expand Down
6 changes: 6 additions & 0 deletions TikTakToe/TikTakToeGameModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ class TikTakToeGameModel {
public:
void playersMove(const std::string& player, int cellID);
void resetBoard();
void checkIfGameCompleted();
bool checkForWinner();
bool checkIfBoardFull();
nlohmann::json updateClientState();

static TikTakToeGameModel& getGameModel();
Expand All @@ -38,6 +41,9 @@ class TikTakToeGameModel {
int whosNext = 0;
int numPlayers = 0;
int board[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
bool gameFinished = false; //if one player won, or all fields have been filled
bool draw = false; //all fields are filled, but no player won
std::string winner = "";

friend class TikTakToeSubProtocol;

Expand Down
15 changes: 6 additions & 9 deletions TikTakToe/TikTakToeSubProtocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,17 +88,14 @@ void TikTakToeSubProtocol::onMessageEnd() {

if (action["type"] == "move") {
gameModel.playersMove(action["playerID"], action["cellID"]);
nlohmann::json message = gameModel.updateClientState();

/* // also possible
forEachClient([&message](SubProtocol* client) {
client->sendMessage(message.dump());
});
*/
}

sendBroadcast(message.dump());
VLOG(0) << "SendMessage Dump: " << message.dump();
if (action["type"] == "reset-game") {
gameModel.resetBoard();
}
nlohmann::json message = gameModel.updateClientState();
sendBroadcast(message.dump());
VLOG(0) << "SendMessage Dump: " << message.dump();

data.clear();
}
Expand Down
2 changes: 2 additions & 0 deletions TikTakToe/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ <h1 class="game-title">Websocket Tic Tac Toe</h1>
<div class="game-info">
<div class="game-info__players-name">Player Name</div>
<div class="game-info__players-turn">Player Turn</div>
<div class="game-info__status">Status: Game in Progress</div>
<button class="reset-game">Start a new game</button>
</div>
</div>

Expand Down
26 changes: 25 additions & 1 deletion TikTakToe/public/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ if (location.protocol == "https:") {
var gameState = {
whosTurn: undefined,
playerID: undefined,
gameOver: undefined,
board: [0, 0, 0, 0, 0, 0, 0, 0, 0]
};

Expand All @@ -21,6 +22,7 @@ var initializeBoard = () => {

// This function updates the board and whos turn it is.
var updateBoard = () => {

let myTurn = gameState.whosTurn === gameState.playerID ? "My Turn" : "Opponents Turn"
document.querySelector('.game-info__players-turn').innerText = myTurn;

Expand All @@ -36,13 +38,19 @@ var updateBoard = () => {
element.classList.add('game-board__cell--red')
}
}

if(gameState.gameOver) {
document.querySelector('.game-info__status').innerText = gameState.gameOver;
document.querySelector('.game-board').style.pointerEvents = "none";
}
}

// This responds to the server push messages
ws.addEventListener('message', (message) => {

let action = JSON.parse(message.data);
let loadingEl = document.querySelector('.game-loading');

switch(action.type) {
case 'setup':
gameState = action.playerData;
Expand All @@ -53,6 +61,7 @@ ws.addEventListener('message', (message) => {
loadingEl.style.display = 'block';
gameState.whosTurn = action.whosTurn;
gameState.board = action.board;
gameState.gameOver = action.gameOver;
updateBoard();
loadingEl.style.display = 'none';
break;
Expand All @@ -75,3 +84,18 @@ ws.addEventListener('open', () => {
ws.send(JSON.stringify(message));
})
})

ws.addEventListener('open', () => {
document
.querySelector('.reset-game')
.addEventListener('click', (event) => {
document.querySelector('.game-board').style.pointerEvents = "auto";
document.querySelector('.game-info__status').innerText = "Status: Game in Progress";
let element = event.target;
let message = {
type: 'reset-game',
playerID: gameState.playerID,
}
setTimeout(function(){ ws.send(JSON.stringify(message)); }, 1000);
})
})
24 changes: 24 additions & 0 deletions TikTakToe/public/stylesheets/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@
font-size: 1.5rem;
text-align: center;
}
.game-info__status {
font-weight: bold;
font-size: 1.5rem;
text-align: center;
padding-top: 20px;
}
.reset-game {
display: block;
text-align: center;
margin: 20px auto;
box-shadow:inset 0px 1px 0px 0px #ffffff;
background:linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%);
background-color:#f9f9f9;
border-radius:6px;
border:1px solid #dcdcdc;
cursor:pointer;
color:#666666;
font-family:Arial;
font-size:15px;
font-weight:bold;
padding:6px 24px;
text-decoration:none;
text-shadow:0px 1px 0px #ffffff;
}

.game-board {
width: 500px;
Expand Down