mirror of
https://github.com/cassoule/flopobot_v2.git
synced 2026-01-18 16:37:40 +01:00
poker is on the right way
This commit is contained in:
239
index.js
239
index.js
@@ -16,7 +16,7 @@ import {
|
||||
gork,
|
||||
getRandomHydrateText,
|
||||
getAPOUsers,
|
||||
postAPOBuy, initialShuffledCards
|
||||
postAPOBuy, initialShuffledCards, getFirstActivePlayerAfterDealer, getNextActivePlayer, isPreFlopDone
|
||||
} from './utils.js';
|
||||
import {channelPointsHandler, eloHandler, pokerTest, slowmodesHandler} from './game.js';
|
||||
import { Client, GatewayIntentBits, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle } from 'discord.js';
|
||||
@@ -50,6 +50,7 @@ import { v4 as uuidv4 } from 'uuid';
|
||||
import { uniqueNamesGenerator, adjectives, languages, animals } from 'unique-names-generator';
|
||||
import pkg from 'pokersolver';
|
||||
const { Hand } = pkg;
|
||||
import axios from 'axios';
|
||||
|
||||
// Create an express app
|
||||
const app = express();
|
||||
@@ -3474,12 +3475,15 @@ app.post('/create-poker-room', async (req, res) => {
|
||||
created_at: Date.now(),
|
||||
last_move_at: Date.now(),
|
||||
players: {},
|
||||
queue: {},
|
||||
pioche: initialShuffledCards(),
|
||||
tapis: [],
|
||||
dealer: null,
|
||||
sb: null,
|
||||
bb: null,
|
||||
highest_bet: null,
|
||||
current_player: null,
|
||||
current_turn: null,
|
||||
playing: false,
|
||||
fakeMoney: false,
|
||||
}
|
||||
@@ -3516,11 +3520,19 @@ app.post('/poker-room/join', async (req, res) => {
|
||||
bet: null,
|
||||
solve: null,
|
||||
folded: false,
|
||||
allin: false,
|
||||
last_played_turn: null,
|
||||
is_last_raiser: false,
|
||||
}
|
||||
|
||||
try {
|
||||
pokerRooms[roomId].players[userId] = player
|
||||
if (fakeMoney) pokerRooms[roomId].fakeMoney = true
|
||||
if (pokerRooms[roomId].playing) {
|
||||
pokerRooms[roomId].queue[userId] = player
|
||||
} else {
|
||||
pokerRooms[roomId].players[userId] = player
|
||||
if (fakeMoney) pokerRooms[roomId].fakeMoney = true
|
||||
}
|
||||
|
||||
pokerRooms[roomId].last_move_at = Date.now()
|
||||
} catch (e) {
|
||||
//
|
||||
@@ -3557,6 +3569,9 @@ app.post('/poker-room/leave', async (req, res) => {
|
||||
app.post('/poker-room/start', async (req, res) => {
|
||||
const { roomId } = req.body
|
||||
|
||||
if (!pokerRooms[roomId]) return res.status(404).send({ message: 'Table introuvable' })
|
||||
|
||||
// preflop
|
||||
try {
|
||||
for (const playerId in pokerRooms[roomId].players) {
|
||||
const player = pokerRooms[roomId].players[playerId]
|
||||
@@ -3567,12 +3582,6 @@ app.post('/poker-room/start', async (req, res) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (pokerRooms[roomId].pioche.length > 0) {
|
||||
pokerRooms[roomId].tapis.push(pokerRooms[roomId].pioche[0])
|
||||
pokerRooms[roomId].pioche.shift()
|
||||
}
|
||||
}
|
||||
for (const playerId in pokerRooms[roomId].players) {
|
||||
const player = pokerRooms[roomId].players[playerId]
|
||||
let fullHand = pokerRooms[roomId].tapis
|
||||
@@ -3586,8 +3595,12 @@ app.post('/poker-room/start', async (req, res) => {
|
||||
pokerRooms[roomId].sb = Object.keys(pokerRooms[roomId].players)[1]
|
||||
pokerRooms[roomId].bb = Object.keys(pokerRooms[roomId].players)[2 % Object.keys(pokerRooms[roomId].players).length]
|
||||
pokerRooms[roomId].players[Object.keys(pokerRooms[roomId].players)[1]].bet = 10 //SB
|
||||
pokerRooms[roomId].players[Object.keys(pokerRooms[roomId].players)[1]].bank -= 10 //SB
|
||||
pokerRooms[roomId].players[Object.keys(pokerRooms[roomId].players)[2 % Object.keys(pokerRooms[roomId].players).length]].bet = 20 //BB
|
||||
pokerRooms[roomId].players[Object.keys(pokerRooms[roomId].players)[2 % Object.keys(pokerRooms[roomId].players).length]].bank -= 20 //BB
|
||||
pokerRooms[roomId].highest_bet = 20
|
||||
pokerRooms[roomId].current_player = Object.keys(pokerRooms[roomId].players)[3 % Object.keys(pokerRooms[roomId].players).length]
|
||||
pokerRooms[roomId].current_turn = 0;
|
||||
|
||||
pokerRooms[roomId].playing = true
|
||||
pokerRooms[roomId].last_move_at = Date.now()
|
||||
@@ -3596,6 +3609,214 @@ app.post('/poker-room/start', async (req, res) => {
|
||||
return res.status(200)
|
||||
})
|
||||
|
||||
app.post('/poker-room/flop', async (req, res) => {
|
||||
const { roomId } = req.body
|
||||
|
||||
if (!pokerRooms[roomId]) return res.status(404).send({ message: 'Table introuvable' })
|
||||
|
||||
//flop
|
||||
try {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (pokerRooms[roomId].pioche.length > 0) {
|
||||
pokerRooms[roomId].tapis.push(pokerRooms[roomId].pioche[0])
|
||||
pokerRooms[roomId].pioche.shift()
|
||||
}
|
||||
}
|
||||
await updatePokerPlayersSolve(roomId)
|
||||
} catch(e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
pokerRooms[roomId].current_player = getFirstActivePlayerAfterDealer(pokerRooms[roomId])
|
||||
|
||||
io.emit('poker-room-flop')
|
||||
io.emit('new-poker-room')
|
||||
return res.status(200)
|
||||
});
|
||||
|
||||
app.post('/poker-room/turn', async (req, res) => {
|
||||
const { roomId } = req.body
|
||||
|
||||
if (!pokerRooms[roomId]) return res.status(404).send({ message: 'Table introuvable' })
|
||||
|
||||
//turn
|
||||
try {
|
||||
if (pokerRooms[roomId].pioche.length > 0) {
|
||||
pokerRooms[roomId].tapis.push(pokerRooms[roomId].pioche[0])
|
||||
pokerRooms[roomId].pioche.shift()
|
||||
}
|
||||
|
||||
await updatePokerPlayersSolve(roomId)
|
||||
} catch(e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
pokerRooms[roomId].current_player = getFirstActivePlayerAfterDealer(pokerRooms[roomId])
|
||||
|
||||
io.emit('poker-room-turn')
|
||||
io.emit('new-poker-room')
|
||||
return res.status(200)
|
||||
});
|
||||
|
||||
app.post('/poker-room/river', async (req, res) => {
|
||||
const { roomId } = req.body
|
||||
|
||||
if (!pokerRooms[roomId]) return res.status(404).send({ message: 'Table introuvable' })
|
||||
|
||||
//river
|
||||
try {
|
||||
if (pokerRooms[roomId].pioche.length > 0) {
|
||||
pokerRooms[roomId].tapis.push(pokerRooms[roomId].pioche[0])
|
||||
pokerRooms[roomId].pioche.shift()
|
||||
}
|
||||
|
||||
await updatePokerPlayersSolve(roomId)
|
||||
} catch(e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
pokerRooms[roomId].current_player = getFirstActivePlayerAfterDealer(pokerRooms[roomId])
|
||||
|
||||
io.emit('poker-room-river')
|
||||
io.emit('new-poker-room')
|
||||
return res.status(200)
|
||||
});
|
||||
|
||||
app.post('/poker-room/action/fold', async (req, res) => {
|
||||
const { roomId, playerId } = req.body
|
||||
|
||||
if (!pokerRooms[roomId]) return res.status(404).send({ message: 'Table introuvable' })
|
||||
if (!pokerRooms[roomId].players[playerId]) return res.status(404).send({ message: 'Joueur introuvable' })
|
||||
|
||||
if (pokerRooms[roomId].current_player !== playerId) return res.status(403).send({ message: 'Ce n\'est pas ton tour' });
|
||||
|
||||
try {
|
||||
pokerRooms[roomId].players[playerId].folded = true
|
||||
pokerRooms[roomId].players[playerId].last_played_turn = pokerRooms[roomId].current_turn
|
||||
|
||||
await checksAfterPokerAction(roomId)
|
||||
|
||||
io.emit('poker-room-player-action')
|
||||
io.emit('new-poker-room')
|
||||
} catch(e) {
|
||||
console.log(e)
|
||||
return res.status(500).send({ message: e})
|
||||
}
|
||||
|
||||
return res.status(200)
|
||||
});
|
||||
|
||||
app.post('/poker-room/action/check', async (req, res) => {
|
||||
const { roomId, playerId } = req.body
|
||||
|
||||
if (!pokerRooms[roomId]) return res.status(404).send({ message: 'Table introuvable' })
|
||||
if (!pokerRooms[roomId].players[playerId]) return res.status(404).send({ message: 'Joueur introuvable' })
|
||||
|
||||
if (pokerRooms[roomId].current_player !== playerId) return res.status(403).send({ message: 'Ce n\'est pas ton tour' });
|
||||
|
||||
try {
|
||||
pokerRooms[roomId].players[playerId].last_played_turn = pokerRooms[roomId].current_turn
|
||||
|
||||
await checksAfterPokerAction(roomId)
|
||||
|
||||
io.emit('poker-room-player-action')
|
||||
io.emit('new-poker-room')
|
||||
} catch(e) {
|
||||
console.log(e)
|
||||
return res.status(500).send({ message: e})
|
||||
}
|
||||
|
||||
return res.status(200)
|
||||
});
|
||||
|
||||
app.post('/poker-room/action/call', async (req, res) => {
|
||||
const { roomId, playerId } = req.body
|
||||
|
||||
if (!pokerRooms[roomId]) return res.status(404).send({ message: 'Table introuvable' })
|
||||
if (!pokerRooms[roomId].players[playerId]) return res.status(404).send({ message: 'Joueur introuvable' })
|
||||
|
||||
if (pokerRooms[roomId].current_player !== playerId) return res.status(403).send({ message: 'Ce n\'est pas ton tour' });
|
||||
|
||||
try {
|
||||
let diff = pokerRooms[roomId].highest_bet - pokerRooms[roomId].players[playerId].bet
|
||||
if (diff > pokerRooms[roomId].players[playerId].bank) {
|
||||
diff = pokerRooms[roomId].players[playerId].bank
|
||||
pokerRooms[roomId].players[playerId].allin = true
|
||||
}
|
||||
pokerRooms[roomId].players[playerId].bet += diff
|
||||
pokerRooms[roomId].players[playerId].bank -= diff
|
||||
pokerRooms[roomId].players[playerId].last_played_turn = pokerRooms[roomId].current_turn
|
||||
|
||||
await checksAfterPokerAction(roomId)
|
||||
|
||||
io.emit('poker-room-player-action')
|
||||
io.emit('new-poker-room')
|
||||
} catch(e) {
|
||||
console.log(e)
|
||||
return res.status(500).send({ message: e})
|
||||
}
|
||||
|
||||
return res.status(200)
|
||||
});
|
||||
|
||||
app.post('/poker-room/action/raise', async (req, res) => {
|
||||
const { roomId, playerId, amount } = req.body
|
||||
|
||||
if (!pokerRooms[roomId]) return res.status(404).send({ message: 'Table introuvable' })
|
||||
if (!pokerRooms[roomId].players[playerId]) return res.status(404).send({ message: 'Joueur introuvable' })
|
||||
|
||||
if (pokerRooms[roomId].current_player !== playerId) return res.status(403).send({ message: 'Ce n\'est pas ton tour' });
|
||||
if (amount > pokerRooms[roomId].players[playerId].bank) return res.status(403).send({ message: 'Tu n\as pas assez'});
|
||||
|
||||
try {
|
||||
if (amount === pokerRooms[roomId].players[playerId].bank) {
|
||||
pokerRooms[roomId].players[playerId].allin = true
|
||||
}
|
||||
pokerRooms[roomId].players[playerId].bet += amount
|
||||
pokerRooms[roomId].players[playerId].bank -= amount
|
||||
pokerRooms[roomId].players[playerId].last_played_turn = pokerRooms[roomId].current_turn
|
||||
for (let id in pokerRooms[roomId].players) {
|
||||
pokerRooms[roomId].players[id].is_last_raiser = false
|
||||
}
|
||||
pokerRooms[roomId].players[playerId].is_last_raiser = true
|
||||
pokerRooms[roomId].highest_bet = pokerRooms[roomId].players[playerId].bet
|
||||
|
||||
await checksAfterPokerAction(roomId)
|
||||
|
||||
io.emit('poker-room-player-action')
|
||||
io.emit('new-poker-room')
|
||||
} catch(e) {
|
||||
console.log(e)
|
||||
return res.status(500).send({ message: e})
|
||||
}
|
||||
|
||||
return res.status(200)
|
||||
});
|
||||
|
||||
async function checksAfterPokerAction(roomId) {
|
||||
let currentTurnDone = false
|
||||
let nextTurnUrl;
|
||||
if (pokerRooms[roomId].current_turn === 0) {
|
||||
currentTurnDone = isPreFlopDone(pokerRooms[roomId])
|
||||
nextTurnUrl = 'flop'
|
||||
}
|
||||
|
||||
if (currentTurnDone) {
|
||||
const url = (process.env.DEV_SITE === 'true' ? process.env.API_URL_DEV : process.env.API_URL) + '/poker-room/' + nextTurnUrl
|
||||
const response = await axios.post(url, { roomId: roomId})
|
||||
} else {
|
||||
pokerRooms[roomId].current_player = getNextActivePlayer(pokerRooms[roomId])
|
||||
}
|
||||
}
|
||||
|
||||
async function updatePokerPlayersSolve(roomId) {
|
||||
for (const playerId in pokerRooms[roomId].players) {
|
||||
const player = pokerRooms[roomId].players[playerId]
|
||||
let fullHand = pokerRooms[roomId].tapis
|
||||
player.solve = Hand.solve(fullHand.concat(player.hand), 'standard', false).descr
|
||||
}
|
||||
}
|
||||
|
||||
import http from 'http';
|
||||
import { Server } from 'socket.io';
|
||||
const server = http.createServer(app);
|
||||
|
||||
38
package-lock.json
generated
38
package-lock.json
generated
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@google/genai": "^0.8.0",
|
||||
"@mistralai/mistralai": "^1.6.0",
|
||||
"axios": "^1.9.0",
|
||||
"better-sqlite3": "^11.9.1",
|
||||
"discord-interactions": "^4.0.0",
|
||||
"discord.js": "^14.18.0",
|
||||
@@ -339,6 +340,17 @@
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz",
|
||||
"integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.0",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
@@ -1068,6 +1080,26 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
|
||||
@@ -2005,6 +2037,12 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pstree.remy": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"dependencies": {
|
||||
"@google/genai": "^0.8.0",
|
||||
"@mistralai/mistralai": "^1.6.0",
|
||||
"axios": "^1.9.0",
|
||||
"better-sqlite3": "^11.9.1",
|
||||
"discord-interactions": "^4.0.0",
|
||||
"discord.js": "^14.18.0",
|
||||
|
||||
47
utils.js
47
utils.js
@@ -197,4 +197,51 @@ export async function postAPOBuy(userId, amount) {
|
||||
})
|
||||
.then(response => response)
|
||||
.catch(error => console.log('Post error:', error))
|
||||
}
|
||||
|
||||
export function getFirstActivePlayerAfterDealer(room) {
|
||||
const players = Object.values(room.players);
|
||||
const dealerPosition = players.findIndex((p) => p.id === room.dealer);
|
||||
for (let i = 1; i < players.length; i++) {
|
||||
const nextPos = (dealerPosition + i) % players.length;
|
||||
if (!players[nextPos].folded && !players[nextPos].allin) {
|
||||
return players[nextPos].id;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getNextActivePlayer(room) {
|
||||
const players = Object.values(room.players);
|
||||
const currentPlayerPosition = players.findIndex((p) => p.id === room.current_player);
|
||||
for (let i = 1; i < players.length; i++) {
|
||||
const nextPos = (currentPlayerPosition + i) % players.length;
|
||||
if (!players[nextPos].folded && !players[nextPos].allin) {
|
||||
return players[nextPos].id;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function isPreFlopDone(room) {
|
||||
const players = Object.values(room.players);
|
||||
const currentBet = room.highest_bet;
|
||||
|
||||
const activePlayers = players.filter((p) => !p.folded && !p.allin);
|
||||
|
||||
if (activePlayers.length < 2) return true
|
||||
|
||||
const allCalledOrChecked = activePlayers.every(player => {
|
||||
return player.bet === currentBet || currentBet === 0;
|
||||
})
|
||||
|
||||
const lastRaiser = players.find(p => p.is_last_raiser)
|
||||
if (lastRaiser) {
|
||||
const raiserIndex = players.indexOf(lastRaiser);
|
||||
const playersAfterRaiser = players.slice(raiserIndex + 1).concat(players.slice(0, raiserIndex));
|
||||
const allAfterRaiserActed = playersAfterRaiser.every(p => p.folded || p.allin || p.bet === currentBet);
|
||||
return allCalledOrChecked && allAfterRaiserActed;
|
||||
}
|
||||
|
||||
return allCalledOrChecked;
|
||||
}
|
||||
Reference in New Issue
Block a user