diff --git a/.github/workflows/black-lint.yml b/.github/workflows/black-lint.yml index 311edbe..21c7f51 100644 --- a/.github/workflows/black-lint.yml +++ b/.github/workflows/black-lint.yml @@ -3,12 +3,8 @@ name: Black Lint on: push: branches: [main, dev] - paths: - - '**/*.py' pull_request: branches: [main] - paths: - - '**/*.py' workflow_dispatch: concurrency: diff --git a/.gitignore b/.gitignore index 89304cb..e96a541 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .claude/ +CLAUDE.md + *.pyc __pychache__/ .pytest_cache/ diff --git a/PWA.md b/PWA.md new file mode 100644 index 0000000..1fbbcaa --- /dev/null +++ b/PWA.md @@ -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 ๐ diff --git a/README.md b/README.md index 3b55098..8669a90 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,23 @@ # ๐ฐMonkeyJOB: Jack's Online Blackjack +[](./PWA.md) + +[](https://www.jack-s-onlineblackjack.com) +[](https://www.jack-s-onlineblackjack.com) + +[](https://www.jack-s-onlineblackjack.com) +[](https://www.jack-s-onlineblackjack.com) + +### ๐ฐ๏ธ Metadata + [](https://github.com/StarsExpress/MonkeyJOB/actions) [](https://github.com/StarsExpress/MonkeyJOB/actions) [](https://github.com/StarsExpress/MonkeyJOB/actions) -[](https://github.com/StarsExpress/MonkeyJOB/actions) +[](https://github.com/StarsExpress/MonkeyJOB/actions) +[](https://github.com/StarsExpress/MonkeyJOB/releases) + +--- ### [๐คต๐ป Let's Have A Seat ๐ต](https://www.jack-s-onlineblackjack.com) diff --git a/blackjack.py b/blackjack.py index 7211511..7c4d8ec 100644 --- a/blackjack.py +++ b/blackjack.py @@ -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 @@ -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. @@ -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() @@ -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": [ @@ -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 diff --git a/configs/bets_config.py b/configs/bets_config.py index bcca43d..f766368 100644 --- a/configs/bets_config.py +++ b/configs/bets_config.py @@ -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 diff --git a/static/app.js b/static/app.js index 94ec1e5..5ef64eb 100644 --- a/static/app.js +++ b/static/app.js @@ -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, @@ -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 @@ -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); @@ -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'; diff --git a/static/index.html b/static/index.html index 6d9a06b..7e2d407 100644 --- a/static/index.html +++ b/static/index.html @@ -6,10 +6,19 @@