poker is on the right way

This commit is contained in:
milo
2025-06-13 16:33:53 +02:00
parent 46ff0a3581
commit f03474ad52
4 changed files with 316 additions and 9 deletions

239
index.js
View File

@@ -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
View File

@@ -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",

View File

@@ -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",

View File

@@ -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;
}