Restructure blackjack to only use a single endpoint and better handle "game end" logic

remotes/1693045480750635534/spooky-22
Outrun Colors 2022-09-05 13:27:00 -05:00
parent 6ae4459063
commit b1674355c0
No known key found for this signature in database
GPG Key ID: 0426976DCEFE6073
5 changed files with 133 additions and 142 deletions

View File

@ -82,6 +82,8 @@ function handleSlotsResponse(xhr) {
}
// Blackjack
// Checking existing status onload.
// When the casino loads, look up the "blackjack status" of a player to either start a new game or continue an existing game.
if (
document.readyState === "complete" ||
@ -114,12 +116,16 @@ function handleBlackjackStatusResponse(xhr) {
if (succeeded) {
if (response.active) {
updateBlackjack(response.game_state);
} else {
updateBlackjackActions(null);
}
} else {
console.error("error");
}
}
// DOM Manipulation
// When starting a new game or taking an action in an existing one, a new state will be returned, and the DOM must be updated.
function updateBlackjack(state) {
const { player, dealer, status } = state;
@ -232,7 +238,7 @@ function updateBlackjackActions(state) {
clearBlackjackActions();
if (state.status === "active") {
if (state && state.status === "active") {
document.getElementById("casinoBlackjackWager").style.display = "none";
const actionLookup = {
@ -258,8 +264,7 @@ function updateBlackjackActions(state) {
actionWrapper.innerHTML = actions.join("\n");
} else {
// Game is over, deal a new game.
document.getElementById("casinoBlackjackWager").style.display = "flex";
document.getElementById("casinoBlackjackBet").disabled = false;
showWagerWidget();
const deal = buildBlackjackAction(
"casinoBlackjackDeal",
@ -272,30 +277,20 @@ function updateBlackjackActions(state) {
}
}
function dealBlackjack() {
const wager = document.getElementById("casinoBlackjackBet").value;
const currency = document.querySelector(
'input[name="casinoBlackjackCurrency"]:checked'
).value;
function hideWagerWidget() {
document.getElementById("casinoBlackjackBet").disabled = true;
document.getElementById("casinoBlackjackDeal").disabled = true;
document.getElementById("casinoBlackjackWager").style.display = "none";
document.getElementById("casinoBlackjackResult").style.visibility = "hidden";
const xhr = new XMLHttpRequest();
xhr.open("post", "/casino/blackjack");
xhr.onload = handleBlackjackResponse.bind(null, xhr);
const form = new FormData();
form.append("formkey", formkey());
form.append("wager", wager);
form.append("currency", currency);
xhr.send(form);
}
function takeBlackjackAction(action) {
function showWagerWidget() {
document.getElementById("casinoBlackjackWager").style.display = "flex";
document.getElementById("casinoBlackjackBet").disabled = false;
}
// Actions, Requests & Responses
function takeBlackjackAction(action, args = {}) {
const xhr = new XMLHttpRequest();
xhr.open("post", "/casino/blackjack/action");
xhr.onload = handleBlackjackResponse.bind(null, xhr);
@ -304,9 +299,20 @@ function takeBlackjackAction(action) {
form.append("formkey", formkey());
form.append("action", action);
for (const [key, value] of Object.entries(args)) {
form.append(key, value);
}
xhr.send(form);
}
const dealBlackjack = () => {
const wager = document.getElementById("casinoBlackjackBet").value;
const currency = document.querySelector('input[name="casinoBlackjackCurrency"]:checked').value;
hideWagerWidget();
takeBlackjackAction("deal", { currency, wager });
}
const hitBlackjack = takeBlackjackAction.bind(null, "hit");
const stayBlackjack = takeBlackjackAction.bind(null, "stay");
const doubleBlackjack = takeBlackjackAction.bind(null, "double_down");
@ -324,7 +330,7 @@ function handleBlackjackResponse(xhr) {
const succeeded =
xhr.status >= 200 && xhr.status < 300 && response && !response.error;
const blackjackResult = document.getElementById("casinoBlackjackResult");
blackjackResult.classList.remove("text-success", "text-danger");
blackjackResult.classList.remove("text-success", "text-danger", "text-warning");
if (succeeded) {
if (response.game_state) {

View File

@ -54,32 +54,30 @@ def get_active_game(gambler):
Casino_Game.user_id == gambler.id).one_or_none()
if game:
return game, json.loads(game.game_state)
game_state = json.loads(game.game_state)
return game, game_state, get_safe_game_state(game_state)
else:
return None, None
return None, None, None
def get_safe_game_state(gambler):
game, game_state = get_active_game(gambler)
def get_safe_game_state(game_state):
return {
"player": game_state['player'],
"dealer": [game_state['dealer'][0], "?"],
"actions": game_state['actions'],
"insurance": game_state['insurance'],
"doubled_down": game_state['doubled_down'],
"status": game_state['status']
}
if game:
return {
"player": game_state['player'],
"dealer": [game_state['dealer'][0], "?"],
"actions": game_state['actions'],
"insurance": game_state['insurance'],
"doubled_down": game_state['doubled_down'],
"status": game_state['status']
}
else:
return None
def apply_blackjack_result(gambler):
game, game_state = get_active_game(gambler)
game, game_state, _ = get_active_game(gambler)
if game and game.active:
if game:
result = game_state['status']
if result == 'push' or result == 'insured_loss':
reward = game.wager
elif result == 'won':
@ -95,53 +93,58 @@ def apply_blackjack_result(gambler):
gambler.winnings += reward
game.winnings += reward
if result not in ('push','blackjack'):
game.active = False
game.active = False
g.db.add(game)
def deal_blackjack_game(gambler, wager_value, currency):
over_min = wager_value >= minimum_bet
under_max = wager_value <= maximum_bet
using_dramacoin = currency == "dramacoin"
using_marseybux = not using_dramacoin
has_proper_funds = (using_dramacoin and gambler.coins >= wager_value) or (
using_marseybux and gambler.procoins >= wager_value)
currency_prop = "coins" if using_dramacoin else "procoins"
currency_value = getattr(gambler, currency_prop, 0)
if (over_min and under_max and has_proper_funds):
build_game(gambler, currency_prop, wager_value)
game, game_state = get_active_game(gambler)
player_value = get_hand_value(game_state['player'])
dealer_value = get_hand_value(game_state['dealer'])
# Charge the gambler for the game, reduce their winnings, and start the game.
setattr(gambler, currency_prop, currency_value - wager_value)
gambler.winnings -= wager_value
game.winnings -= wager_value
# if player_value == 21 and dealer_value == 21:
# game_state["status"] = 'push'
# save_game_state(game, game_state)
# apply_blackjack_result(gambler)
# elif player_value == 21:
# game_state["status"] = 'blackjack'
# save_game_state(game, game_state)
# apply_blackjack_result(gambler)
g.db.flush()
return True
else:
return False
# region Actions
def gambler_dealt(gambler, currency, wager):
existing_game, _, _ = get_active_game(gambler)
if not existing_game:
over_min = wager >= minimum_bet
under_max = wager <= maximum_bet
using_dramacoin = currency == "dramacoin"
using_marseybux = not using_dramacoin
has_proper_funds = (using_dramacoin and gambler.coins >= wager) or (
using_marseybux and gambler.procoins >= wager)
currency_prop = "coins" if using_dramacoin else "procoins"
currency_value = getattr(gambler, currency_prop, 0)
if (over_min and under_max and has_proper_funds):
# Start the game.
build_game(gambler, currency_prop, wager)
game, game_state, safe_state = get_active_game(gambler)
player_value = get_hand_value(game_state['player'])
dealer_value = get_hand_value(game_state['dealer'])
# Charge the gambler for the game, reduce their winnings.
setattr(gambler, currency_prop, currency_value - wager)
gambler.winnings -= wager
game.winnings -= wager
# In two cases, the game is instantly over.
instantly_over = False
if player_value == 21 and dealer_value == 21:
instantly_over = True
game_state["status"] = 'push'
save_game_state(game, game_state)
apply_blackjack_result(gambler)
elif player_value == 21:
instantly_over = True
game_state["status"] = 'blackjack'
save_game_state(game, game_state)
apply_blackjack_result(gambler)
g.db.flush()
if instantly_over:
return True, game_state
else:
return True, safe_state
def gambler_hit(gambler):
game, game_state = get_active_game(gambler)
game, game_state, safe_state = get_active_game(gambler)
if game:
player = game_state['player']
@ -167,13 +170,14 @@ def gambler_hit(gambler):
forced_stay_success, forced_stay_state = gambler_stayed(gambler)
return forced_stay_success, forced_stay_state
else:
return True, game_state
_, _, safe_state = get_active_game(gambler)
return True, safe_state
else:
return False, game_state
return False, safe_state
def gambler_stayed(gambler):
game, game_state = get_active_game(gambler)
game, game_state, safe_state = get_active_game(gambler)
if game:
player = game_state['player']
@ -206,11 +210,11 @@ def gambler_stayed(gambler):
return True, game_state
else:
return False, game_state
return False, safe_state
def gambler_doubled_down(gambler):
game, game_state = get_active_game(gambler)
game, game_state, safe_state = get_active_game(gambler)
if game and not game_state['doubled_down']:
currency_value = getattr(gambler, game.currency, 0)
@ -229,14 +233,13 @@ def gambler_doubled_down(gambler):
g.db.flush()
last_hit_success, last_hit_state = gambler_hit(gambler)
return last_hit_success, last_hit_state
else:
return False, game_state
return False, safe_state
def gambler_purchased_insurance(gambler):
game, game_state = get_active_game(gambler)
game, game_state, safe_state = get_active_game(gambler)
if game and not game_state['insurance']:
insurance_cost = game.wager / 2
@ -253,9 +256,10 @@ def gambler_purchased_insurance(gambler):
game_state['actions'] = determine_actions(game_state)
save_game_state(game, game_state)
return True, game_state
_, _, safe_state = get_active_game(gambler)
return True, safe_state
else:
return False, game_state
return False, safe_state
# endregion

View File

@ -46,47 +46,12 @@ def pull_slots(v):
@limiter.limit("3/second;30/minute;600/hour;12000/day")
@auth_required
def get_player_blackjack_status(v):
game, game_state = get_active_game(v)
game, _, safe_state = get_active_game(v)
if game and game.active:
safe_state = get_safe_game_state(v)
return {"active": True, "game_state": safe_state}
if game:
return { "active": True, "game_state": safe_state }
else:
return {"active": False, "game_state": game_state}
@app.post("/casino/blackjack")
@limiter.limit("3/second;30/minute;600/hour;12000/day")
@auth_required
def deal_blackjack(v):
try:
wager = int(request.values.get("wager"))
except:
return {"error": "Invalid wager."}
try:
currency = request.values.get("currency")
except:
return {"error": "Invalid currency (expected 'dramacoin' or 'marseybux')."}
if (currency == "dramacoin" and wager > v.coins) or (currency == "marseybux" and wager > v.procoins):
return {"error": f"Not enough {currency} to make that bet."}
success = deal_blackjack_game(v, wager, currency)
if success:
game, game_state = get_active_game(v)
if game and game.active:
safe_state = get_safe_game_state(v)
if safe_state['status'] in ('push','blackjack'):
game.active = False
return {"game_state": safe_state, "gambler": { "coins": v.coins, "procoins": v.procoins }}
else:
return {"game_state": game_state, "gambler": { "coins": v.coins, "procoins": v.procoins }}
else:
return {"error": "Wager must be more than 100 {currency}."}
return { "active": False }
@app.post("/casino/blackjack/action")
@ -96,12 +61,29 @@ def player_took_blackjack_action(v):
try:
action = request.values.get("action")
except:
return {"error": "Invalid action."}
return { "error": "Invalid action." }
was_successful = False
state = None
if action == 'hit':
if action == 'deal':
try:
currency = request.values.get("currency")
wager = int(request.values.get("wager"))
except:
return { "error": "Missing either currency or wager values." }
existing_game, _, _ = get_active_game(v)
if (currency == "dramacoin" and wager > v.coins) or (currency == "marseybux" and wager > v.procoins):
return {"error": f"Not enough {currency} to make that bet."}
elif existing_game:
return { "error": "Cannot start a new game while an existing game persists." }
else:
success, game_state = gambler_dealt(v, currency, wager)
was_successful = success
state = game_state
elif action == 'hit':
success, game_state = gambler_hit(v)
was_successful = success
state = game_state
@ -119,6 +101,10 @@ def player_took_blackjack_action(v):
state = game_state
if was_successful:
return {"active": True, "game_state": state, "gambler": { "coins": v.coins, "procoins": v.procoins }}
return {
"active": True,
"game_state": state,
"gambler": { "coins": v.coins, "procoins": v.procoins }
}
else:
return {"active": False, "game_state": None}
return { "active": False }

View File

@ -32,6 +32,10 @@ def leaderboard_thread():
for user in users8:
users9.append((user.id, votes3[user.id]))
users9 = sorted(users9, key=lambda x: x[1], reverse=True)
if (len(users9) < 2):
return
users9_1, users9_2 = zip(*users9[:25])
votes1 = db.query(Vote.user_id, func.count(Vote.user_id)).filter(Vote.vote_type==1).group_by(Vote.user_id).order_by(func.count(Vote.user_id).desc()).all()

View File

@ -234,15 +234,6 @@
</div>
<div id="casinoBlackjackActions" class="casino-blackjack-actions">
<button
type="button"
class="btn btn-success lottery-page--action"
id="casinoBlackjackDeal"
style="width: 100%"
onclick="dealBlackjack()"
>
Deal
</button>
</div>
</div>
</div>