Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .github/workflows/black-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@ name: Black Lint
on:
push:
branches: [main, dev]
paths:
- '**/*.py'
pull_request:
branches: [main]
paths:
- '**/*.py'
workflow_dispatch:

concurrency:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
.claude/
CLAUDE.md

*.pyc
__pychache__/
.pytest_cache/
Expand Down
72 changes: 72 additions & 0 deletions PWA.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# 📲Install MonkeyJOB App

Let MonkeyJob be part of your desktop:

---

## 📱iOS

1. Open [www.jack-s-onlineblackjack.com](https://www.jack-s-onlineblackjack.com) in Safari.
2. Tap the **Share** button — square with an arrow one.
3. Scroll down and tap **Add to Home Screen**.
4. Confirm — icon lands on your home screen, like any other app.

---

## 💻macOS

**🧭Safari**
1. Open [www.jack-s-onlineblackjack.com](https://www.jack-s-onlineblackjack.com).

2. Menu bar → **File → Add to Dock**.

↳ Or share icon → Add to Dock.

3. MonkeyJob appears in your Dock as a standalone app.

**🌈Chrome**
1. Open [www.jack-s-onlineblackjack.com](https://www.jack-s-onlineblackjack.com).

2. Click **Install** icon on address bar's right side.

↳ Or ⋮ menu → Cast, Save, and Share → Install MonkeyJob.

3. Find it in **Launchpad**, or drag it into your Dock.

---

## 🤖Android

1. Open [www.jack-s-onlineblackjack.com](https://www.jack-s-onlineblackjack.com) in Chrome.

2. Tap the **⋮** menu → **Install app**.

↳ Tap **Install** if Chrome shows a banner automatically.

3. Confirm — MonkeyJob is added to your home screen and app drawer.

---

## 🪟Windows

**Edge** — best support
1. Open [www.jack-s-onlineblackjack.com](https://www.jack-s-onlineblackjack.com).

2. Click **Install** icon on address bar's right side.

↳ Or ⋯ menu → Apps → Install this site as an app.

3. MonkeyJob opens in its own window and is added to Start Menu.

**🌈Chrome**
1. Open [www.jack-s-onlineblackjack.com](https://www.jack-s-onlineblackjack.com).

2. Click **Install** icon on address bar's right side.

↳ Or ⋮ menu → Cast, Save, and Share → Install MonkeyJob.

3. Find it in Start Menu, or pin it to your taskbar.

---

JOB — **J**ack's **O**nline **B**lackjack — is officially in your desktop 🎃
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,23 @@

# 🎰MonkeyJOB: Jack's Online Blackjack

[![Installation Guide](https://img.shields.io/badge/📲%20Installation-Guide%20📖-0d1f17?style=for-the-badge)](./PWA.md)

[![iOS](https://img.shields.io/badge/iOS-000000?style=for-the-badge&logo=apple&logoColor=white)](https://www.jack-s-onlineblackjack.com)
[![Android](https://img.shields.io/badge/Android-3DDC84?style=for-the-badge&logo=android&logoColor=white)](https://www.jack-s-onlineblackjack.com)

[![macOS](https://img.shields.io/badge/macOS-A2AAAD?style=for-the-badge&logo=apple&logoColor=black)](https://www.jack-s-onlineblackjack.com)
[![Windows](https://img.shields.io/badge/Windows-0078D4?style=for-the-badge&logo=windows&logoColor=white)](https://www.jack-s-onlineblackjack.com)

### 🛰️ Metadata

[![main Unit Tests](https://github.com/StarsExpress/MonkeyJOB/actions/workflows/unit_tests.yml/badge.svg?branch=main)](https://github.com/StarsExpress/MonkeyJOB/actions)
[![main Component Tests](https://github.com/StarsExpress/MonkeyJOB/actions/workflows/component_tests.yml/badge.svg?branch=main)](https://github.com/StarsExpress/MonkeyJOB/actions)
[![main Integration Tests](https://github.com/StarsExpress/MonkeyJOB/actions/workflows/integration_tests.yml/badge.svg?branch=main)](https://github.com/StarsExpress/MonkeyJOB/actions)
[![main Black Linter](https://github.com/StarsExpress/MonkeyJOB/actions/workflows/black-lint.yml/badge.svg?branch=main)](https://github.com/StarsExpress/MonkeyJOB/actions)
[![main Black Lint](https://github.com/StarsExpress/MonkeyJOB/actions/workflows/black-lint.yml/badge.svg?branch=main)](https://github.com/StarsExpress/MonkeyJOB/actions)
[![Latest Release](https://img.shields.io/github/v/release/StarsExpress/MonkeyJOB)](https://github.com/StarsExpress/MonkeyJOB/releases)

---

### [🤵🏻 Let's Have A Seat 🐵](https://www.jack-s-onlineblackjack.com)

Expand Down
40 changes: 39 additions & 1 deletion blackjack.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
from utils.judges import judge_blackjack, judge_surrender, judge_split
from utils.trackers import update_properties, track_display_value
from configs.hands_config import MIN_DEALER_VALUE, MAX_TOTAL_VALUE, HANDS_RANGE
from configs.bets_config import MAX_CAPITAL, MIN_BET, MAX_BET, BLACKJACK_PAY
from configs.bets_config import (
MAX_CAPITAL,
MIN_BET,
MAX_BET,
BLACKJACK_PAY,
HUGE_PROFIT_RATIO,
)
from configs.display_config import DEFAULT_PLAYER_NAME, DANGER_ZONE, MAX_NAME_LEN


Expand Down Expand Up @@ -38,6 +44,10 @@ def __init__(self):
self._initial_capital = 0
self._profits: dict = dict()

# Whole-round ROI congrats payload, set once at settlement when the
# round clears HUGE_PROFIT_RATIO; None otherwise. See _close_round.
self._congrats: dict | None = None

# Keys: hand_branch.
# Values categories:
# I. Blackjack related: bj | early_pay.
Expand Down Expand Up @@ -96,6 +106,7 @@ def start_round(self, bets: list) -> dict:

self._profits.clear() # Reset for new round.
self._outcomes.clear()
self._congrats = None

self._bj_early_pay_queue.clear() # Reset for new round.
self._early_paid_hands.clear()
Expand Down Expand Up @@ -491,12 +502,36 @@ def _close_round(self):
}
)

self._flag_huge_profit(total_profit)

self.round_num += 1
self._phase = "settled"

self._active_hand = None
self._active_branch = None

def _flag_huge_profit(self, net_profit: int):
"""Whole-round ROI check (ported from v1.0.0 POPUP_DICT["huge_profits"]).

Runs once per round, only here at full settlement. The denominator is
every chip committed this round: base bets, double/split added wagers
(captured by each branch's chips), and insurance. If net profit over
that total clears HUGE_PROFIT_RATIO, flag a one-time congrats payload
for the final settlement response to carry; the frontend renders it.
"""
committed = 0
for hand in self.player.hands_dict.values():
for branch_id in hand.cards_dict:
committed += hand.chips_dict.get(branch_id, hand.initial_chips)
committed += hand.insurance

if committed <= 0:
return

ratio = net_profit / committed
if ratio >= HUGE_PROFIT_RATIO:
self._congrats = {"profit_rate": round(ratio * 100, 1)}

def _serialize(self) -> dict:
dealer_data = {
"cards": [
Expand Down Expand Up @@ -620,6 +655,9 @@ def _serialize(self) -> dict:
"round": self.round_num,
}

if self._phase == "settled" and self._congrats is not None:
result["congrats"] = self._congrats

if self._phase == "playing" and self._active_hand:
result["active_hand"] = self._active_hand
result["active_branch"] = self._active_branch
Expand Down
6 changes: 6 additions & 0 deletions configs/bets_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@
MIN_BET = 300

BLACKJACK_PAY = 1.5

# Whole-round ROI congrats popup (ported from v1.0.0 POPUP_DICT["huge_profits"]).
# Fires once after a round is fully settled, when the round's net profit divided
# by the total chips committed (base bets + double/split wagers + insurance)
# meets this ratio. 0.7 == a 70% return on everything staked that round.
HUGE_PROFIT_RATIO = 0.7
27 changes: 26 additions & 1 deletion static/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ const MAX_NAME_LEN = 50;
const SUIT_SYMBOL = { S: '♠', H: '♥', D: '♦', C: '♣' };
const SUIT_COLOR = { S: 'black', H: 'red', D: 'red', C: 'black' };

// Whole-round "huge profit" congrats popup (ported from v1.0.0). The server
// decides whether it fires (sends `congrats.profit_rate`); these are the
// display strings only.
const HUGE_PROFIT_POPUP = {
title: '🎉 Huge Profit! 🎉',
body: rate => `💵 ${rate}% Profit Rate 🍾`,
};

// ── State ──────────────────────────────────────────────────────────────────────
const state = {
balance: 0,
Expand Down Expand Up @@ -86,6 +94,7 @@ function enterBettingPhase() {
updateBetDisplay();
renderBalance(state.balance); // bets reset to 0; restore full balance
clearTable();
hideHugeProfit();
}

// Build the 1–6 count buttons
Expand Down Expand Up @@ -284,7 +293,12 @@ async function updateUI(data) {
renderHands(data.hands, data.phase);
showPhase('settled');
flashRoundResult(data.hands);
if (data.capital < MIN_BET) setTimeout(showGameOver, 2500);
if (data.capital < MIN_BET) {
setTimeout(showGameOver, 2500);
} else if (data.congrats) {
// One celebratory popup, after the dealer reveal + result flash.
setTimeout(() => showHugeProfit(data.congrats.profit_rate), 1800);
}
} else {
renderDealer(data.dealer);
renderHands(data.hands, data.phase);
Expand Down Expand Up @@ -641,6 +655,17 @@ function showGameOver() {
document.getElementById('gameover-modal').style.display = 'flex';
}

// ── Huge-profit congrats modal ─────────────────────────────────────────────────
function showHugeProfit(profitRate) {
document.getElementById('huge-profit-body').textContent =
HUGE_PROFIT_POPUP.body(profitRate);
document.getElementById('huge-profit-modal').style.display = 'flex';
}

function hideHugeProfit() {
document.getElementById('huge-profit-modal').style.display = 'none';
}

// ── GitHub modal ───────────────────────────────────────────────────────────────
function showGitHub() {
document.getElementById('github-modal').style.display = 'flex';
Expand Down
24 changes: 21 additions & 3 deletions static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@
<title>🎰MonkeyJOB's Here</title>
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@500&display=swap" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="/static/images/favicon.ico">
<link rel="stylesheet" href="/static/style.css?v=8">
<link rel="stylesheet" href="/static/style.css?v=11">
<link rel="manifest" href="/static/manifest.json">
</head>
<body>

<!-- ROTATE PROMPT (portrait only; landscape-only game) -->
<div class="rotate-overlay" id="rotate-overlay" role="alert">
<div class="rotate-msg">
<span class="rotate-icon" aria-hidden="true">📱</span>
<p>Please rotate your device to landscape to play.</p>
</div>
</div>

<!-- SESSION SETUP OVERLAY -->
<div class="session-overlay" id="session-overlay">
<div class="session-page-row">
Expand All @@ -32,7 +41,7 @@ <h2>♠️♥️MonkeyJOB♦️♣️<br>Jack's Online Blackjack</h2>

<!-- TOP BAR -->
<header class="topbar">
<div class="topbar-title">♠️♥️JOB: Jack's Online Blackjack♦️♣️</div>
<div class="topbar-title"><span class="tt-deco">♠️♥️</span>JOB<span class="tt-full">: Jack's Online Blackjack</span><span class="tt-deco">♦️♣️</span></div>
<div class="topbar-balance">Balance &nbsp;<span id="balance">$0</span></div>
<nav class="topbar-nav">
<button class="nav-btn" onclick="showRules()">👀Read Rules📖</button>
Expand Down Expand Up @@ -196,6 +205,15 @@ <h3 class="gameover-title">😏Game Over😏</h3>
</div>
</div>

<!-- HUGE PROFIT MODAL — whole-round ROI congrats; shown via JS when server flags it -->
<div class="hugeprofit-modal" id="huge-profit-modal" style="display:none;" onclick="hideHugeProfit()">
<div class="hugeprofit-card" onclick="event.stopPropagation()">
<h3 class="hugeprofit-title">🎉 Huge Profit! 🎉</h3>
<div class="hugeprofit-body" id="huge-profit-body"></div>
<button class="action-btn btn-deal hugeprofit-ok-btn" onclick="hideHugeProfit()">Keep Playing</button>
</div>
</div>

<!-- GITHUB MODAL -->
<div class="github-modal" id="github-modal" style="display:none;">
<div class="github-card">
Expand All @@ -216,6 +234,6 @@ <h3 class="gameover-title">😏Game Over😏</h3>
</div>
</div>

<script src="/static/app.js?v=6"></script>
<script src="/static/app.js?v=7"></script>
</body>
</html>
19 changes: 19 additions & 0 deletions static/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "MonkeyJOB",
"short_name": "MonkeyJOB",
"description": "Jack's Online Blackjack — a Macau-rules Blackjack game.",
"start_url": "/",
"scope": "/",
"display": "standalone",
"orientation": "landscape",
"background_color": "#0d1f14",
"theme_color": "#0d1f14",
"icons": [
{
"src": "/static/images/logo.png",
"sizes": "1024x1024",
"type": "image/png",
"purpose": "any"
}
]
}
Loading
Loading