Skip to content

Instantly share code, notes, and snippets.

@cakedan
Last active August 26, 2025 20:35
Show Gist options
  • Save cakedan/a1d56468374da52b80f983bdb4594cbe to your computer and use it in GitHub Desktop.
Save cakedan/a1d56468374da52b80f983bdb4594cbe to your computer and use it in GitHub Desktop.
let crypto = require("crypto");
let db = {
data: {},
load: () => db.data = JSON.parse(discord.storage.server.db || "{}"),
save: () => discord.storage.server.db = JSON.stringify(db.data),
get: (key) => db.data[key],
set: (key, val) => db.data[key] = val,
delete: (key) => delete db.data[key]
};
let States = {
START: 1,
PLAYER_TURN: 2,
GAME_OVER: 3
};
let Actions = {
BET: 1,
HIT: 2,
STAND: 3,
DOUBLE_DOWN: 4,
SPLIT: 5,
SPLIT_HIT: 6,
FAKE: 7,
PRINT: 8,
MONEY: 9,
HELP: 10
};
let isOwner = discord.user.id == "345691161530466304";
let session = {
state: States.START,
hand: [],
dealerHand: [],
splitHand: [],
bet: 0,
splitBet: 0,
balance: 1000,
doubled: false,
split: false
};
let cards = [
{ name: "A", value: -1, },
{ name: "J", value: 10, },
{ name: "Q", value: 10, },
{ name: "K", value: 10, }
];
let suits = [ "♥️", "♦️", "♣️", "♠️" ];
let deck = [];
let action = -1;
let nickname = discord.member && discord.member.nick;
let displayname = discord.user.global_name;
let username = discord.user.username;
let embed = {
title: `Blackjack - ${nickname || displayname || username}`,
color: Math.floor(Math.random() * (0xFFFFFF + 1)),
};
function createDeck() {
for (let i = 0; i < 8; i++) {
for (let i = 2; i <= 10; i++) {
cards.push({ name: i.toString(), value: i });
}
for (let suit of suits) {
for (let card of cards) {
deck.push({
id: `${card.name}${suit}`,
value: card.value,
hidden: false,
});
}
}
}
for (let i = 0; i < deck.length; i++) {
let j = crypto.randomInt(deck.length);
[deck[i], deck[j]] = [deck[j], deck[i]];
}
}
function manageSession() {
db.load();
let data = db.get(discord.user.id);
session = data ?? session;
if (session.state == States.GAME_OVER) {
session.state = States.START;
session.hand = [];
session.splitHand = [];
session.dealerHand = [];
session.bet = 0;
session.splitBet = 0;
session.doubled = false;
session.split = false;
if (session.balance <= 0) {
session.balance = 1000;
}
}
}
function parseCommands() {
let cmds = {
["--bet"]: Actions.BET, ["-b"]: Actions.BET,
["--hit"]: Actions.HIT, ["-h"]: Actions.HIT,
["--stand"]: Actions.STAND, ["-s"]: Actions.STAND,
["--double"]: Actions.DOUBLE_DOWN, ["-d"]: Actions.DOUBLE_DOWN,
["--split"]: Actions.SPLIT, ["-sp"]: Actions.SPLIT,
["--split_hit"]: Actions.SPLIT_HIT, ["-sh"]: Actions.SPLIT_HIT,
["--fake"]: Actions.FAKE, ["-f"]: Actions.FAKE,
["--print"]: Actions.PRINT, ["-p"]: Actions.PRINT,
["--money"]: Actions.MONEY, ["-m"]: Actions.MONEY,
["--help"]: Actions.HELP, ["-?"]: Actions.HELP
};
action = cmds[discord.variables.__args[0]] || -1;
if (action == -1) {
let betAmount = parseInt(discord.variables.__args[0]);
if (!isNaN(betAmount) && betAmount >= 0) {
action = Actions.BET;
discord.variables.__args[1] = betAmount.toString();
}
}
}
function calculateScore(hand) {
let score = 0;
let aces = 0;
for (let card of hand) {
if (card.hidden) {
continue;
}
if (card.value == -1) {
aces++;
score += 11;
} else {
score += card.value;
}
}
while (score > 21 && aces > 0) {
score -= 10;
aces--;
}
return score;
}
function canDoubleDown() {
if (session.hand.length > 2) return false;
if (session.hand.some(c => c.value == -1)) return false;
if (session.balance < session.bet) return false;
let score = calculateScore(session.hand);
if (score < 8 || score > 11) return false;
return true;
}
function canSplit() {
if (session.hand.length > 2) return false;
if (session.balance < session.bet) return false;
if (!session.hand[0] || !session.hand[1]) return false; // temporary check
if (session.hand[0].value != session.hand[1].value) return false;
return true;
}
function getPlayerActions() {
let playerActions = ["hit", "stand"];
if (canDoubleDown()) playerActions.push("double down");
if (canSplit()) playerActions.push("split");
playerActions = playerActions.reduce(
(text, element, index, array) => text + (index < array.length - 1 ? ", " : " or ") + element
);
return playerActions;
}
function handleStart() {
if (action == Actions.BET) {
let betAmount = parseInt(discord.variables.__args[1]);
if (isNaN(betAmount) || betAmount < 0) {
console.log("Invalid bet amount. Please enter a positive number.");
return -1;
}
if (betAmount > session.balance) {
console.log(`Insufficient balance. Your current balance is $${session.balance}.`);
return -1;
}
session.bet = betAmount;
session.balance -= betAmount;
let cards = deck.splice(0, 4);
let first = cards[0];
let second = cards[1];
let third = cards[2];
let fourth = cards[3];
session.hand.push(first);
session.dealerHand.push(second);
session.hand.push(third);
fourth.hidden = true;
session.dealerHand.push(fourth);
if ((first.value == -1 && third.value == 10) || (first.value == 10 && third.value == -1)) {
session.state = States.GAME_OVER;
embed.description = `Blackjack! You win with a score of 21!`;
session.balance += session.bet * 2.5;
return 0;
}
session.state = States.PLAYER_TURN;
embed.description = `You drew a ${first.id} and a ${third.id}. You can ${getPlayerActions()}.`
return 0;
} else {
console.log(`Please place a bet using bj <amount>. Your current balance is $${session.balance.toLocaleString()}.`);
return -1;
}
}
function handleDealerTurn() {
session.dealerHand = session.dealerHand.map(c => ({ ...c, hidden: false }));
while (calculateScore(session.dealerHand) < 17) {
let card = deck.pop();
session.dealerHand.push(card);
}
let playerScore = calculateScore(session.hand);
let splitScore = calculateScore(session.splitHand);
let dealerScore = calculateScore(session.dealerHand);
embed.description = "";
if (dealerScore > 21) {
embed.description += ` You win! Dealer busted with a score of ${dealerScore}.`;
session.balance += session.bet * 2 + session.splitBet * 2;
session.state = States.GAME_OVER;
return;
}
if (playerScore > dealerScore) {
embed.description += ` You win! Your score was ${playerScore} against dealer's ${dealerScore}.`;
session.balance += session.bet * 2;
} else if (playerScore < dealerScore) {
embed.description += ` You lose with a score of ${playerScore} against dealer's ${dealerScore}.`;
} else {
embed.description += ` It's a tie with both scoring ${playerScore}. You get your bet back.`;
session.balance += session.bet;
}
if (session.split) {
if (splitScore > dealerScore) {
embed.description += ` You win your split hand! Your score was ${splitScore} against dealer's ${dealerScore}.`;
session.balance += session.splitBet * 2;
} else if (splitScore < dealerScore) {
embed.description += ` You lose your split hand with a score of ${splitScore} against dealer's ${dealerScore}.`;
} else {
embed.description += ` It's a tie with your split hand scoring ${splitScore}. You get your split bet back.`;
session.balance += session.splitBet;
}
}
session.state = States.GAME_OVER;
}
function handlePlayerDraw() {
let handScore = calculateScore(session.hand);
let splitScore = calculateScore(session.splitHand);
let hit = action == Actions.HIT || action == Actions.DOUBLE_DOWN;
let splitHit = action == Actions.SPLIT_HIT && session.split;
embed.description = "";
if (hit && handScore <= 21) {
let handCard = deck.pop();
session.hand.push(handCard);
embed.description += ` You drew a ${handCard.id}.`;
}
if (splitHit && splitScore <= 21) {
let splitCard = deck.pop();
session.splitHand.push(splitCard);
embed.description += ` You drew a ${splitCard.id} for your split hand.`;
}
handScore = calculateScore(session.hand);
splitScore = calculateScore(session.splitHand);
if (hit && handScore > 21) {
embed.description += ` You busted! Your score was ${handScore}.`;
}
if (splitHit && splitScore > 21) {
embed.description += ` You busted your split hand! Your score was ${splitScore}.`;
}
if (session.split && handScore > 21 && splitScore > 21) {
session.state = States.GAME_OVER;
} else if (handScore > 21) {
session.state = States.GAME_OVER;
}
if (session.state == States.GAME_OVER) {
session.dealerHand = session.dealerHand.map(c => ({ ...c, hidden: false }));
}
}
function handleDoubleDown() {
if (!canDoubleDown()) {
embed.description = "You cannot double down at this time.";
return;
}
session.balance -= session.bet;
session.bet *= 2;
session.doubled = true;
handlePlayerDraw();
handleDealerTurn();
}
function handleSplit() {
if (!canSplit()) {
embed.description = "You cannot split your hand at this time.";
return;
}
session.split = true;
session.splitHand.push(session.hand.pop());
session.splitBet = session.bet;
session.balance -= session.bet;
embed.description = `You have split your hand.`;
}
function handlePlayerTurn() {
switch (action) {
case Actions.HIT:
case Actions.SPLIT_HIT:
handlePlayerDraw();
break;
case Actions.STAND:
handleDealerTurn();
break;
case Actions.DOUBLE_DOWN:
handleDoubleDown();
break;
case Actions.SPLIT:
handleSplit();
break;
default:
embed.description = `Please ${getPlayerActions()}.`;
return 0;
}
return 0;
}
function loadCards() {
session.hand = session.hand.map(id => deck.find(c => c.id == id));
session.splitHand = session.splitHand.map(id => deck.find(c => c.id == id));
session.dealerHand = session.dealerHand.map(data => ({
...deck.find(c => c.id == data.id),
hidden: data.hidden || false
}));
for (let card of [...session.hand, ...session.splitHand, ...session.dealerHand]) {
let found = deck.find(c => c.id == card.id);
if (found) deck.splice(deck.indexOf(found), 1);
}
}
function saveCards() {
session.hand = session.hand.map(c => c.id);
session.splitHand = session.splitHand.map(c => c.id);
session.dealerHand = session.dealerHand.map(c => ({ id: c.id, hidden: c.hidden }));
}
function handleMoney() {
let target = discord.variables.__args[1];
if (discord.member && target) {
let found = false;
target = target.toLowerCase();
for (let member of discord.guild.members) {
let userMatch = member.user.username
.toLowerCase()
.indexOf(target);
let nickMatch = (member.nick || "")
.toLowerCase()
.indexOf(target);
if (userMatch == -1 && nickMatch == -1) continue;
let id = member.user.id;
let data = db.get(id);
if (data) {
console.log(`<@${id}>'s account balance is $${data.balance.toLocaleString()}.`);
found = true;
return;
}
}
if (!found) {
console.log("No member found or member does not have any data.");
}
} else {
console.log(`Your account balance is $${session.balance.toLocaleString()}.`);
}
}
function handleHelp() {
console.log(`\`\`\`
Commands:
-b, --bet <amount> : Place a bet
-h, --hit : Hit
-s, --stand : Stand
-d, --double : Double down
-sp, --split : Split hand
-sh, --split_hit : Split hit
-m, --money : Show current balance
-?, --help : Show this help message
\`\`\``);
}
function handleFakeGame() {
let args = discord.variables.__args;
if (args[3] && args[4]) {
session.dealerHand = [
{ id: args[3], hidden: false },
{ id: args[4], hidden: true }
];
} else {
session.dealerHand = deck.splice(0, 2);
}
session.hand = [args[1], args[2]];
session.state = States.PLAYER_TURN;
db.set(discord.user.id, session);
db.save();
}
function runGame() {
switch (action) {
case Actions.MONEY:
handleMoney();
return;
case Actions.HELP:
handleHelp();
return;
case Actions.FAKE:
if (isOwner) {
handleFakeGame();
} else {
console.log("You do not have permission to use this command.");
}
return;
case Actions.PRINT:
if (isOwner) {
loadCards();
console.log(session);
} else {
console.log("You do not have permission to use this command.");
}
return;
}
let resultCode = 0;
if (session.state == States.START) {
resultCode = handleStart();
} else if (session.state == States.PLAYER_TURN) {
loadCards();
resultCode = handlePlayerTurn();
}
if (resultCode != 0) return;
embed.fields = [
{
name: "Your Hand",
value: session.hand.map(c => c.id).join(", "),
inline: true
},
{
name: "Dealer's Hand",
value: session.dealerHand.map(c => c.hidden ? "?" : c.id).join(", "),
inline: true
},
{
name: "Bet",
value: `$${Number(session.bet).toLocaleString()}`,
inline: true
},
{
name: "Your Score",
value: calculateScore(session.hand).toString(),
inline: true
},
{
name: "Dealer's Score",
value: calculateScore(session.dealerHand).toString(),
inline: true
},
{
name: "Balance",
value: `$${Number(session.balance).toLocaleString()}`,
inline: true
},
];
if (session.split) {
embed.fields.splice(1, 0, {
name: "Split Hand",
value: session.splitHand.map(c => c.id).join(", "),
inline: true
});
embed.fields.splice(4, 0, {
name: "Split Bet",
value: `$${Number(session.splitBet).toLocaleString()}`,
inline: true
});
embed.fields.splice(7, 0, {
name: "Split Score",
value: calculateScore(session.splitHand).toString(),
inline: true
});
}
let output = {
embed: embed,
components: []
};
if (session.split) {
if (calculateScore(session.hand) <= 21) {
output.components.push(
{ type: 2, label: "Hit", run: `\{tag:{tagid}|--hit\}` }
);
}
if (calculateScore(session.splitHand) <= 21) {
output.components.push(
{ type: 2, label: "Split Hit", run: `\{tag:{tagid}|--split_hit\}` }
);
}
output.components.push(
{ type: 2, label: "Stand", run: `\{tag:{tagid}|--stand\}` }
);
} else {
output.components = [
{ type: 2, label: "Hit", run: `\{tag:{tagid}|--hit\}` },
{ type: 2, label: "Stand", run: `\{tag:{tagid}|--stand\}` }
];
}
if (canSplit()) {
output.components.push(
{ type: 2, label: "Split", run: `\{tag:{tagid}|--split\}` }
);
}
if (canDoubleDown()) {
output.components.push(
{ type: 2, label: "Double Down", run: `\{tag:{tagid}|--double\}` }
);
}
if (session.state == States.GAME_OVER) {
output.components = [];
}
console.log(JSON.stringify(output));
saveCards();
db.set(discord.user.id, session);
db.save();
}
function run() {
createDeck();
manageSession();
parseCommands();
runGame();
}
run();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment