From 3fce4a76095b8d9d965526b43829b10dafe0a844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pir=C3=B3g?= <69601940+aetn23@users.noreply.github.com> Date: Sun, 21 May 2023 23:29:23 +0200 Subject: [PATCH 1/2] Gameplay: raise (#51) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: sormys Co-authored-by: Karol WÄ…sowski --- package.json | 2 +- src/app.ts | 11 ++-- src/routes/gameplay/fold.ts | 18 +++++- src/routes/gameplay/raise.ts | 93 ++++++++++++++++++++++++++++++ src/routes/startGame.ts | 14 ++++- src/tests/actionRaise.test.ts | 103 ++++++++++++++++++++++++++++++++++ src/tests/fold.test.ts | 19 ++++--- src/utils/commonRequest.ts | 85 +++++++++++++++++++++------- src/utils/types.ts | 2 + 9 files changed, 308 insertions(+), 39 deletions(-) create mode 100644 src/routes/gameplay/raise.ts create mode 100644 src/tests/actionRaise.test.ts 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 0b5da4d..2d66214 100644 --- a/src/app.ts +++ b/src/app.ts @@ -7,8 +7,9 @@ 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 check from './routes/gameplay/check' +import actionFold from './routes/gameplay/fold' +import actionRaise from './routes/gameplay/raise' +import actionCheck from './routes/gameplay/check' import { rateLimiter } from './utils/rateLimiter' export const app = express() @@ -41,8 +42,10 @@ app.use(leaveGame) app.use(startGame) -app.use(fold) +app.use(actionFold) -app.use(check) +app.use(actionRaise) + +app.use(actionCheck) app.use(errorHandling) diff --git a/src/routes/gameplay/fold.ts b/src/routes/gameplay/fold.ts index 3589ac6..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({ @@ -47,9 +47,22 @@ router.get( if (!(await isPlayersTurn(playerToken, gameId, client))) { return res.sendStatus(402) } - 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 = { @@ -62,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 new file mode 100644 index 0000000..8fe78c6 --- /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 playerRaised(gameId, playerToken, amount, client) + await setPlayerState(playerToken, client, PlayerState.Raised) + await changeGameRoundIfNeeded(gameId, newPlayer, client) + + const message = { + data: { + player: sha256(playerToken).toString(), + type: PlayerState.Raised, + actionPayload: amount.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/routes/startGame.ts b/src/routes/startGame.ts index 7a3b306..da8126a 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 ) } @@ -216,7 +224,7 @@ async function notifyPlayers( const message = { data: { type: 'startGame', - startedGameInfo: JSON.stringify(gameInfo), + players: JSON.stringify(gameInfo.players), card1: '', card2: '', }, diff --git a/src/tests/actionRaise.test.ts b/src/tests/actionRaise.test.ts new file mode 100644 index 0000000..e1cb267 --- /dev/null +++ b/src/tests/actionRaise.test.ts @@ -0,0 +1,103 @@ +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) + + 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(`/actionFold?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(`/actionFold?playerToken=${players[0].token}&gameId=${gameId}`) + .expect(201) + + await client.end() +}, 60000) diff --git a/src/tests/fold.test.ts b/src/tests/fold.test.ts index 361571c..a94b0fc 100644 --- a/src/tests/fold.test.ts +++ b/src/tests/fold.test.ts @@ -7,10 +7,13 @@ import { getPlayersInGame } from '../utils/commonRequest' test('Fold, wrong args', (done) => { const wrongToken = 'TESTFOLD_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) }) @@ -50,24 +53,22 @@ test('Fold, correct arguments, wrong turn', async () => { const gameId = key.toString() const players = await getPlayersInGame(gameId, client) - 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 60eb189..e0ef622 100644 --- a/src/utils/commonRequest.ts +++ b/src/utils/commonRequest.ts @@ -70,28 +70,38 @@ 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( @@ -180,3 +190,40 @@ 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+bet>=$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 getOldBet = 'SELECT bet FROM Players WHERE token=$1' + const setNewBet = + 'UPDATE Players SET funds=funds+bet-$1, bet=$1 WHERE token=$2' + const putMoneyToTable = + 'UPDATE Games SET current_table_value=current_table_value+$1 WHERE game_id=$2' + + const oldBet: number = (await client.query(getOldBet, [playerToken])).rows[0] + .bet + await client.query(setNewBet, [amount, playerToken]) + await client.query(putMoneyToTable, [parseInt(amount) - oldBet, gameId]) +} diff --git a/src/utils/types.ts b/src/utils/types.ts index b79d190..aa450e3 100644 --- a/src/utils/types.ts +++ b/src/utils/types.ts @@ -39,4 +39,6 @@ export enum PlayerState { Raised = 'raise', Checked = 'check', Called = 'call', + NoAction = '', + Won = 'won', } From 8afc38d05f8764cbdff7887c2ce4ca28cabf92a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pir=C3=B3g?= <69601940+aetn23@users.noreply.github.com> Date: Sun, 21 May 2023 23:56:04 +0200 Subject: [PATCH 2/2] @aetn23/call (#53) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: sormys Co-authored-by: Karol WÄ…sowski --- src/app.ts | 3 ++ src/routes/gameplay/call.ts | 89 +++++++++++++++++++++++++++++++++ src/routes/gameplay/fold.ts | 13 ++++- src/tests/call.test.ts | 98 +++++++++++++++++++++++++++++++++++++ src/utils/commonRequest.ts | 34 +++++++++++-- 5 files changed, 232 insertions(+), 5 deletions(-) create mode 100644 src/routes/gameplay/call.ts create mode 100644 src/tests/call.test.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/routes/gameplay/fold.ts b/src/routes/gameplay/fold.ts index 9be604e..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(newPlayer).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] +} diff --git a/src/tests/call.test.ts b/src/tests/call.test.ts new file mode 100644 index 0000000..cc64b07 --- /dev/null +++ b/src/tests/call.test.ts @@ -0,0 +1,98 @@ +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) + 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=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(402) // round ended + + await client.end() +}, 20000) diff --git a/src/utils/commonRequest.ts b/src/utils/commonRequest.ts index e0ef622..457ebce 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( @@ -92,6 +95,7 @@ export async function setNewCurrentPlayer( playersTurns.rows[i].token, gameId, ]) + console.log(playersTurns.rows[i].token) return playersTurns.rows[i].token } } @@ -100,6 +104,7 @@ export async function setNewCurrentPlayer( playersTurns.rows[0].token, gameId, ]) + console.log(playersTurns.rows[0].token) return playersTurns.rows[0].token } } @@ -197,7 +202,20 @@ export async function playerHasEnoughMoney( amount: string, client: Client ): Promise { - const query = 'SELECT 1 FROM Players WHERE token=$1 AND funds+bet>=$2' + 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 } @@ -227,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 +}