diff --git a/README.md b/README.md new file mode 100644 index 0000000..f8f8057 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +tiktaktoe + +Egle Sabaliauskaite S2010629010 +Sahabaj Barbhuiya S190629001 + +Final TikTakToe project for NDS course. + +Game logic, win/lost message is working. diff --git a/TikTakToe/TikTakToeGameModel.cpp b/TikTakToe/TikTakToeGameModel.cpp index c57de10..347a068 100644 --- a/TikTakToe/TikTakToeGameModel.cpp +++ b/TikTakToe/TikTakToeGameModel.cpp @@ -20,6 +20,7 @@ #include // for operator== #include // for basic_json<>::object_t, basic_json<>::v... +#include TikTakToeGameModel TikTakToeGameModel::gameModel; @@ -33,12 +34,14 @@ void TikTakToeGameModel::playersMove(const std::string& player, int cellID) { cellValue = -1; } - board[cellID] = cellValue; - - if (whosNext >= 1) { - whosNext = 0; - } else { - whosNext += 1; + if(board[cellID]== 0 && !gameEnded){ + board[cellID] = cellValue; + gameWon(cellValue); + if (whosNext >= 1) { + whosNext = 0; + } else { + whosNext += 1; + } } } } @@ -49,6 +52,45 @@ void TikTakToeGameModel::resetBoard() { board[i] = 0; } } +void TikTakToeGameModel::gameWon(int cellValue) { + + int playerNum; + if (whosNext >= 1) { + playerNum = 1; + } else { + playerNum = 0; + } + + if (board[0]==cellValue && board[1]==cellValue && board[2]==cellValue){ + gameEnded = true; + + }else if (board[3]==cellValue && board[4]==cellValue && board[5]==cellValue){ + gameEnded = true; + + }else if (board[6]==cellValue && board[7]==cellValue && board[8]==cellValue){ + gameEnded = true; + + }else if (board[0]==cellValue && board[3]==cellValue && board[6]==cellValue){ + gameEnded = true; + + }else if (board[1]==cellValue && board[4]==cellValue && board[7]==cellValue){ + gameEnded = true; + + }else if (board[2]==cellValue && board[5]==cellValue && board[8]==cellValue){ + gameEnded = true; + + } else if (board[0]==cellValue && board[4]==cellValue && board[8]==cellValue){ + gameEnded = true; + + }else if (board[2]==cellValue && board[4]==cellValue && board[6]==cellValue){ + gameEnded = true; + + }else if (board[0] == !cellValue && board[1] == !cellValue && board[2] == !cellValue && board[3] == !cellValue && board[4] == !cellValue && board[5] == !cellValue && board[6] == !cellValue && board[7] == !cellValue && board[8] == !cellValue) { + gameEnded = true; + + } + +} nlohmann::json TikTakToeGameModel::updateClientState() { nlohmann::json message; @@ -56,7 +98,7 @@ nlohmann::json TikTakToeGameModel::updateClientState() { message["type"] = "update"; message["whosTurn"] = players[whosNext]; message["board"] = board; - + return message; } diff --git a/TikTakToe/TikTakToeGameModel.h b/TikTakToe/TikTakToeGameModel.h index 7abda23..9b74fdf 100644 --- a/TikTakToe/TikTakToeGameModel.h +++ b/TikTakToe/TikTakToeGameModel.h @@ -29,12 +29,15 @@ class TikTakToeGameModel { public: void playersMove(const std::string& player, int cellID); void resetBoard(); + void gameWon(int cellValue); nlohmann::json updateClientState(); static TikTakToeGameModel& getGameModel(); protected: + bool gameEnded = false; std::string players[2] = {"red", "blue"}; + std::string state[3] = {"Won", "Lost", "Draw"}; int whosNext = 0; int numPlayers = 0; int board[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; diff --git a/TikTakToe/TikTakToeSubProtocol.cpp b/TikTakToe/TikTakToeSubProtocol.cpp index c681069..8600f70 100644 --- a/TikTakToe/TikTakToeSubProtocol.cpp +++ b/TikTakToe/TikTakToeSubProtocol.cpp @@ -89,15 +89,9 @@ 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(); + } data.clear(); @@ -113,6 +107,7 @@ void TikTakToeSubProtocol::onPongReceived() { } void TikTakToeSubProtocol::onDisconnected() { + nlohmann::json json; VLOG(0) << "TikTakToe on disconnected:"; if (activePlayer) { @@ -121,7 +116,7 @@ void TikTakToeSubProtocol::onDisconnected() { if (gameModel.numPlayers == 0) { gameModel.resetBoard(); } - } + } VLOG(0) << "\tServer: " + getLocalAddressAsString(); VLOG(0) << "\tClient: " + getRemoteAddressAsString(); diff --git a/TikTakToe/config.h.in b/TikTakToe/config.h.in index 8cffcfe..f7dec76 100644 --- a/TikTakToe/config.h.in +++ b/TikTakToe/config.h.in @@ -1,22 +1,22 @@ #ifndef CONFIG #define CONFIG -#cmakedefine CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@/" +#cmakedefine CMAKE_SOURCE_DIR "/home/voc/projects/ServerVoc/" -#define SNODEC_CMAKE_SOURCE_DIR "/home/voc/projects/ServerVoc/" +#define SERVERROOT CMAKE_SOURCE_DIR "docs/html" -#define SERVERROOT SNODEC_CMAKE_SOURCE_DIR "docs/html" +#define SERVERCAFILE CMAKE_SOURCE_DIR "certs/snode.c_-_Root_CA.crt" +#define SERVERCERTF CMAKE_SOURCE_DIR "certs/snode.c_-_server.pem" +#define SERVERKEYF CMAKE_SOURCE_DIR "certs/snode.c_-_server.key.encrypted.pem" -#define SERVERCAFILE SNODEC_CMAKE_SOURCE_DIR "certs/snode.c_-_Root_CA.crt" -#define SERVERCERTF SNODEC_CMAKE_SOURCE_DIR "certs/snode.c_-_server.pem" -#define SERVERKEYF SNODEC_CMAKE_SOURCE_DIR "certs/snode.c_-_server.key.encrypted.pem" - -#define CLIENTCAFILE SNODEC_CMAKE_SOURCE_DIR "certs/snode.c_-_Root_CA.crt" -#define CLIENTCERTF SNODEC_CMAKE_SOURCE_DIR "certs/snode.c_-_client.pem" -#define CLIENTKEYF SNODEC_CMAKE_SOURCE_DIR "certs/snode.c_-_client.key.encrypted.pem" +#define CLIENTCAFILE CMAKE_SOURCE_DIR "certs/snode.c_-_Root_CA.crt" +#define CLIENTCERTF CMAKE_SOURCE_DIR "certs/snode.c_-_client.pem" +#define CLIENTKEYF CMAKE_SOURCE_DIR "certs/snode.c_-_client.key.encrypted.pem" #define KEYFPASS "snode.c" #define MAX_FLYING_PINGS 3 +#define TIKTAKTOEPATH "/home/student/projects/tiktaktoe/tiktaktoe/websocket-tic-tac-toe/public" + #endif diff --git a/TikTakToe/tiktaktoe.cpp b/TikTakToe/tiktaktoe.cpp index f46a058..58f49d8 100644 --- a/TikTakToe/tiktaktoe.cpp +++ b/TikTakToe/tiktaktoe.cpp @@ -36,7 +36,7 @@ int main(int argc, char* argv[]) { req.url = "/index.html"; } - res.sendFile(CMAKE_SOURCE_DIR "public" + req.url, [&req](int ret) -> void { + res.sendFile(TIKTAKTOEPATH + req.url, [&req](int ret) -> void { if (ret != 0) { PLOG(ERROR) << req.url; } @@ -44,7 +44,7 @@ int main(int argc, char* argv[]) { }); legacyApp.get("/stylesheets", [] APPLICATION(req, res) { - res.sendFile(CMAKE_SOURCE_DIR "public" + req.url, [&req](int ret) -> void { + res.sendFile(TIKTAKTOEPATH + req.url, [&req](int ret) -> void { if (ret != 0) { PLOG(ERROR) << req.url; } @@ -52,7 +52,7 @@ int main(int argc, char* argv[]) { }); legacyApp.get("/js", [] APPLICATION(req, res) { - res.sendFile(CMAKE_SOURCE_DIR "public" + req.url, [&req](int ret) -> void { + res.sendFile(TIKTAKTOEPATH + req.url, [&req](int ret) -> void { if (ret != 0) { PLOG(ERROR) << req.url; } @@ -82,7 +82,7 @@ int main(int argc, char* argv[]) { req.url = "/index.html"; } - res.sendFile(CMAKE_SOURCE_DIR "public" + req.url, [&req](int ret) -> void { + res.sendFile(TIKTAKTOEPATH + req.url, [&req](int ret) -> void { if (ret != 0) { PLOG(ERROR) << req.url; } @@ -90,7 +90,7 @@ int main(int argc, char* argv[]) { }); tlsApp.get("/stylesheets", [] APPLICATION(req, res) { - res.sendFile(CMAKE_SOURCE_DIR "public" + req.url, [&req](int ret) -> void { + res.sendFile(TIKTAKTOEPATH + req.url, [&req](int ret) -> void { if (ret != 0) { PLOG(ERROR) << req.url; } @@ -98,7 +98,7 @@ int main(int argc, char* argv[]) { }); tlsApp.get("/js", [] APPLICATION(req, res) { - res.sendFile(CMAKE_SOURCE_DIR "public" + req.url, [&req](int ret) -> void { + res.sendFile(TIKTAKTOEPATH + req.url, [&req](int ret) -> void { if (ret != 0) { PLOG(ERROR) << req.url; } diff --git a/websocket-tic-tac-toe/public/index.html b/websocket-tic-tac-toe/public/index.html index 4551366..6f46c30 100644 --- a/websocket-tic-tac-toe/public/index.html +++ b/websocket-tic-tac-toe/public/index.html @@ -3,32 +3,34 @@ Websocket Tic Tac Toe +

