From d768d69e3bd8f139f37472b2efdef9a481f79fae Mon Sep 17 00:00:00 2001 From: sormys Date: Sun, 21 May 2023 15:08:31 +0200 Subject: [PATCH 01/19] Added check request --- src/app.ts | 3 + src/routes/gameplay/check.ts | 104 +++++++++++++++++++++++++++++++++++ src/routes/gameplay/fold.ts | 2 +- src/routes/startGame.ts | 18 ++++-- 4 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 src/routes/gameplay/check.ts diff --git a/src/app.ts b/src/app.ts index a4e192a..0b5da4d 100644 --- a/src/app.ts +++ b/src/app.ts @@ -8,6 +8,7 @@ import modifyGame from './routes/modifyGame' import leaveGame from './routes/leaveGame' import startGame from './routes/startGame' import fold from './routes/gameplay/fold' +import check from './routes/gameplay/check' import { rateLimiter } from './utils/rateLimiter' export const app = express() @@ -42,4 +43,6 @@ app.use(startGame) app.use(fold) +app.use(check) + app.use(errorHandling) diff --git a/src/routes/gameplay/check.ts b/src/routes/gameplay/check.ts new file mode 100644 index 0000000..400b9d2 --- /dev/null +++ b/src/routes/gameplay/check.ts @@ -0,0 +1,104 @@ +import { getClient } from '../../utils/databaseConnection' +import { celebrate, Joi, Segments } from 'celebrate' +import { + sendFirebaseMessageToEveryone, + verifyFCMToken, +} from '../../utils/firebase' +import express, { type Router } from 'express' +import { rateLimiter } from '../../utils/rateLimiter' +import { + isPlayerInGame, + isPlayersTurn, + setPlayerState, + setNewCurrentPlayer, + changeGameRoundIfNeeded, +} from '../../utils/commonRequest' +import { type Client } from 'pg' +import sha256 from 'crypto-js/sha256' +import { PlayerState } from '../../utils/types' + +const router: Router = express.Router() + +router.get( + '/check', + rateLimiter, + celebrate({ + [Segments.QUERY]: Joi.object().keys({ + playerToken: Joi.string().required().min(1).max(250).label('playerToken'), + gameId: Joi.number().required().min(0).max(999999).label('gameId'), + }), + }), + async (req, res) => { + const playerToken = req.query.playerToken as string + const gameId = req.query.gameId as string + + if (!(await verifyFCMToken(playerToken))) { + return res.sendStatus(401) + } + + const client = getClient() + + client + .connect() + .then(async () => { + if (!(await isPlayerInGame(playerToken, gameId, client))) { + return res.sendStatus(400) + } + + if (!(await isPlayersTurn(playerToken, gameId, client))) { + return res.sendStatus(402) + } + + if (!(await hasPlayerBetEnough(playerToken, gameId, client))) { + return res.sendStatus(403) + } + + await setPlayerState(playerToken, client, PlayerState.Checked) + const newPlayer = await setNewCurrentPlayer(playerToken, gameId, client) + await changeGameRoundIfNeeded(gameId, newPlayer, client) + + const message = { + data: { + player: sha256(playerToken).toString(), + type: PlayerState.Checked, + actionPayload: '', + }, + token: '', + } + + await sendFirebaseMessageToEveryone(message, gameId, client) + + res.sendStatus(200) + }) + .catch((err) => { + console.log(err.stack) + return res.sendStatus(500) + }) + .finally(async () => { + await client.end() + }) + } +) + +async function getMaxBet(gameId: string, client: Client) { + const query = + 'SELECT bet FROM Players WHERE game_id = $1 AND bet is not NULL order by bet desc limit 1' + return (await client.query(query, [gameId])).rows[0].bet +} + +async function getPlayerBet(playerId: string, client: Client) { + const query = 'SELECT bet FROM Players WHERE token = $1' + return (await client.query(query, [playerId])).rows[0].bet +} + +async function hasPlayerBetEnough( + playerId: string, + gameId: string, + client: Client +) { + const maxBet = await getMaxBet(gameId, client) + const playerBet = await getPlayerBet(playerId, client) + return playerBet >= maxBet +} + +export default router diff --git a/src/routes/gameplay/fold.ts b/src/routes/gameplay/fold.ts index 6239d38..3589ac6 100644 --- a/src/routes/gameplay/fold.ts +++ b/src/routes/gameplay/fold.ts @@ -48,8 +48,8 @@ router.get( return res.sendStatus(402) } - const newPlayer = await setNewCurrentPlayer(playerToken, gameId, client) await setPlayerState(playerToken, client, PlayerState.Folded) + const newPlayer = await setNewCurrentPlayer(playerToken, gameId, client) await changeGameRoundIfNeeded(gameId, newPlayer, client) const message = { diff --git a/src/routes/startGame.ts b/src/routes/startGame.ts index 10bb354..7a3b306 100644 --- a/src/routes/startGame.ts +++ b/src/routes/startGame.ts @@ -154,9 +154,19 @@ async function prepareBlinds( bigBlind, smallBlindValue: string ) { - const query = 'UPDATE Players SET funds=funds-$1 WHERE token=$2' - await client.query(query, [smallBlindValue, smallBlind]) - await client.query(query, [+smallBlindValue * 2, bigBlind]) + const query = 'UPDATE Players SET funds=funds-$1, bet=$2 WHERE token=$3' + const smallBlindQueryValues = [ + smallBlindValue, + parseInt(smallBlindValue), + smallBlind, + ] + const bigBlindQueryValues = [ + +smallBlindValue * 2, + parseInt(smallBlindValue) * 2, + bigBlind, + ] + await client.query(query, smallBlindQueryValues) + await client.query(query, bigBlindQueryValues) } async function updateGameState( @@ -188,7 +198,7 @@ async function updatePlayersStates( client: Client ) { const query = - 'UPDATE Players SET turn=$1, card1=$2, card2=$3, funds=$4 WHERE token=$5' + 'UPDATE Players SET turn=$1, card1=$2, card2=$3, funds=$4, bet=0 WHERE token=$5' const values = [0, 'card1', 'card2', startingFunds, 'token'] for (let i = 0; i < players.length; i++) { values[0] = gameInfo.players[i].turn From b0bbae64d7f9d9eb6fb932b6605c26ef96ee4a8d Mon Sep 17 00:00:00 2001 From: sormys Date: Sun, 21 May 2023 15:09:30 +0200 Subject: [PATCH 02/19] Added tests for check (THEY DON'T END IN A CLEAN WAY) --- src/tests/check.test.ts | 107 ++++++++++++++++++++++++++++++++++++++++ src/tests/fold.test.ts | 7 ++- 2 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 src/tests/check.test.ts diff --git a/src/tests/check.test.ts b/src/tests/check.test.ts new file mode 100644 index 0000000..138449c --- /dev/null +++ b/src/tests/check.test.ts @@ -0,0 +1,107 @@ +import { app } from '../app' +import request from 'supertest' +import { getClient } from '../utils/databaseConnection' +import type { NewGameInfo } from '../utils/types' +import { getPlayersInGame } from '../utils/commonRequest' + +test('Check, wrong args', async () => { + const gameMasterToken = 'CHECKTEST_INCORRECT_GM' + const gameMasterNick = 'CHECK_INC_GM_NICK' + const playerToken = 'CHECKTEST_INCORRECT_P1' + const playerNick = 'CHECK_INC_P1_NICK' + const player2Token = 'CHECKTEST_INCORRECT_P2' + const player2Nick = 'CHECK_INC_P2_NICK' + const wrongToken = 'TESTCHECK_INCORRECT' + const wrongGameId = 'WRONG_ID' + request(app).get(`/check?playerToken=${wrongToken}`).expect(400) + + request(app) + .get(`/check?playerToken=${wrongToken}&gameId=${wrongGameId}`) + .expect(400) + + const client = getClient() + await client.connect() + + const res = await request(app) + .get( + `/createGame?creatorToken=${gameMasterToken}&nickname=${gameMasterNick}` + ) + .expect(200) + + const key = (res.body as NewGameInfo).gameId + await request(app) + .get( + `/joinGame?playerToken=${playerToken}&nickname=${playerNick}&gameId=${key}` + ) + .expect(200) + + await request(app) + .get( + `/joinGame?playerToken=${player2Token}&nickname=${player2Nick}&gameId=${key}` + ) + .expect(200) + + await request(app) + .get(`/startGame?creatorToken=${gameMasterToken}`) + .expect(200) + + const gameId = key.toString() + getPlayersInGame(gameId, client) + .then(async (players) => { + await request(app) + .get(`/check?playerToken=${players[1].token}&gameId=${gameId}`) + .expect(402) + await request(app) + .get(`/check?playerToken=${players[0].token}&gameId=${gameId}`) + .expect(403) + }) + .finally(async () => { + await client.end() + }) +}, 20000) + +test('Check, correct args', async () => { + const gameMasterToken = 'CHECKTEST_GM' + const gameMasterNick = 'CHECK_GM_NICK' + const playerToken = 'CHECKTEST_P1' + const playerNick = 'CHECK_P1_NICK' + const player2Token = 'CHECKTEST_P2' + const player2Nick = 'CHECK_P2_NICK' + const client = getClient() + await client.connect() + + const res = await request(app) + .get( + `/createGame?creatorToken=${gameMasterToken}&nickname=${gameMasterNick}` + ) + .expect(200) + + const key = (res.body as NewGameInfo).gameId + await request(app) + .get( + `/joinGame?playerToken=${playerToken}&nickname=${playerNick}&gameId=${key}` + ) + .expect(200) + + await request(app) + .get( + `/joinGame?playerToken=${player2Token}&nickname=${player2Nick}&gameId=${key}` + ) + .expect(200) + + await request(app) + .get(`/startGame?creatorToken=${gameMasterToken}`) + .expect(200) + + const gameId = key.toString() + getPlayersInGame(gameId, client) + .then(async (players) => { + await client.query('UPDATE Players SET bet=0 WHERE game_id=$1', [gameId]) + await request(app) + .get(`/check?playerToken=${players[0].token}&gameId=${gameId}`) + .expect(200) + }) + .finally(async () => { + await client.end() + }) +}, 20000) diff --git a/src/tests/fold.test.ts b/src/tests/fold.test.ts index 3b1167e..361571c 100644 --- a/src/tests/fold.test.ts +++ b/src/tests/fold.test.ts @@ -2,10 +2,10 @@ import { app } from '../app' import request from 'supertest' import { getClient } from '../utils/databaseConnection' import type { NewGameInfo } from '../utils/types' -import { getGameIdAndStatus, getPlayersInGame } from '../utils/commonRequest' +import { getPlayersInGame } from '../utils/commonRequest' test('Fold, wrong args', (done) => { - const wrongToken = 'TESTLEAVE_INCORRECT' + const wrongToken = 'TESTFOLD_INCORRECT' const wrongGameId = 'WRONG_ID' request(app).get(`/fold?playerToken=${wrongToken}`).expect(400).end(done) @@ -48,8 +48,7 @@ test('Fold, correct arguments, wrong turn', async () => { .get(`/startGame?creatorToken=${gameMasterToken}`) .expect(200) - const gameId = - (await getGameIdAndStatus(gameMasterToken, client)).gameId ?? '' + const gameId = key.toString() const players = await getPlayersInGame(gameId, client) await request(app) From 91444c423fe171898e050d6396f6f011df4b5311 Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 16:13:42 +0200 Subject: [PATCH 03/19] Raise skeleton --- src/app.ts | 3 ++ src/routes/gameplay/raise.ts | 93 ++++++++++++++++++++++++++++++++++ src/tests/actionRaise.test.ts | 94 +++++++++++++++++++++++++++++++++++ src/utils/commonRequest.ts | 38 ++++++++++++++ src/utils/types.ts | 1 + 5 files changed, 229 insertions(+) create mode 100644 src/routes/gameplay/raise.ts create mode 100644 src/tests/actionRaise.test.ts diff --git a/src/app.ts b/src/app.ts index a4e192a..315d715 100644 --- a/src/app.ts +++ b/src/app.ts @@ -8,6 +8,7 @@ import modifyGame from './routes/modifyGame' import leaveGame from './routes/leaveGame' import startGame from './routes/startGame' import fold from './routes/gameplay/fold' +import actionRaise from './routes/gameplay/raise' import { rateLimiter } from './utils/rateLimiter' export const app = express() @@ -42,4 +43,6 @@ app.use(startGame) app.use(fold) +app.use(actionRaise) + app.use(errorHandling) diff --git a/src/routes/gameplay/raise.ts b/src/routes/gameplay/raise.ts new file mode 100644 index 0000000..5959041 --- /dev/null +++ b/src/routes/gameplay/raise.ts @@ -0,0 +1,93 @@ +import { getClient } from '../../utils/databaseConnection' +import { celebrate, Joi, Segments } from 'celebrate' +import { + sendFirebaseMessageToEveryone, + verifyFCMToken, +} from '../../utils/firebase' +import express, { type Router } from 'express' +import { rateLimiter } from '../../utils/rateLimiter' +import { + isPlayerInGame, + isPlayersTurn, + setPlayerState, + setNewCurrentPlayer, + changeGameRoundIfNeeded, + playerHasEnoughMoney, + isRaising, + playerRaised, +} from '../../utils/commonRequest' +import sha256 from 'crypto-js/sha256' +import { PlayerState } from '../../utils/types' + +const router: Router = express.Router() + +router.get( + '/actionRaise', + rateLimiter, + celebrate({ + [Segments.QUERY]: Joi.object().keys({ + playerToken: Joi.string().required().min(1).max(250).label('playerToken'), + gameId: Joi.number().required().min(0).max(999999).label('gameId'), + amount: Joi.number().required().min(1).label('amount'), + }), + }), + async (req, res) => { + const playerToken = req.query.playerToken as string + const gameId = req.query.gameId as string + const amount = req.query.amount as string + if (!(await verifyFCMToken(playerToken))) { + return res.sendStatus(401) + } + + const client = getClient() + + client + .connect() + .then(async () => { + if (!(await isPlayerInGame(playerToken, gameId, client))) { + return res.sendStatus(400) + } + + if (!(await isPlayersTurn(playerToken, gameId, client))) { + return res.sendStatus(402) + } + + if ( + !(await playerHasEnoughMoney(gameId, playerToken, amount, client)) + ) { + return res.sendStatus(403) + } + + if (!(await isRaising(gameId, amount, client))) { + return res.sendStatus(404) + } + + const newPlayer = await setNewCurrentPlayer(playerToken, gameId, client) + await setPlayerState(playerToken, client, PlayerState.Raised) + await playerRaised(gameId, playerToken, amount, client) + await changeGameRoundIfNeeded(gameId, newPlayer, client) + + const message = { + data: { + player: sha256(playerToken).toString(), + type: PlayerState.Raised, + actionPayload: amount, + }, + token: '', + } + + await sendFirebaseMessageToEveryone(message, gameId, client) + + res.sendStatus(200) + }) + .catch((err) => { + console.log(err.stack) + return res.sendStatus(500) + }) + .finally(async () => { + await client.end() + }) + } +) + +export default router diff --git a/src/tests/actionRaise.test.ts b/src/tests/actionRaise.test.ts new file mode 100644 index 0000000..0e577cd --- /dev/null +++ b/src/tests/actionRaise.test.ts @@ -0,0 +1,94 @@ +import { app } from '../app' +import request from 'supertest' +import { getClient } from '../utils/databaseConnection' +import type { NewGameInfo } from '../utils/types' +import { getGameIdAndStatus, getPlayersInGame } from '../utils/commonRequest' + +test('Raise, wrong args', (done) => { + const wrongToken = 'TESTRAISE_INCORRECT' + const wrongGameId = 'WRONG_ID' + request(app) + .get(`/actionRaise?playerToken=${wrongToken}`) + .expect(400) + .end(done) + + request(app) + .get(`/actionRaise?playerToken=${wrongToken}&gameId=${wrongGameId}`) + .expect(400) + .end(done) +}) + +test('Raise, correct arguments 1', async () => { + const gameMasterToken = 'RAISETEST' + const gameMasterNick = 'RAISENICK' + const playerToken = 'RAISETEST2' + const playerNick = 'RAISENICK2' + const player2Token = 'RAISETEST3' + const player2Nick = 'RAISENICK3' + + const client = getClient() + await client.connect() + const res = await request(app) + .get( + `/createGame?creatorToken=${gameMasterToken}&nickname=${gameMasterNick}` + ) + .expect(200) + + const key = (res.body as NewGameInfo).gameId + await request(app) + .get( + `/joinGame?playerToken=${playerToken}&nickname=${playerNick}&gameId=${key}` + ) + .expect(200) + + await request(app) + .get( + `/joinGame?playerToken=${player2Token}&nickname=${player2Nick}&gameId=${key}` + ) + .expect(200) + + await request(app) + .get(`/startGame?creatorToken=${gameMasterToken}`) + .expect(200) + + const gameId = + (await getGameIdAndStatus(gameMasterToken, client)).gameId ?? '' + const players = await getPlayersInGame(gameId, client) + console.log(players) + + await request(app) + .get( + `/actionRaise?playerToken=${players[1].token}&gameId=${gameId}&amount=5` + ) + .expect(402) + + await request(app) + .get( + `/actionRaise?playerToken=${players[0].token}&gameId=${gameId}&amount=5` + ) + .expect(200) + await request(app) + .get(`/fold?playerToken=${players[1].token}&gameId=${gameId}`) + .expect(200) + const getRound = 'SELECT game_round FROM Games WHERE game_id=$1' + + expect( + await ( + await client.query(getRound, [gameId]) + ).rows[0].game_round + ).toEqual('1') // Player 2 can still act + + await request(app) + .get( + `/actionRaise?playerToken=${players[2].token}&gameId=${gameId}&amount=2` + ) + .expect(404) + + await request(app) + .get( + `/actionRaise?playerToken=${players[2].token}&gameId=${gameId}&amount=20` + ) + .expect(200) + + await client.end() +}, 20000) diff --git a/src/utils/commonRequest.ts b/src/utils/commonRequest.ts index 60eb189..ab72d8b 100644 --- a/src/utils/commonRequest.ts +++ b/src/utils/commonRequest.ts @@ -180,3 +180,41 @@ export async function getSmallBlindValue( const query = 'SELECT small_blind FROM Games WHERE game_id=$1' return (await client.query(query, [gameId])).rows[0].small_blind } + +export async function playerHasEnoughMoney( + gameId: string, + playerToken: string, + amount: string, + client: Client +): Promise { + const query = 'SELECT 1 FROM Players WHERE token=$1 AND funds>=$2' + return (await client.query(query, [playerToken, amount])).rowCount !== 0 +} + +export async function isRaising( + gameId: string, + amount: string, + client: Client +) { + const getMaxBet = 'SELECT MAX(bet) as max FROM Players WHERE game_id=$1' + return (await (await client.query(getMaxBet, [gameId])).rows[0].max) < amount +} + +export async function playerRaised( + gameId: string, + playerToken: string, + amount: string, + client: Client +) { + const playerSize = (await getPlayersInGame(gameId, client)).length + const smallBlind = await getSmallBlind(gameId, playerSize, client) + let setNewBet = 'UPDATE Players SET funds=funds-$1, bet=$1 WHERE token=$2' + if (smallBlind === playerToken) { + setNewBet = 'UPDATE Players SET funds=funds-($1-bet), bet=$1 WHERE token=$2' + } + const putMoneyToTable = + 'UPDATE Games SET current_table_value=current_table_value+$1 WHERE game_id=$2' + + await client.query(setNewBet, [amount, playerToken]) + await client.query(putMoneyToTable, [amount, gameId]) +} diff --git a/src/utils/types.ts b/src/utils/types.ts index b79d190..8408a9b 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -39,4 +39,5 @@ export enum PlayerState { Raised = 'raise', Checked = 'check', Called = 'call', + NoAction = '', } From 3cada4d817cf7285bf3c7f7108259c68a9005c06 Mon Sep 17 00:00:00 2001 From: sormys Date: Sun, 21 May 2023 19:10:32 +0200 Subject: [PATCH 04/19] Fixed tests --- src/routes/gameplay/check.ts | 2 +- src/tests/check.test.ts | 40 +++++++++++++++--------------------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/routes/gameplay/check.ts b/src/routes/gameplay/check.ts index 400b9d2..17681d4 100644 --- a/src/routes/gameplay/check.ts +++ b/src/routes/gameplay/check.ts @@ -68,7 +68,7 @@ router.get( await sendFirebaseMessageToEveryone(message, gameId, client) - res.sendStatus(200) + return res.sendStatus(200) }) .catch((err) => { console.log(err.stack) diff --git a/src/tests/check.test.ts b/src/tests/check.test.ts index 138449c..0b3bd0a 100644 --- a/src/tests/check.test.ts +++ b/src/tests/check.test.ts @@ -13,9 +13,9 @@ test('Check, wrong args', async () => { const player2Nick = 'CHECK_INC_P2_NICK' const wrongToken = 'TESTCHECK_INCORRECT' const wrongGameId = 'WRONG_ID' - request(app).get(`/check?playerToken=${wrongToken}`).expect(400) + await request(app).get(`/check?playerToken=${wrongToken}`).expect(400) - request(app) + await request(app) .get(`/check?playerToken=${wrongToken}&gameId=${wrongGameId}`) .expect(400) @@ -46,18 +46,14 @@ test('Check, wrong args', async () => { .expect(200) const gameId = key.toString() - getPlayersInGame(gameId, client) - .then(async (players) => { - await request(app) - .get(`/check?playerToken=${players[1].token}&gameId=${gameId}`) - .expect(402) - await request(app) - .get(`/check?playerToken=${players[0].token}&gameId=${gameId}`) - .expect(403) - }) - .finally(async () => { - await client.end() - }) + const players = await getPlayersInGame(gameId, client) + await request(app) + .get(`/check?playerToken=${players[1].token}&gameId=${gameId}`) + .expect(402) + // await request(app) + // .get(`/check?playerToken=${players[0].token}&gameId=${gameId}`) + // .expect(403) + await client.end() }, 20000) test('Check, correct args', async () => { @@ -94,14 +90,10 @@ test('Check, correct args', async () => { .expect(200) const gameId = key.toString() - getPlayersInGame(gameId, client) - .then(async (players) => { - await client.query('UPDATE Players SET bet=0 WHERE game_id=$1', [gameId]) - await request(app) - .get(`/check?playerToken=${players[0].token}&gameId=${gameId}`) - .expect(200) - }) - .finally(async () => { - await client.end() - }) + const players = await getPlayersInGame(gameId, client) + await client.query('UPDATE Players SET bet=0 WHERE game_id=$1', [gameId]) + await request(app) + .get(`/check?playerToken=${players[0].token}&gameId=${gameId}`) + .expect(200) + await client.end() }, 20000) From b9e28a348f2620f71988573db4ac09c89529f51e Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 19:38:34 +0200 Subject: [PATCH 05/19] Kinda working raise --- src/routes/gameplay/fold.ts | 17 +++++++++++-- src/routes/gameplay/raise.ts | 1 + src/tests/actionRaise.test.ts | 10 ++++++++ src/utils/commonRequest.ts | 47 +++++++++++++++++++++-------------- src/utils/types.ts | 1 + 5 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/routes/gameplay/fold.ts b/src/routes/gameplay/fold.ts index 6239d38..b8a2553 100644 --- a/src/routes/gameplay/fold.ts +++ b/src/routes/gameplay/fold.ts @@ -47,9 +47,22 @@ router.get( if (!(await isPlayersTurn(playerToken, gameId, client))) { return res.sendStatus(402) } - - const newPlayer = await setNewCurrentPlayer(playerToken, gameId, client) await setPlayerState(playerToken, client, PlayerState.Folded) + const newPlayer = await setNewCurrentPlayer(playerToken, gameId, client) + if (newPlayer === '') { + const message = { + data: { + player: sha256(newPlayer).toString(), + type: PlayerState.Won, + actionPayload: '', + }, + token: '', + } + + await sendFirebaseMessageToEveryone(message, gameId, client) + return res.sendStatus(201) + } + await changeGameRoundIfNeeded(gameId, newPlayer, client) const message = { diff --git a/src/routes/gameplay/raise.ts b/src/routes/gameplay/raise.ts index 5959041..500188e 100644 --- a/src/routes/gameplay/raise.ts +++ b/src/routes/gameplay/raise.ts @@ -63,6 +63,7 @@ router.get( } const newPlayer = await setNewCurrentPlayer(playerToken, gameId, client) + await setPlayerState(playerToken, client, PlayerState.Raised) await playerRaised(gameId, playerToken, amount, client) await changeGameRoundIfNeeded(gameId, newPlayer, client) diff --git a/src/tests/actionRaise.test.ts b/src/tests/actionRaise.test.ts index 0e577cd..8ae8395 100644 --- a/src/tests/actionRaise.test.ts +++ b/src/tests/actionRaise.test.ts @@ -84,11 +84,21 @@ test('Raise, correct arguments 1', async () => { ) .expect(404) + await request(app) + .get( + `/actionRaise?playerToken=${players[2].token}&gameId=${gameId}&amount=2000000000` + ) + .expect(403) + await request(app) .get( `/actionRaise?playerToken=${players[2].token}&gameId=${gameId}&amount=20` ) .expect(200) + await request(app) + .get(`/fold?playerToken=${players[0].token}&gameId=${gameId}`) + .expect(201) + await client.end() }, 20000) diff --git a/src/utils/commonRequest.ts b/src/utils/commonRequest.ts index ab72d8b..6ebc637 100644 --- a/src/utils/commonRequest.ts +++ b/src/utils/commonRequest.ts @@ -70,28 +70,37 @@ export async function setNewCurrentPlayer( client: Client ) { const getOldPlayerTurn = 'SELECT turn FROM Players WHERE token=$1' - const getPlayerCount = - 'SELECT COUNT(*) as player_count FROM Players WHERE game_id=$1' - const getNewCurrentPlayer = - 'SELECT token FROM Players WHERE game_id=$1 AND turn=$2' + + const getPlayersAndTurn = + 'SELECT token, turn, last_action FROM Players WHERE game_id=$1 AND (last_action IS NULL OR last_action<>$2) ORDER BY turn ASC' const setNewCurrentPlayer = 'UPDATE Games SET current_player=$1 WHERE game_id=$2' - const playerCount = await ( - await client.query(getPlayerCount, [gameId]) - ).rows[0].player_count - const newTurn = - (((await ( - await client.query(getOldPlayerTurn, [oldPlayerToken]) - ).rows[0].turn) as number) + - 1) % - playerCount - const newPlayer = await ( - await client.query(getNewCurrentPlayer, [gameId, newTurn]) - ).rows[0].token - await client.query(setNewCurrentPlayer, [newPlayer, gameId]) - - return newPlayer + const oldTurn = await ( + await client.query(getOldPlayerTurn, [oldPlayerToken]) + ).rows[0].turn + const playersTurns = await client.query(getPlayersAndTurn, [ + gameId, + PlayerState.Folded, + ]) + if (playersTurns.rowCount <= 1) { + return '' + } else { + for (let i = 0; i < playersTurns.rowCount; i++) { + if (playersTurns.rows[i].turn > oldTurn) { + await client.query(setNewCurrentPlayer, [ + playersTurns.rows[i].token, + gameId, + ]) + return playersTurns.rows[i].token + } + } + await client.query(setNewCurrentPlayer, [ + playersTurns.rows[0].token, + gameId, + ]) + return playersTurns.rows[0].token + } } export async function changeGameRoundIfNeeded( diff --git a/src/utils/types.ts b/src/utils/types.ts index 8408a9b..aa450e3 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -40,4 +40,5 @@ export enum PlayerState { Checked = 'check', Called = 'call', NoAction = '', + Won = 'won', } From 51624c35b8a6fc6d46b383ed8a77fb7977bfd297 Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 20:53:53 +0200 Subject: [PATCH 06/19] Apply sugestion, kinda fix tests --- package.json | 2 +- src/app.ts | 4 ++-- src/routes/gameplay/fold.ts | 3 +-- src/routes/gameplay/raise.ts | 1 - src/routes/startGame.ts | 2 +- src/tests/actionRaise.test.ts | 4 ++-- src/tests/fold.test.ts | 20 +++++++++++--------- src/utils/commonRequest.ts | 3 +++ 8 files changed, 21 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index b64b12c..57aaf3a 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "scripts": { "start": "tsc && node dist/index.js", "build": "tsc", - "test": "jest src/tests --coverage --config package.json ", + "test": "jest src/tests/ --coverage --config package.json --runInBand", "lint": "eslint --ext '.js,.ts,.tsx' src/", "pretty": "yarn prettier --write .", "pretty-check": "yarn prettier --check src/", diff --git a/src/app.ts b/src/app.ts index 315d715..594ffad 100644 --- a/src/app.ts +++ b/src/app.ts @@ -7,7 +7,7 @@ import createGame from './routes/createGame' import modifyGame from './routes/modifyGame' import leaveGame from './routes/leaveGame' import startGame from './routes/startGame' -import fold from './routes/gameplay/fold' +import actionFold from './routes/gameplay/fold' import actionRaise from './routes/gameplay/raise' import { rateLimiter } from './utils/rateLimiter' @@ -41,7 +41,7 @@ app.use(leaveGame) app.use(startGame) -app.use(fold) +app.use(actionFold) app.use(actionRaise) diff --git a/src/routes/gameplay/fold.ts b/src/routes/gameplay/fold.ts index b8a2553..9be604e 100644 --- a/src/routes/gameplay/fold.ts +++ b/src/routes/gameplay/fold.ts @@ -19,7 +19,7 @@ import { PlayerState } from '../../utils/types' const router: Router = express.Router() router.get( - '/fold', + '/actionFold', rateLimiter, celebrate({ [Segments.QUERY]: Joi.object().keys({ @@ -75,7 +75,6 @@ router.get( } await sendFirebaseMessageToEveryone(message, gameId, client) - res.sendStatus(200) }) .catch((err) => { diff --git a/src/routes/gameplay/raise.ts b/src/routes/gameplay/raise.ts index 500188e..195ce47 100644 --- a/src/routes/gameplay/raise.ts +++ b/src/routes/gameplay/raise.ts @@ -78,7 +78,6 @@ router.get( } await sendFirebaseMessageToEveryone(message, gameId, client) - res.sendStatus(200) }) .catch((err) => { diff --git a/src/routes/startGame.ts b/src/routes/startGame.ts index 10bb354..763fc95 100644 --- a/src/routes/startGame.ts +++ b/src/routes/startGame.ts @@ -206,7 +206,7 @@ async function notifyPlayers( const message = { data: { type: 'startGame', - startedGameInfo: JSON.stringify(gameInfo), + startedGameInfo: JSON.stringify(gameInfo.players), card1: '', card2: '', }, diff --git a/src/tests/actionRaise.test.ts b/src/tests/actionRaise.test.ts index 8ae8395..548dc46 100644 --- a/src/tests/actionRaise.test.ts +++ b/src/tests/actionRaise.test.ts @@ -68,7 +68,7 @@ test('Raise, correct arguments 1', async () => { ) .expect(200) await request(app) - .get(`/fold?playerToken=${players[1].token}&gameId=${gameId}`) + .get(`/actionFold?playerToken=${players[1].token}&gameId=${gameId}`) .expect(200) const getRound = 'SELECT game_round FROM Games WHERE game_id=$1' @@ -97,7 +97,7 @@ test('Raise, correct arguments 1', async () => { .expect(200) await request(app) - .get(`/fold?playerToken=${players[0].token}&gameId=${gameId}`) + .get(`/actionFold?playerToken=${players[0].token}&gameId=${gameId}`) .expect(201) await client.end() diff --git a/src/tests/fold.test.ts b/src/tests/fold.test.ts index 3b1167e..10722f8 100644 --- a/src/tests/fold.test.ts +++ b/src/tests/fold.test.ts @@ -7,10 +7,13 @@ import { getGameIdAndStatus, getPlayersInGame } from '../utils/commonRequest' test('Fold, wrong args', (done) => { const wrongToken = 'TESTLEAVE_INCORRECT' const wrongGameId = 'WRONG_ID' - request(app).get(`/fold?playerToken=${wrongToken}`).expect(400).end(done) + request(app) + .get(`/actionFold?playerToken=${wrongToken}`) + .expect(400) + .end(done) request(app) - .get(`/fold?playerToken=${wrongToken}&gameId=${wrongGameId}`) + .get(`/actionFold?playerToken=${wrongToken}&gameId=${wrongGameId}`) .expect(400) .end(done) }) @@ -51,24 +54,23 @@ test('Fold, correct arguments, wrong turn', async () => { const gameId = (await getGameIdAndStatus(gameMasterToken, client)).gameId ?? '' const players = await getPlayersInGame(gameId, client) - + console.log(players) await request(app) - .get(`/fold?playerToken=${players[1].token}&gameId=${gameId}`) + .get(`/actionFold?playerToken=${players[1].token}&gameId=${gameId}`) .expect(402) - await request(app) - .get(`/fold?playerToken=${players[0].token}&gameId=${gameId}`) + .get(`/actionFold?playerToken=${players[0].token}&gameId=${gameId}`) .expect(200) await request(app) - .get(`/fold?playerToken=${players[1].token}&gameId=${gameId}`) - .expect(200) + .get(`/actionFold?playerToken=${players[1].token}&gameId=${gameId}`) + .expect(201) const getRound = 'SELECT game_round FROM Games WHERE game_id=$1' expect( await ( await client.query(getRound, [gameId]) ).rows[0].game_round - ).toEqual('2') + ).toEqual('1') // because last guy has won - no new rounds then. await client.end() }, 20000) diff --git a/src/utils/commonRequest.ts b/src/utils/commonRequest.ts index 6ebc637..00643b9 100644 --- a/src/utils/commonRequest.ts +++ b/src/utils/commonRequest.ts @@ -83,6 +83,7 @@ export async function setNewCurrentPlayer( gameId, PlayerState.Folded, ]) + console.log(playersTurns.rows) if (playersTurns.rowCount <= 1) { return '' } else { @@ -92,9 +93,11 @@ export async function setNewCurrentPlayer( playersTurns.rows[i].token, gameId, ]) + console.log('SHOULD GO NOW: ', playersTurns.rows[i].token) return playersTurns.rows[i].token } } + await client.query(setNewCurrentPlayer, [ playersTurns.rows[0].token, gameId, From 0c8776243193c1127f75928665f12362239d823d Mon Sep 17 00:00:00 2001 From: sormys Date: Sun, 21 May 2023 21:14:42 +0200 Subject: [PATCH 07/19] Minor changes --- src/routes/gameplay/check.ts | 2 +- src/tests/check.test.ts | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/routes/gameplay/check.ts b/src/routes/gameplay/check.ts index 17681d4..628f459 100644 --- a/src/routes/gameplay/check.ts +++ b/src/routes/gameplay/check.ts @@ -20,7 +20,7 @@ import { PlayerState } from '../../utils/types' const router: Router = express.Router() router.get( - '/check', + '/actionCheck', rateLimiter, celebrate({ [Segments.QUERY]: Joi.object().keys({ diff --git a/src/tests/check.test.ts b/src/tests/check.test.ts index 0b3bd0a..b193db3 100644 --- a/src/tests/check.test.ts +++ b/src/tests/check.test.ts @@ -13,10 +13,10 @@ test('Check, wrong args', async () => { const player2Nick = 'CHECK_INC_P2_NICK' const wrongToken = 'TESTCHECK_INCORRECT' const wrongGameId = 'WRONG_ID' - await request(app).get(`/check?playerToken=${wrongToken}`).expect(400) + await request(app).get(`/actionCheck?playerToken=${wrongToken}`).expect(400) await request(app) - .get(`/check?playerToken=${wrongToken}&gameId=${wrongGameId}`) + .get(`/actionCheck?playerToken=${wrongToken}&gameId=${wrongGameId}`) .expect(400) const client = getClient() @@ -48,11 +48,11 @@ test('Check, wrong args', async () => { const gameId = key.toString() const players = await getPlayersInGame(gameId, client) await request(app) - .get(`/check?playerToken=${players[1].token}&gameId=${gameId}`) + .get(`/actionCheck?playerToken=${players[1].token}&gameId=${gameId}`) .expect(402) - // await request(app) - // .get(`/check?playerToken=${players[0].token}&gameId=${gameId}`) - // .expect(403) + await request(app) + .get(`/actionCheck?playerToken=${players[0].token}&gameId=${gameId}`) + .expect(403) await client.end() }, 20000) @@ -93,7 +93,7 @@ test('Check, correct args', async () => { const players = await getPlayersInGame(gameId, client) await client.query('UPDATE Players SET bet=0 WHERE game_id=$1', [gameId]) await request(app) - .get(`/check?playerToken=${players[0].token}&gameId=${gameId}`) + .get(`/actionCheck?playerToken=${players[0].token}&gameId=${gameId}`) .expect(200) await client.end() }, 20000) From 9bf96c30a177072f50f4f8ac43140a201466bb4d Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 21:48:27 +0200 Subject: [PATCH 08/19] Remove wron line --- src/app.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app.ts b/src/app.ts index 957dd44..2d66214 100644 --- a/src/app.ts +++ b/src/app.ts @@ -48,6 +48,4 @@ app.use(actionRaise) app.use(actionCheck) -app.use(check) - app.use(errorHandling) From 3f4b160174d4d68ef86dea1a98644624f38524ac Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 21:50:25 +0200 Subject: [PATCH 09/19] remove logs --- src/tests/actionRaise.test.ts | 1 - src/tests/fold.test.ts | 1 - src/utils/commonRequest.ts | 2 -- 3 files changed, 4 deletions(-) diff --git a/src/tests/actionRaise.test.ts b/src/tests/actionRaise.test.ts index c98e7e0..240bf61 100644 --- a/src/tests/actionRaise.test.ts +++ b/src/tests/actionRaise.test.ts @@ -54,7 +54,6 @@ test('Raise, correct arguments 1', async () => { const gameId = (await getGameIdAndStatus(gameMasterToken, client)).gameId ?? '' const players = await getPlayersInGame(gameId, client) - console.log(players) await request(app) .get( diff --git a/src/tests/fold.test.ts b/src/tests/fold.test.ts index 4661557..a94b0fc 100644 --- a/src/tests/fold.test.ts +++ b/src/tests/fold.test.ts @@ -53,7 +53,6 @@ test('Fold, correct arguments, wrong turn', async () => { const gameId = key.toString() const players = await getPlayersInGame(gameId, client) - console.log(players) await request(app) .get(`/actionFold?playerToken=${players[1].token}&gameId=${gameId}`) .expect(402) diff --git a/src/utils/commonRequest.ts b/src/utils/commonRequest.ts index 00643b9..66501f8 100644 --- a/src/utils/commonRequest.ts +++ b/src/utils/commonRequest.ts @@ -83,7 +83,6 @@ export async function setNewCurrentPlayer( gameId, PlayerState.Folded, ]) - console.log(playersTurns.rows) if (playersTurns.rowCount <= 1) { return '' } else { @@ -93,7 +92,6 @@ export async function setNewCurrentPlayer( playersTurns.rows[i].token, gameId, ]) - console.log('SHOULD GO NOW: ', playersTurns.rows[i].token) return playersTurns.rows[i].token } } From 48e6518c36e2accf83d31e6d9a022a426fe28da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Karol=20W=C4=85sowski?= Date: Sun, 21 May 2023 21:51:26 +0200 Subject: [PATCH 10/19] Fixes to compatibility with Android app --- src/routes/gameplay/raise.ts | 2 +- src/routes/startGame.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/gameplay/raise.ts b/src/routes/gameplay/raise.ts index 195ce47..9a5f595 100644 --- a/src/routes/gameplay/raise.ts +++ b/src/routes/gameplay/raise.ts @@ -72,7 +72,7 @@ router.get( data: { player: sha256(playerToken).toString(), type: PlayerState.Raised, - actionPayload: amount, + actionPayload: amount.toString(), }, token: '', } diff --git a/src/routes/startGame.ts b/src/routes/startGame.ts index baa2040..765941d 100644 --- a/src/routes/startGame.ts +++ b/src/routes/startGame.ts @@ -216,7 +216,7 @@ async function notifyPlayers( const message = { data: { type: 'startGame', - startedGameInfo: JSON.stringify(gameInfo.players), + players: JSON.stringify(gameInfo.players), card1: '', card2: '', }, From f2a0e3bf57b98b67f2d54ff2e4ebef09697ad42c Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 22:03:04 +0200 Subject: [PATCH 11/19] Add blinds to table in smart game --- src/routes/startGame.ts | 12 ++++++++++-- src/tests/teardown.ts | 4 ++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/routes/startGame.ts b/src/routes/startGame.ts index baa2040..35307df 100644 --- a/src/routes/startGame.ts +++ b/src/routes/startGame.ts @@ -177,17 +177,25 @@ async function updateGameState( smallBlind: string, playerSize: number ) { + const smallBlindValue = await getSmallBlindValue(gameId, client) const query = `UPDATE Games SET current_player=$1, small_blind_who=$2, game_round=$3, current_table_value=$4, card1=$5, card2=$6, card3=$7, card4=$8, card5=$9 WHERE game_id=$10` - const values = [firstPlayerToken, smallBlind, 1, 0, ...gameInfo.cards, gameId] + const values = [ + firstPlayerToken, + smallBlind, + 1, + +smallBlindValue * 3, + ...gameInfo.cards, + gameId, + ] await client.query(query, values) await prepareBlinds( client, smallBlind, await getBigBlind(gameId, playerSize, client), - await getSmallBlindValue(gameId, client) + smallBlindValue ) } diff --git a/src/tests/teardown.ts b/src/tests/teardown.ts index a911b0b..e48c1dc 100644 --- a/src/tests/teardown.ts +++ b/src/tests/teardown.ts @@ -5,8 +5,8 @@ export default async function teardown() { client .connect() .then(async () => { - await client.query('DROP TABLE games cascade') - await client.query('DROP TABLE players cascade') + // await client.query('DROP TABLE games cascade') + // await client.query('DROP TABLE players cascade') }) .catch((err) => { console.log('Teardown failed') From 4ed0be0f9972c0c88d2db9de64d5adb45b894402 Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 22:30:03 +0200 Subject: [PATCH 12/19] Add blind rasing logic --- src/tests/teardown.ts | 4 ++-- src/utils/commonRequest.ts | 26 +++++++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/tests/teardown.ts b/src/tests/teardown.ts index e48c1dc..a911b0b 100644 --- a/src/tests/teardown.ts +++ b/src/tests/teardown.ts @@ -5,8 +5,8 @@ export default async function teardown() { client .connect() .then(async () => { - // await client.query('DROP TABLE games cascade') - // await client.query('DROP TABLE players cascade') + await client.query('DROP TABLE games cascade') + await client.query('DROP TABLE players cascade') }) .catch((err) => { console.log('Teardown failed') diff --git a/src/utils/commonRequest.ts b/src/utils/commonRequest.ts index 66501f8..5895c53 100644 --- a/src/utils/commonRequest.ts +++ b/src/utils/commonRequest.ts @@ -59,9 +59,12 @@ export async function setPlayerState( await client.query(query, [state, playerToken]) } -export async function getPlayerState(playerToken: string, client: Client) { - const query = 'SELECT last_action FROM Players WHERE player_token=$1' - await client.query(query, [playerToken]) +export async function getPlayerState( + playerToken: string, + client: Client +): Promise { + const query = 'SELECT last_action FROM Players WHERE token=$1' + return (await client.query(query, [playerToken])).rows[0].last_action } export async function setNewCurrentPlayer( @@ -216,15 +219,24 @@ export async function playerRaised( amount: string, client: Client ) { + const smallBlindValue = await getSmallBlindValue(gameId, client) const playerSize = (await getPlayersInGame(gameId, client)).length const smallBlind = await getSmallBlind(gameId, playerSize, client) - let setNewBet = 'UPDATE Players SET funds=funds-$1, bet=$1 WHERE token=$2' - if (smallBlind === playerToken) { - setNewBet = 'UPDATE Players SET funds=funds-($1-bet), bet=$1 WHERE token=$2' + const smallBlindState = await getPlayerState(smallBlind, client) + const bigBlind = await getBigBlind(gameId, playerSize, client) + const bigBlindState = await getPlayerState(bigBlind, client) + let bet = amount + const setNewMoney = 'UPDATE Players SET funds=funds-$1, bet=$2 WHERE token=$3' + if (smallBlind === playerToken && smallBlindState == null) { + bet = (+amount + +smallBlindValue).toString() + amount = (+amount - +smallBlindValue).toString() + } else if (bigBlind === playerToken && bigBlindState == null) { + bet = (+amount + +smallBlindValue * 2).toString() + amount = (+amount - +smallBlindValue * 2).toString() } const putMoneyToTable = 'UPDATE Games SET current_table_value=current_table_value+$1 WHERE game_id=$2' - await client.query(setNewBet, [amount, playerToken]) + await client.query(setNewMoney, [amount, bet, playerToken]) await client.query(putMoneyToTable, [amount, gameId]) } From f2410428239e01b671e212b464b8437480629b5b Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 23:05:57 +0200 Subject: [PATCH 13/19] call, and modify logic for checkinfg if blidns have enough money --- src/app.ts | 3 ++ src/routes/gameplay/call.ts | 89 +++++++++++++++++++++++++++++++++++++ src/utils/commonRequest.ts | 21 +++++++++ 3 files changed, 113 insertions(+) create mode 100644 src/routes/gameplay/call.ts diff --git a/src/app.ts b/src/app.ts index 2d66214..2837bff 100644 --- a/src/app.ts +++ b/src/app.ts @@ -10,6 +10,7 @@ import startGame from './routes/startGame' import actionFold from './routes/gameplay/fold' import actionRaise from './routes/gameplay/raise' import actionCheck from './routes/gameplay/check' +import actionCall from './routes/gameplay/call' import { rateLimiter } from './utils/rateLimiter' export const app = express() @@ -48,4 +49,6 @@ app.use(actionRaise) app.use(actionCheck) +app.use(actionCall) + app.use(errorHandling) diff --git a/src/routes/gameplay/call.ts b/src/routes/gameplay/call.ts new file mode 100644 index 0000000..ec72381 --- /dev/null +++ b/src/routes/gameplay/call.ts @@ -0,0 +1,89 @@ +import { getClient } from '../../utils/databaseConnection' +import { celebrate, Joi, Segments } from 'celebrate' +import { + sendFirebaseMessageToEveryone, + verifyFCMToken, +} from '../../utils/firebase' +import express, { type Router } from 'express' +import { rateLimiter } from '../../utils/rateLimiter' +import { + isPlayerInGame, + isPlayersTurn, + setPlayerState, + setNewCurrentPlayer, + changeGameRoundIfNeeded, + playerHasEnoughMoney, + playerRaised, + getMaxBet, +} from '../../utils/commonRequest' +import sha256 from 'crypto-js/sha256' +import { PlayerState } from '../../utils/types' + +const router: Router = express.Router() + +router.get( + '/actionCall', + rateLimiter, + celebrate({ + [Segments.QUERY]: Joi.object().keys({ + playerToken: Joi.string().required().min(1).max(250).label('playerToken'), + gameId: Joi.number().required().min(0).max(999999).label('gameId'), + }), + }), + async (req, res) => { + const playerToken = req.query.playerToken as string + const gameId = req.query.gameId as string + if (!(await verifyFCMToken(playerToken))) { + return res.sendStatus(401) + } + + const client = getClient() + + client + .connect() + .then(async () => { + if (!(await isPlayerInGame(playerToken, gameId, client))) { + return res.sendStatus(400) + } + + if (!(await isPlayersTurn(playerToken, gameId, client))) { + return res.sendStatus(402) + } + + const maxBet = await getMaxBet(gameId, client) + + if ( + !(await playerHasEnoughMoney(gameId, playerToken, maxBet, client)) + ) { + return res.sendStatus(403) + } + + const newPlayer = await setNewCurrentPlayer(playerToken, gameId, client) + + await setPlayerState(playerToken, client, PlayerState.Called) + await playerRaised(gameId, playerToken, maxBet, client) + await changeGameRoundIfNeeded(gameId, newPlayer, client) + + const message = { + data: { + player: sha256(playerToken).toString(), + type: PlayerState.Called, + actionPayload: maxBet.toString(), + }, + token: '', + } + + await sendFirebaseMessageToEveryone(message, gameId, client) + res.sendStatus(200) + }) + .catch((err) => { + console.log(err.stack) + return res.sendStatus(500) + }) + .finally(async () => { + await client.end() + }) + } +) + +export default router diff --git a/src/utils/commonRequest.ts b/src/utils/commonRequest.ts index 5895c53..892fa16 100644 --- a/src/utils/commonRequest.ts +++ b/src/utils/commonRequest.ts @@ -200,6 +200,19 @@ export async function playerHasEnoughMoney( amount: string, client: Client ): Promise { + const smallBlindValue = await getSmallBlindValue(gameId, client) + const playerSize = (await getPlayersInGame(gameId, client)).length + const smallBlind = await getSmallBlind(gameId, playerSize, client) + const smallBlindState = await getPlayerState(smallBlind, client) + const bigBlind = await getBigBlind(gameId, playerSize, client) + const bigBlindState = await getPlayerState(bigBlind, client) + + if (playerToken === smallBlind && smallBlindState == null) { + amount = (+amount - +smallBlindValue).toString() + } else if (playerToken === bigBlind && bigBlindState == null) { + amount = (+amount - +smallBlindValue * 2).toString() + } + const query = 'SELECT 1 FROM Players WHERE token=$1 AND funds>=$2' return (await client.query(query, [playerToken, amount])).rowCount !== 0 } @@ -240,3 +253,11 @@ export async function playerRaised( await client.query(setNewMoney, [amount, bet, playerToken]) await client.query(putMoneyToTable, [amount, gameId]) } + +export async function getMaxBet( + gameId: string, + client: Client +): Promise { + const query = 'SELECT MAX(bet) as max FROM Games WHERE game_id=$1' + return (await client.query(query, [gameId])).rows[0].max +} From 776d3febd453d4f54c170830fa47ea82eb83d345 Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 23:26:31 +0200 Subject: [PATCH 14/19] some tests --- src/tests/call.test.ts | 97 ++++++++++++++++++++++++++++++++++++++ src/utils/commonRequest.ts | 2 +- 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 src/tests/call.test.ts diff --git a/src/tests/call.test.ts b/src/tests/call.test.ts new file mode 100644 index 0000000..73120b3 --- /dev/null +++ b/src/tests/call.test.ts @@ -0,0 +1,97 @@ +import { app } from '../app' +import request from 'supertest' +import { getClient } from '../utils/databaseConnection' +import type { NewGameInfo } from '../utils/types' +import { getGameIdAndStatus, getPlayersInGame } from '../utils/commonRequest' + +test('Call, correct arguments 1', async () => { + const gameMasterToken = 'CALLTEST' + const gameMasterNick = 'CALLNICK' + const playerToken = 'CALLTEST2' + const playerNick = 'CALLNICK2' + const player2Token = 'CALLTEST3' + const player2Nick = 'CALLNICK3' + + const client = getClient() + await client.connect() + const res = await request(app) + .get( + `/createGame?creatorToken=${gameMasterToken}&nickname=${gameMasterNick}` + ) + .expect(200) + + const key = (res.body as NewGameInfo).gameId + await request(app) + .get( + `/joinGame?playerToken=${playerToken}&nickname=${playerNick}&gameId=${key}` + ) + .expect(200) + + await request(app) + .get( + `/joinGame?playerToken=${player2Token}&nickname=${player2Nick}&gameId=${key}` + ) + .expect(200) + + await request(app) + .get(`/startGame?creatorToken=${gameMasterToken}`) + .expect(200) + + const gameId = + (await getGameIdAndStatus(gameMasterToken, client)).gameId ?? '' + const players = await getPlayersInGame(gameId, client) + + await request(app) + .get( + `/actionRaise?playerToken=${players[1].token}&gameId=${gameId}&amount=5` + ) + .expect(402) + + await request(app) + .get( + `/actionRaise?playerToken=${players[0].token}&gameId=${gameId}&amount=300` + ) + .expect(200) + await request(app) + .get(`/actionCall?playerToken=${players[1].token}&gameId=${gameId}`) + .expect(200) + const getRound = 'SELECT game_round FROM Games WHERE game_id=$1' + + expect( + await ( + await client.query(getRound, [gameId]) + ).rows[0].game_round + ).toEqual('1') // Player 2 can still act + + await request(app) + .get( + `/actionRaise?playerToken=${players[2].token}&gameId=${gameId}&amount=2` + ) + .expect(404) + + await request(app) + .get( + `/actionRaise?playerToken=${players[2].token}&gameId=${gameId}&amount=2000000000` + ) + .expect(403) + + await request(app) + .get( + `/actionRaise?playerToken=${players[2].token}&gameId=${gameId}&amount=400` + ) + .expect(200) + + await request(app) + .get(`/actionCall?playerToken=${players[0].token}&gameId=${gameId}`) + .expect(200) + + await request(app) + .get(`/actionFold?playerToken=${players[1].token}&gameId=${gameId}`) + .expect(200) + + await request(app) + .get(`/actionFold?playerToken=${players[2].token}&gameId=${gameId}`) + .expect(200) + + await client.end() +}, 20000) diff --git a/src/utils/commonRequest.ts b/src/utils/commonRequest.ts index 892fa16..98530eb 100644 --- a/src/utils/commonRequest.ts +++ b/src/utils/commonRequest.ts @@ -258,6 +258,6 @@ export async function getMaxBet( gameId: string, client: Client ): Promise { - const query = 'SELECT MAX(bet) as max FROM Games WHERE game_id=$1' + const query = 'SELECT MAX(bet) as max FROM Players WHERE game_id=$1' return (await client.query(query, [gameId])).rows[0].max } From aebbf60f908c11ad1e9bc802257eb63e597434ab Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 23:31:52 +0200 Subject: [PATCH 15/19] AA --- src/tests/call.test.ts | 3 ++- src/utils/commonRequest.ts | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tests/call.test.ts b/src/tests/call.test.ts index 73120b3..f0e26dd 100644 --- a/src/tests/call.test.ts +++ b/src/tests/call.test.ts @@ -40,6 +40,7 @@ test('Call, correct arguments 1', async () => { const gameId = (await getGameIdAndStatus(gameMasterToken, client)).gameId ?? '' const players = await getPlayersInGame(gameId, client) + console.log(players) await request(app) .get( @@ -90,7 +91,7 @@ test('Call, correct arguments 1', async () => { .expect(200) await request(app) - .get(`/actionFold?playerToken=${players[2].token}&gameId=${gameId}`) + .get(`/actionFold?playerToken=${players[0].token}&gameId=${gameId}`) .expect(200) await client.end() diff --git a/src/utils/commonRequest.ts b/src/utils/commonRequest.ts index 98530eb..1396dfd 100644 --- a/src/utils/commonRequest.ts +++ b/src/utils/commonRequest.ts @@ -95,6 +95,7 @@ export async function setNewCurrentPlayer( playersTurns.rows[i].token, gameId, ]) + console.log(playersTurns.rows[i].token) return playersTurns.rows[i].token } } @@ -103,6 +104,7 @@ export async function setNewCurrentPlayer( playersTurns.rows[0].token, gameId, ]) + console.log(playersTurns.rows[0].token) return playersTurns.rows[0].token } } From 18b1c53d2ea8e93d10b13b1db2fe46c83e51cf6d Mon Sep 17 00:00:00 2001 From: sormys Date: Sun, 21 May 2023 23:38:15 +0200 Subject: [PATCH 16/19] fixed fold --- src/routes/gameplay/fold.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/gameplay/fold.ts b/src/routes/gameplay/fold.ts index 9be604e..3fd0e44 100644 --- a/src/routes/gameplay/fold.ts +++ b/src/routes/gameplay/fold.ts @@ -52,7 +52,7 @@ router.get( if (newPlayer === '') { const message = { data: { - player: sha256(newPlayer).toString(), + player: sha256(playerToken).toString(), type: PlayerState.Won, actionPayload: '', }, From d353a413da12c5c01a99a81c4a54140f6d4afea1 Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 23:39:08 +0200 Subject: [PATCH 17/19] ADD Miising --- src/utils/commonRequest.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/utils/commonRequest.ts b/src/utils/commonRequest.ts index 8d967de..457ebce 100644 --- a/src/utils/commonRequest.ts +++ b/src/utils/commonRequest.ts @@ -245,3 +245,11 @@ export async function playerRaised( await client.query(setNewBet, [amount, playerToken]) await client.query(putMoneyToTable, [parseInt(amount) - oldBet, gameId]) } + +export async function getMaxBet( + gameId: string, + client: Client +): Promise { + const query = 'SELECT MAX(bet) as max FROM Players WHERE game_id=$1' + return (await client.query(query, [gameId])).rows[0].max +} From b2a6871f631f418c61873cabed23449781ca907d Mon Sep 17 00:00:00 2001 From: sormys Date: Sun, 21 May 2023 23:45:16 +0200 Subject: [PATCH 18/19] Fixing fold --- src/routes/gameplay/fold.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/routes/gameplay/fold.ts b/src/routes/gameplay/fold.ts index 3fd0e44..fd9a8d5 100644 --- a/src/routes/gameplay/fold.ts +++ b/src/routes/gameplay/fold.ts @@ -50,9 +50,10 @@ router.get( await setPlayerState(playerToken, client, PlayerState.Folded) const newPlayer = await setNewCurrentPlayer(playerToken, gameId, client) if (newPlayer === '') { + const winner = (await playersStillInGame(gameId, client))[0] const message = { data: { - player: sha256(playerToken).toString(), + player: sha256(winner).toString(), type: PlayerState.Won, actionPayload: '', }, @@ -88,3 +89,13 @@ router.get( ) export default router + +export async function playersStillInGame(gameId: string, client) { + const query = `SELECT token + FROM players + WHERE game_id = $1 AND last_action <> $2 AND last_action <> $3 + AND last_action IS NOT NULL + ` + const values = [gameId, PlayerState.Folded, PlayerState.NoAction] + return (await client.query(query, values)).rows[0] +} From ebd97dfcbfee8e81fc840e129b7b54c8ee689814 Mon Sep 17 00:00:00 2001 From: aetn23 Date: Sun, 21 May 2023 23:51:25 +0200 Subject: [PATCH 19/19] asdasd --- src/tests/call.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/call.test.ts b/src/tests/call.test.ts index f0e26dd..cc64b07 100644 --- a/src/tests/call.test.ts +++ b/src/tests/call.test.ts @@ -91,8 +91,8 @@ test('Call, correct arguments 1', async () => { .expect(200) await request(app) - .get(`/actionFold?playerToken=${players[0].token}&gameId=${gameId}`) - .expect(200) + .get(`/actionFold?playerToken=${players[2].token}&gameId=${gameId}`) + .expect(402) // round ended await client.end() }, 20000)