uff #1
|
@ -13,7 +13,6 @@
|
|||
"author": "Flummi",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@xpressit/winning-poker-hand-rank": "^0.1.6",
|
||||
"cuffeo": "^1.2.2"
|
||||
}
|
||||
}
|
||||
|
|
1410
src/inc/constants.mjs
Normal file
1410
src/inc/constants.mjs
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -9,7 +9,7 @@ try {
|
|||
}
|
||||
|
||||
export default new class {
|
||||
suits = { "♠": "S", "♣": "C", "♦": "D", "♥": "H" };
|
||||
suits = { "♠": "s", "♣": "c", "♦": "d", "♥": "h" };
|
||||
stripColors = msg => msg.replace(/\x03\d{0,2}(,\d{0,2}|\x02\x02)?/g, '');
|
||||
rand = (max = 1) => ~~(Math.random() * (max - 1) + 1);
|
||||
|
||||
|
|
136
src/inc/hr.mjs
Normal file
136
src/inc/hr.mjs
Normal file
|
@ -0,0 +1,136 @@
|
|||
import constants from './constants.mjs';
|
||||
|
||||
export default new class handranker {
|
||||
rankHands(board, hand) {
|
||||
const bestHand = this.calcBestHand(hand.map(c => this.toCard(c)), board.map(c => this.toCard(c)));
|
||||
|
||||
return {
|
||||
rank: bestHand.rank,
|
||||
percentage: (9999 - bestHand.rank) / 100,
|
||||
combination: this.toCombination(bestHand.rank),
|
||||
//madeHand: bestHand.madeHand.map((c) => this.toPlayingCard(c)),
|
||||
//unused: bestHand.unused.map((c) => this.toPlayingCard(c)),
|
||||
};
|
||||
};
|
||||
|
||||
calcBestHand(pocketCards, communityCards) {
|
||||
const cards = [...pocketCards, ...communityCards];
|
||||
const { rank, madeHand } = this.rank567cardHand([...pocketCards, ...communityCards]);
|
||||
return {
|
||||
rank,
|
||||
madeHand,
|
||||
unused: cards.filter((c) => !madeHand.find((mc) => mc === c)),
|
||||
};
|
||||
};
|
||||
|
||||
toCombination(rank) {
|
||||
const fixedRank = this.toFixedTexasRank(rank);
|
||||
if(fixedRank === 10) return 'StraightFlush';
|
||||
if(fixedRank === 166) return 'FourOfAKind';
|
||||
if(fixedRank === 322) return 'FullHouse';
|
||||
if(fixedRank === 1599) return 'Flush';
|
||||
if(fixedRank === 1609) return 'Straight';
|
||||
if(fixedRank === 2467) return 'ThreeOfAKind';
|
||||
if(fixedRank === 3325) return 'TwoPairs';
|
||||
if(fixedRank === 6185) return 'Pair';
|
||||
if(fixedRank === 7462) return 'HighCard';
|
||||
return 'Invalid';
|
||||
};
|
||||
|
||||
cactusFastRankHand(hand) {
|
||||
const [c0, c1, c2, c3, c4] = hand;
|
||||
if((c0 & c1 & c2 & c3 & c4 & 0xf000) !== 0)
|
||||
return constants.fastFlushes[(c0 | c1 | c2 | c3 | c4) >>> 16];
|
||||
const r = constants.fastUnique5[(c0 | c1 | c2 | c3 | c4) >>> 16];
|
||||
if(r)
|
||||
return r;
|
||||
let u = 0xe91aaa35 + (((c0 & 0xff) * (c1 & 0xff) * (c2 & 0xff) * (c3 & 0xff) * (c4 & 0xff)) | 0);
|
||||
u = u ^ (u >>> 16);
|
||||
u += u << 8;
|
||||
u ^= u >>> 4;
|
||||
return constants.hash[((u + (u << 2)) >>> 19) ^ (constants.hashAdjust[(u >>> 8) & 0x1ff] | 0)];
|
||||
};
|
||||
|
||||
rank567cardHand(hand) {
|
||||
if(hand.length === 5) {
|
||||
return {
|
||||
rank: this.cactusFastRankHand([hand[0], hand[1], hand[2], hand[3], hand[4]]),
|
||||
madeHand: [hand[0], hand[1], hand[2], hand[3], hand[4]],
|
||||
};
|
||||
}
|
||||
if(hand.length === 6) {
|
||||
const possibleHands = [
|
||||
[hand[0], hand[1], hand[2], hand[3], hand[4]],
|
||||
[hand[0], hand[1], hand[2], hand[3], hand[5]],
|
||||
[hand[0], hand[1], hand[2], hand[4], hand[5]],
|
||||
[hand[0], hand[1], hand[3], hand[4], hand[5]],
|
||||
[hand[0], hand[2], hand[3], hand[4], hand[5]],
|
||||
[hand[1], hand[2], hand[3], hand[4], hand[5]],
|
||||
];
|
||||
const sortedHands = possibleHands.map(h => ({
|
||||
rank: this.cactusFastRankHand(h),
|
||||
madeHand: h,
|
||||
})).sort((a, b) => a.rank - b.rank);
|
||||
return sortedHands[0];
|
||||
}
|
||||
if (hand.length === 7) {
|
||||
let r = 0;
|
||||
let rank = 9999;
|
||||
let bestHand = [hand[0], hand[1], hand[2], hand[3], hand[4]];
|
||||
for (let i = 0; i < 21; i++) {
|
||||
const inputHand = [
|
||||
hand[constants.t7c5[i][0]],
|
||||
hand[constants.t7c5[i][1]],
|
||||
hand[constants.t7c5[i][2]],
|
||||
hand[constants.t7c5[i][3]],
|
||||
hand[constants.t7c5[i][4]],
|
||||
];
|
||||
r = this.cactusFastRankHand(inputHand);
|
||||
if (r < rank) {
|
||||
rank = r;
|
||||
bestHand = inputHand;
|
||||
}
|
||||
}
|
||||
return {
|
||||
rank,
|
||||
madeHand: bestHand,
|
||||
};
|
||||
}
|
||||
throw new Error(`Hand ranker doesn't support ${hand.length} cards`);
|
||||
};
|
||||
|
||||
toFixedTexasRank(r) {
|
||||
if(r <= 10) return 10; // StraightFlush
|
||||
if(r <= 166) return 166; // FourOfAKind
|
||||
if(r <= 322) return 322; // FullHouse
|
||||
if(r <= 1599) return 1599; // Flush
|
||||
if(r <= 1609) return 1609; // Straight
|
||||
if(r <= 2467) return 2467; // ThreeOfAKind
|
||||
if(r <= 3325) return 3325; // TwoPairs
|
||||
if(r <= 6185) return 6185; // Pair
|
||||
if(r != 65535) return 7462; // HighCard
|
||||
return 65535; // Invalid
|
||||
};
|
||||
|
||||
toPlayingCard(card) {
|
||||
const rankRune = constants.rankToRune[(card >> 8) & 0xf];
|
||||
const suitRune = constants.suitToRune[(card >> 12) & 0xf];
|
||||
if (!rankRune || !suitRune) {
|
||||
throw new Error(`Cannot convert Card ${card} to PlayingCard`);
|
||||
}
|
||||
return (rankRune + suitRune);
|
||||
};
|
||||
|
||||
toCard(playingCard) {
|
||||
const [rank, suit] = this.toRankAndSuit(playingCard);
|
||||
return ((1 << rank) << 16) | (suit << 12) | (rank << 8) | constants.PRIMES[rank];
|
||||
};
|
||||
|
||||
toRankAndSuit(playingCard) {
|
||||
const rank = constants.runeToRank[playingCard[0]];
|
||||
const suit = constants.runeToSuit[playingCard[1]];
|
||||
if (!suit || rank === undefined)
|
||||
throw new Error(`Invalid playing card: ${playingCard}`);
|
||||
return [rank, suit];
|
||||
};
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
import cuffeo from 'cuffeo';
|
||||
import handranker from './inc/handranker.mjs';
|
||||
import { rankHands } from '@xpressit/winning-poker-hand-rank';
|
||||
import helper from './inc/helper.mjs';
|
||||
import hr from './inc/hr.mjs';
|
||||
|
||||
const cfg = helper.config;
|
||||
export const bot = await new cuffeo(cfg.getFull().clients);
|
||||
|
@ -29,6 +29,30 @@ bot.on("notice", msg => {
|
|||
bot.on("message", async e => {
|
||||
if(e.channel !== cfg.get('channel'))
|
||||
return;
|
||||
if(e.message.startsWith(".cards ")) {
|
||||
let cards = [];
|
||||
try {
|
||||
cards = JSON.parse(e.message.slice(7));
|
||||
} catch(err) {
|
||||
return e.reply('das ist kein Array du Pflaumennase');
|
||||
}
|
||||
|
||||
const hand = cards.slice(0, 2);
|
||||
const board = cards.slice(2);
|
||||
|
||||
let rank;
|
||||
|
||||
try {
|
||||
rank = hr.rankHands(board, hand);
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
return e.reply(JSON.stringify(err));
|
||||
}
|
||||
|
||||
e.reply(JSON.stringify(rank));
|
||||
|
||||
return;
|
||||
}
|
||||
if(e.message === `.${e.self.me.nickname} help`) {
|
||||
await e.write(`PRIVMSG ${e.user.nick} I always say hirc schmirc, available commands are:`);
|
||||
const commands = [
|
||||
|
@ -48,32 +72,6 @@ bot.on("message", async e => {
|
|||
await e.write(`PRIVMSG ${e.user.nick} ${command}`);
|
||||
}
|
||||
}
|
||||
if(e.message.startsWith(".cards ")) {
|
||||
let cards = [];
|
||||
try {
|
||||
cards = JSON.parse(e.message.slice(7));
|
||||
} catch(err) {
|
||||
return e.reply('das ist kein Array du Pflaumennase');
|
||||
}
|
||||
|
||||
const all = cards;
|
||||
const hand = cards.slice(0, 2);
|
||||
const board = cards.slice(2);
|
||||
|
||||
let oldrank;
|
||||
let newrank;
|
||||
|
||||
try {
|
||||
oldrank = rankHands('texas', board, [hand])[0];
|
||||
newrank = handranker.evalHand(all);
|
||||
} catch(err) {
|
||||
return e.reply(JSON.stringify(err));
|
||||
}
|
||||
|
||||
e.reply('old: ' + JSON.stringify(oldrank));
|
||||
e.reply('new: ' + JSON.stringify(newrank));
|
||||
return;
|
||||
}
|
||||
if(e.message.match(new RegExp(`^${e.self.me.nickname}: Your bank account`))) {
|
||||
env.bank = +e.message.match(/is: (\d+) \(/)[1];
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user