Websocket Tic Tac Toe

- +

S2010629010 S1910629001

- - - + + + - - - + + + - - - + + +
Player Name
Player Turn
+

diff --git a/websocket-tic-tac-toe/public/js/app.js b/websocket-tic-tac-toe/public/js/app.js index 41ac7a2..89b2c1b 100644 --- a/websocket-tic-tac-toe/public/js/app.js +++ b/websocket-tic-tac-toe/public/js/app.js @@ -23,8 +23,13 @@ var initializeBoard = () => { var updateBoard = () => { let myTurn = gameState.whosTurn === gameState.playerID ? "My Turn" : "Opponents Turn" document.querySelector('.game-info__players-turn').innerText = myTurn; - let board = gameState.board; + let cellValue; + if (gameState.playerID==0) { + cellValue=-1; + } else{ + cellValue=1; + } for(let i = 0; i < board.length; i++) { let element = document.querySelector(`.game-board__cell[data-id='${i}']`) element.classList.remove('game-board__cell--blue') @@ -35,14 +40,60 @@ var updateBoard = () => { if (board[i] > 0) { element.classList.add('game-board__cell--red') } + } + playerWon(); +} + +var playerWon = () => { + let gameOver = gameState.whosTurn === gameState.playerID ? "Lost 😱" : "Won 🎉" + let board = gameState.board; + + if (board[0]==1 && board[1]==1 && board[2]==1){ + document.querySelector('.game-info__state').innerText = gameOver; + }else if (board[3]==1 && board[4]==1 && board[5]==1){ + document.querySelector('.game-info__state').innerText = gameOver; + }else if (board[6]==1 && board[7]==1 && board[8]==1){ + document.querySelector('.game-info__state').innerText = gameOver; + }else if (board[0]==1 && board[3]==1 && board[6]==1){ + document.querySelector('.game-info__state').innerText = gameOver + }else if (board[1]==1 && board[4]==1 && board[7]==1){ + document.querySelector('.game-info__state').innerText = gameOver; + }else if (board[2]==1 && board[5]==1 && board[8]==1){ + document.querySelector('.game-info__state').innerText = gameOver; + } else if (board[0]==1 && board[4]==1 && board[8]==1){ + document.querySelector('.game-info__state').innerText = gameOver; + }else if (board[2]==1 && board[4]==1 && board[6]==1){ + document.querySelector('.game-info__state').innerText = gameOver; + } + + if (board[0]==-1 && board[1]==-1 && board[2]==-1){ + document.querySelector('.game-info__state').innerText = gameOver; + }else if (board[3]==-1 && board[4]==-1 && board[5]==-1){ + document.querySelector('.game-info__state').innerText = gameOver; + }else if (board[6]==-1 && board[7]==-1 && board[8]==-1){ + document.querySelector('.game-info__state').innerText = gameOver; + }else if (board[0]==-1 && board[3]==-1 && board[6]==-1){ + document.querySelector('.game-info__state').innerText = gameOver + }else if (board[1]==-1 && board[4]==-1 && board[7]==-1){ + document.querySelector('.game-info__state').innerText = gameOver; + }else if (board[2]==-1 && board[5]==-1 && board[8]==-1){ + document.querySelector('.game-info__state').innerText = gameOver; + } else if (board[0]==-1 && board[4]==-1 && board[8]==-1){ + document.querySelector('.game-info__state').innerText = gameOver; + }else if (board[2]==-1 && board[4]==-1 && board[6]==-1){ + document.querySelector('.game-info__state').innerText = gameOver; + } + + else if (board[0]!==0 && board[1]!==0 && board[2]!==0 && board[3]!==0 && board[4]!==0 && board[5]!==0 && board[6]!==0 && board[7]!==0 && board[8]!==0) { + document.querySelector('.game-info__state').innerText = "Draw"; + } } // 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; @@ -55,7 +106,7 @@ ws.addEventListener('message', (message) => { gameState.board = action.board; updateBoard(); loadingEl.style.display = 'none'; - break; + break; default: console.error("Invalid action"); } diff --git a/websocket-tic-tac-toe/public/stylesheets/app.css b/websocket-tic-tac-toe/public/stylesheets/app.css index 659c1f1..2b5696b 100644 --- a/websocket-tic-tac-toe/public/stylesheets/app.css +++ b/websocket-tic-tac-toe/public/stylesheets/app.css @@ -1,3 +1,7 @@ +@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap'); +html{ + font-family: 'Roboto', sans-serif; +} .game-title { font-weight: bold; font-size: 2.5rem; @@ -28,6 +32,13 @@ text-align: center; } +.game-info__state { + font-weight: bold; + font-size: 3rem; + text-align: center; + color: blue; +} + .game-board { width: 500px; height: 500px; @@ -37,11 +48,34 @@ } .game-board__cell--red { - background: red; + background: white; + width: 170px; + height: 170px; + position: relative; +} +.game-board__cell--red:after { + content: ''; + height: 170px; + border-left: 4px solid red; + position: absolute; + transform: rotate(45deg); + left: 78px; +} + +.game-board__cell--red:before { + content: ''; + height: 170px; + border-left: 4px solid red; + position: absolute; + transform: rotate(-45deg); + left: 78px; } .game-board__cell--blue { background: blue; + border-radius: 50%; + width: 170px; + height: 170px; } .game-loading {