diff --git a/client/src/js/Game/Scoreboard.ts b/client/src/js/Game/Scoreboard.ts index 72b5d9d..5a3332e 100644 --- a/client/src/js/Game/Scoreboard.ts +++ b/client/src/js/Game/Scoreboard.ts @@ -60,9 +60,13 @@ class Scoreboard { public initValues() : void { const { scoreboard, myHits, enemyHits } = this.els; + const { enemy, my } = this.hits; myHits.classList.add('hits', 'my-hits'); enemyHits.classList.add('hits', 'enemy-hits'); + + this.myHits = my; + this.enemyHits = enemy; scoreboard.append(myHits, enemyHits); } diff --git a/server/@types/index.d.ts b/server/@types/index.d.ts new file mode 100644 index 0000000..6f39780 --- /dev/null +++ b/server/@types/index.d.ts @@ -0,0 +1,9 @@ +export interface CardJSON { + id: string; + order: number; + icon: string; +} + +export interface CardAPI { + icon: string; +} diff --git a/server/app.js b/server/app.ts similarity index 82% rename from server/app.js rename to server/app.ts index 082c79b..e3e35d5 100644 --- a/server/app.js +++ b/server/app.ts @@ -1,14 +1,17 @@ -const Express = require('express')(); -const Http = require('http').Server(Express); -const io = require('socket.io')(Http); +import Express from 'express'; +import Http from 'http'; +import socket, { Packet } from 'socket.io'; -const cards = require('./src/data/cards'); -const Board = require('./src/Board'); +const app = new Http.Server(Express()); +const io = socket(app); -const games = {}; +import cards from './src/data/cards'; +import Board from './src/Board'; + +const games : Record = {}; io.on('connection', socket => { - let userRoom; + let userRoom : string; socket.on('room', room => { const rooms = io.sockets.adapter.rooms; @@ -60,7 +63,7 @@ io.on('connection', socket => { const winner = game.checkIfFinish(); if(winner) { - io.in(room).clients((error, clients) => { + io.in(room).clients((error : Packet, clients : string[]) => { if(error) throw error; clients.map(socketId => io.sockets.sockets[socketId]) @@ -83,7 +86,7 @@ io.on('connection', socket => { io.sockets.in(userRoom).emit('enemy-left'); delete games[userRoom]; - io.in(userRoom).clients((error, clients) => { + io.in(userRoom).clients((error : Packet, clients : string[]) => { if(error) throw error; clients.forEach(socketId => io.sockets.sockets[socketId].leave(userRoom)); @@ -91,4 +94,4 @@ io.on('connection', socket => { } }); -Http.listen(process.env.PORT || 3000); \ No newline at end of file +app.listen(process.env.PORT || 3000); diff --git a/server/package.json b/server/package.json index c50b734..25438ea 100644 --- a/server/package.json +++ b/server/package.json @@ -4,7 +4,7 @@ "main": "index.js", "license": "MIT", "scripts": { - "dev": "nodemon app.js", + "dev": "nodemon --watch '*.ts' --exec 'ts-node' app.ts", "start": "node app.js" }, "dependencies": { @@ -12,6 +12,11 @@ "socket.io": "^2.3.0" }, "devDependencies": { - "nodemon": "^2.0.4" + "@types/express": "^4.17.7", + "@types/node": "^14.0.26", + "@types/socket.io": "^2.1.10", + "nodemon": "^2.0.4", + "ts-node": "^8.10.2", + "typescript": "^3.9.7" } } diff --git a/server/src/Board.js b/server/src/Board.ts similarity index 60% rename from server/src/Board.js rename to server/src/Board.ts index e9314e4..0b8fbc1 100644 --- a/server/src/Board.js +++ b/server/src/Board.ts @@ -1,5 +1,20 @@ +import { CardJSON, CardAPI } from "../@types"; + +interface ScoreBoard extends Record{ + total : number; +} + class Board { - constructor (cards, players) { + private elapsedTime : number; + private cards : CardJSON[]; + private players : string[]; + private activesCards : CardJSON[]; + private matches : CardJSON[]; + public scoreboard : ScoreBoard; + public rematchRequests : number; + public playerOfTheTime : string; + + constructor (cards : CardAPI[], players : string[]) { this.elapsedTime = 0; this.cards = this.shuffle([...cards, ...cards].map(card => ({ ...card }))); this.players = players; @@ -11,17 +26,20 @@ class Board { this.playerOfTheTime = players[Math.floor(Math.random() * 2)]; } - shuffle (cards) { - return cards.map(card => { + private shuffle (cards : CardAPI[]) : CardJSON[] { + return cards.map(({ icon }) => { const randomNumber = Math.floor(Math.random() * cards.length); - card.order = randomNumber; - card.id = `_${Math.random().toString(36).substr(2, 9)}`; - + const card : CardJSON = { + icon, + order: randomNumber, + id: `_${Math.random().toString(36).substr(2, 9)}` + }; + return card; }); } - click (id) { + public click (id : string) : CardJSON[] { const card = this.cards.find(card => card.id === id); if(!card || !this.checkIfCanFlip(id) || this.activesCards.length >= 2) return this.activesCards; @@ -31,7 +49,7 @@ class Board { return this.activesCards; } - checkIfMatch () { + public checkIfMatch () : boolean { const [first, second] = this.activesCards; const isMatch = first.icon === second.icon; @@ -41,14 +59,14 @@ class Board { return isMatch; } - checkIfCanFlip (id) { + public checkIfCanFlip (id : string) : boolean { const containInActives = this.activesCards.some(card => card.id === id); const containInMatches = this.matches.some(card => card.id === id); return !(containInActives || containInMatches) } - checkIfFinish () { + public checkIfFinish () : boolean | string { if(this.scoreboard.total === this.cards.length / 2) { return this.players.reduce((winner, client) => this.scoreboard[client] > this.scoreboard[winner] ? client : winner); } @@ -56,15 +74,15 @@ class Board { return false; } - incrementHits () { + public incrementHits () : void { const score = this.scoreboard[this.playerOfTheTime] this.scoreboard[this.playerOfTheTime] = (score || 0) + 1; this.scoreboard.total++; } - togglePlayer () { - this.playerOfTheTime = this.players.find(player => player !== this.playerOfTheTime); + public togglePlayer () : void { + this.playerOfTheTime = this.players.find(player => player !== this.playerOfTheTime) || ''; } } -module.exports = Board; \ No newline at end of file +export default Board; diff --git a/server/src/Card.js b/server/src/Card.js deleted file mode 100644 index e69de29..0000000 diff --git a/server/src/data/cards.js b/server/src/data/cards.ts similarity index 93% rename from server/src/data/cards.js rename to server/src/data/cards.ts index 91c5960..47963b0 100644 --- a/server/src/data/cards.js +++ b/server/src/data/cards.ts @@ -1,6 +1,6 @@ // Simulate a API request -module.exports = [ +export default [ { icon: 'fas spider' }, { icon: 'fas otter' }, { icon: 'fas hippo' }, @@ -12,4 +12,4 @@ module.exports = [ { icon: 'fas dove' }, { icon: 'fas cat' }, { icon: 'fas crow' }, -] \ No newline at end of file +]; diff --git a/server/tsconfig.json b/server/tsconfig.json new file mode 100644 index 0000000..c1df235 --- /dev/null +++ b/server/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + + "strict": true, /* Enable all strict type-checking options. */ + + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + + "skipLibCheck": true, /* Skip type checking of declaration files. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + } +} diff --git a/server/yarn.lock b/server/yarn.lock index a997b9f..3f06c0a 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -14,11 +14,88 @@ dependencies: defer-to-connect "^1.0.1" +"@types/body-parser@*": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" + integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== + dependencies: + "@types/connect" "*" + "@types/node" "*" + "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/connect@*": + version "3.4.33" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" + integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== + dependencies: + "@types/node" "*" + +"@types/engine.io@*": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@types/engine.io/-/engine.io-3.1.4.tgz#3d9472711d179daa7c95c051e50ad411e18a9bdc" + integrity sha512-98rXVukLD6/ozrQ2O80NAlWDGA4INg+tqsEReWJldqyi2fulC9V7Use/n28SWgROXKm6003ycWV4gZHoF8GA6w== + dependencies: + "@types/node" "*" + +"@types/express-serve-static-core@*": + version "4.17.9" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz#2d7b34dcfd25ec663c25c85d76608f8b249667f1" + integrity sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@^4.17.7": + version "4.17.7" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.7.tgz#42045be6475636d9801369cd4418ef65cdb0dd59" + integrity sha512-dCOT5lcmV/uC2J9k0rPafATeeyz+99xTt54ReX11/LObZgfzJqZNcW27zGhYyX+9iSEGXGt5qLPwRSvBZcLvtQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/mime@*": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a" + integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q== + +"@types/node@*", "@types/node@^14.0.26": + version "14.0.26" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.26.tgz#22a3b8a46510da8944b67bfc27df02c34a35331c" + integrity sha512-W+fpe5s91FBGE0pEa0lnqGLL4USgpLgs4nokw16SrBBco/gQxuua7KnArSEOd5iaMqbbSHV10vUDkJYJJqpXKA== + +"@types/qs@*": + version "6.9.4" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a" + integrity sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ== + +"@types/range-parser@*": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" + integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== + +"@types/serve-static@*": + version "1.13.4" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.4.tgz#6662a93583e5a6cabca1b23592eb91e12fa80e7c" + integrity sha512-jTDt0o/YbpNwZbQmE/+2e+lfjJEJJR0I3OFaKQKPWkASkCoW3i6fsUnqudSMcNAfbtmADGu8f4MV4q+GqULmug== + dependencies: + "@types/express-serve-static-core" "*" + "@types/mime" "*" + +"@types/socket.io@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-2.1.10.tgz#cb00583313cc40a65d5201e897d7b8c95cfd8c73" + integrity sha512-1fQMaDU/x2LPljEI/QI5IKl8sBYHM/zv32YYKvNrVEor7/1+MLqMqmWt8Bb8Vpf+PlIPBiTTC0BnrRx7ju3xOw== + dependencies: + "@types/engine.io" "*" + "@types/node" "*" + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -70,6 +147,11 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -167,6 +249,11 @@ braces@~3.0.2: dependencies: fill-range "^7.0.1" +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -371,6 +458,11 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + dot-prop@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" @@ -802,6 +894,11 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -1179,6 +1276,19 @@ socket.io@^2.3.0: socket.io-client "2.3.0" socket.io-parser "~3.4.0" +source-map-support@^0.5.17: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + "statuses@>= 1.5.0 < 2", statuses@~1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" @@ -1269,6 +1379,17 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" +ts-node@^8.10.2: + version "8.10.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" + integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA== + dependencies: + arg "^4.1.0" + diff "^4.0.1" + make-error "^1.1.1" + source-map-support "^0.5.17" + yn "3.1.1" + type-fest@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" @@ -1289,6 +1410,11 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typescript@^3.9.7: + version "3.9.7" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" + integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== + undefsafe@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" @@ -1392,3 +1518,8 @@ yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==