From bbce6c58ec8b487171cf722079af4162ddcf48f9 Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Sat, 5 Apr 2025 19:58:14 -0400 Subject: [PATCH] play split modified: slop_with_models.py modified: streamlit_slop_with_models.py --- slop_with_models.py | 252 +++++++++++++++++++++++----------- streamlit_slop_with_models.py | 224 ++++++++++++++++++------------ 2 files changed, 307 insertions(+), 169 deletions(-) diff --git a/slop_with_models.py b/slop_with_models.py index 5673fb4..2b0e69d 100644 --- a/slop_with_models.py +++ b/slop_with_models.py @@ -408,18 +408,19 @@ def play_blackjack(bet, agent_id, game_id=None, action=None): game_state = { "agent_id": agent_id, "bet": bet, - "player_hand": player_hand, - "player_total": player_total, - "dealer_hand": dealer_hand, # Partial view - "dealer_total": sum(dealer_hand), # Only first card + "player_hands": [player_hand], # List to support splitting + "player_totals": [player_total], + "dealer_hand": dealer_hand, + "dealer_total": sum(dealer_hand), "status": "active", + "active_hand": 0, # Index of the current hand being played } update_resource(f"casino/blackjack/games/{game_id}", game_state) explanation = ( "Blackjack Rules: Bet to play against the dealer. Goal is to get closer to 21 without going over. " "Number cards = face value, Face cards = 10, Ace = 1 or 11 (adjusted automatically). " - "Hit to draw cards, stand to finish. Dealer stands on 17+. Win pays 2x, tie returns bet, loss takes bet. " + "Hit to draw cards, stand to finish, split if two cards match. Dealer stands on 17+. " f"You (agent {agent_id}) started a new game with bet {bet}. " f"Your hand: {player_hand} (Total: {player_total}). Dealer’s up card: {dealer_hand}." ) @@ -428,14 +429,15 @@ def play_blackjack(bet, agent_id, game_id=None, action=None): "explanation": explanation, "game_id": game_id, "game_state": { - "player_hand": player_hand, - "player_total": player_total, + "player_hands": [player_hand], + "player_totals": [player_total], "dealer_hand": dealer_hand, "dealer_total": sum(dealer_hand), + "can_split": len(player_hand) == 2 and player_hand[0] == player_hand[1], }, "bet": bet, "agent_id": agent_id, - "new_balance": wallet["balance"], # Not deducted yet + "new_balance": wallet["balance"], "game_complete": False, } @@ -443,11 +445,7 @@ def play_blackjack(bet, agent_id, game_id=None, action=None): game_key = f"casino/blackjack/games/{game_id}" with resource_lock: resources = load_resources_from_file() - logger.debug( - f"Checking for game {game_key} in resources: {list(resources.keys())}" - ) if game_key not in resources: - logger.warning(f"Game {game_id} not found in resources") return {"error": f"Game {game_id} not found"} game_state = resources[game_key]["content"] @@ -455,62 +453,115 @@ def play_blackjack(bet, agent_id, game_id=None, action=None): return {"error": "This game belongs to another agent"} if game_state["status"] != "active": return {"error": "This game is already complete"} - if action not in ["hit", "stand"]: - logger.warning(f"Invalid action '{action}' received for game {game_id}") - return {"error": "Action must be 'hit' or 'stand'"} + if action not in ["hit", "stand", "split"]: + return {"error": "Action must be 'hit', 'stand', or 'split'"} wallet = get_or_create_wallet(agent_id) cards = [2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 11] * 4 - if action == "hit": - game_state["player_hand"].append(random.choice(cards)) - game_state["player_total"] = sum(game_state["player_hand"]) - aces = game_state["player_hand"].count(11) - while game_state["player_total"] > 21 and aces > 0: - game_state["player_total"] -= 10 - aces -= 1 - - if game_state["player_total"] > 21: - game_state["status"] = "bust" - outcome = "Bust! You went over 21 and lose." - payout = 0 - result = "loss" - # Update wallet and stats on bust - wallet["balance"] = wallet["balance"] - game_state["bet"] - wallet["last_transaction"] = { - "game": "blackjack", - "bet": game_state["bet"], - "payout": payout, - "timestamp": datetime.now().isoformat(), + if ( + action == "split" + and len(game_state["player_hands"]) == 1 + and len(game_state["player_hands"][0]) == 2 + and game_state["player_hands"][0][0] == game_state["player_hands"][0][1] + ): + if wallet["balance"] < game_state["bet"] * 2: + return { + "error": f"Insufficient funds to split! Need {game_state['bet'] * 2}, have {wallet['balance']}" } - update_resource(f"casino/wallet/agent_{agent_id}", wallet) - stats = get_or_create_stats("blackjack", agent_id) - stats["games_played"] += 1 - stats["total_bet"] += game_state["bet"] - stats["total_won"] += payout - stats["losses"] += 1 - update_resource(f"casino/blackjack/stats/agent_{agent_id}", stats) - else: - outcome = "You hit. Game continues." - payout = 0 - result = "active" + hand = game_state["player_hands"][0] + game_state["player_hands"] = [[hand[0]], [hand[1]]] + game_state["player_hands"][0].append(random.choice(cards)) + game_state["player_hands"][1].append(random.choice(cards)) + game_state["player_totals"] = [ + sum(game_state["player_hands"][0]), + sum(game_state["player_hands"][1]), + ] + for i in range(2): + aces = game_state["player_hands"][i].count(11) + while game_state["player_totals"][i] > 21 and aces > 0: + game_state["player_totals"][i] -= 10 + aces -= 1 + game_state["bet"] *= 2 # Double the bet for two hands explanation = ( - "Blackjack: You chose to hit. " - f"Your hand: {game_state['player_hand']} (Total: {game_state['player_total']}). " - f"Dealer’s up card: {game_state['dealer_hand']}. {outcome}" + f"Blackjack: You chose to split your hand {hand}. " + f"Hand 1: {game_state['player_hands'][0]} (Total: {game_state['player_totals'][0]}). " + f"Hand 2: {game_state['player_hands'][1]} (Total: {game_state['player_totals'][1]}). " + f"Dealer’s up card: {game_state['dealer_hand']}. Game continues." ) - update_resource(game_key, game_state) return { "explanation": explanation, "game_id": game_id, "game_state": { - "player_hand": game_state["player_hand"], - "player_total": game_state["player_total"], + "player_hands": game_state["player_hands"], + "player_totals": game_state["player_totals"], "dealer_hand": game_state["dealer_hand"], "dealer_total": game_state["dealer_total"], + "can_split": False, # No further splitting after initial split + }, + "bet": game_state["bet"], + "agent_id": agent_id, + "new_balance": wallet["balance"], + "game_complete": False, + } + + if action == "hit": + active_hand = game_state["active_hand"] + game_state["player_hands"][active_hand].append(random.choice(cards)) + game_state["player_totals"][active_hand] = sum( + game_state["player_hands"][active_hand] + ) + aces = game_state["player_hands"][active_hand].count(11) + while game_state["player_totals"][active_hand] > 21 and aces > 0: + game_state["player_totals"][active_hand] -= 10 + aces -= 1 + + if game_state["player_totals"][active_hand] > 21: + if active_hand + 1 < len(game_state["player_hands"]): + game_state["active_hand"] += 1 # Move to next hand if split + outcome = ( + f"Bust on hand {active_hand + 1}! Moving to hand {active_hand + 2}." + ) + else: + game_state["status"] = "bust" + outcome = "Bust! You went over 21 and lose." + payout = 0 + wallet["balance"] -= game_state["bet"] + wallet["last_transaction"] = { + "game": "blackjack", + "bet": game_state["bet"], + "payout": payout, + "timestamp": datetime.now().isoformat(), + } + update_resource(f"casino/wallet/agent_{agent_id}", wallet) + stats = get_or_create_stats("blackjack", agent_id) + stats["games_played"] += 1 + stats["total_bet"] += game_state["bet"] + stats["total_won"] += payout + stats["losses"] += 1 + update_resource(f"casino/blackjack/stats/agent_{agent_id}", stats) + else: + outcome = f"You hit on hand {active_hand + 1}. Game continues." + payout = 0 + + explanation = ( + f"Blackjack: You chose to hit on hand {active_hand + 1}. " + f"Hand {active_hand + 1}: {game_state['player_hands'][active_hand]} (Total: {game_state['player_totals'][active_hand]}). " + f"Dealer’s up card: {game_state['dealer_hand']}. {outcome}" + ) + update_resource(game_key, game_state) + return { + "explanation": explanation, + "game_id": game_id, + "game_state": { + "player_hands": game_state["player_hands"], + "player_totals": game_state["player_totals"], + "dealer_hand": game_state["dealer_hand"], + "dealer_total": game_state["dealer_total"], + "can_split": False, }, "bet": game_state["bet"], "agent_id": agent_id, @@ -519,6 +570,31 @@ def play_blackjack(bet, agent_id, game_id=None, action=None): } if action == "stand": + active_hand = game_state["active_hand"] + if active_hand + 1 < len(game_state["player_hands"]): + game_state["active_hand"] += 1 # Move to next hand if split + explanation = ( + f"Blackjack: You chose to stand on hand {active_hand + 1}. " + f"Hand {active_hand + 1}: {game_state['player_hands'][active_hand]} (Total: {game_state['player_totals'][active_hand]}). " + f"Dealer’s up card: {game_state['dealer_hand']}. Moving to hand {active_hand + 2}." + ) + update_resource(game_key, game_state) + return { + "explanation": explanation, + "game_id": game_id, + "game_state": { + "player_hands": game_state["player_hands"], + "player_totals": game_state["player_totals"], + "dealer_hand": game_state["dealer_hand"], + "dealer_total": game_state["dealer_total"], + "can_split": False, + }, + "bet": game_state["bet"], + "agent_id": agent_id, + "new_balance": wallet["balance"], + "game_complete": False, + } + # Reveal dealer’s full hand while len(game_state["dealer_hand"]) < 2: game_state["dealer_hand"].append(random.choice(cards)) @@ -531,29 +607,37 @@ def play_blackjack(bet, agent_id, game_id=None, action=None): game_state["dealer_total"] -= 10 aces -= 1 - if game_state["dealer_total"] > 21: - outcome = "Dealer busts! You win!" - payout = game_state["bet"] * 2 - result = "win" - elif game_state["player_total"] > game_state["dealer_total"]: - outcome = "Your total beats the dealer's! You win!" - payout = game_state["bet"] * 2 - result = "win" - elif game_state["dealer_total"] > game_state["player_total"]: - outcome = "Dealer’s total beats yours. You lose." - payout = 0 - result = "loss" - else: - outcome = "Push! It’s a tie, your bet is returned." - payout = game_state["bet"] - result = "tie" + # Resolve all hands + outcomes = [] + payouts = [] + bet_per_hand = game_state["bet"] // len(game_state["player_hands"]) + for i, total in enumerate(game_state["player_totals"]): + if game_state["dealer_total"] > 21: + outcome = f"Hand {i + 1}: Dealer busts! You win!" + payout = bet_per_hand * 2 + result = "win" + elif total > game_state["dealer_total"]: + outcome = f"Hand {i + 1}: Your total beats the dealer's! You win!" + payout = bet_per_hand * 2 + result = "win" + elif game_state["dealer_total"] > total: + outcome = f"Hand {i + 1}: Dealer’s total beats yours. You lose." + payout = 0 + result = "loss" + else: + outcome = f"Hand {i + 1}: Push! It’s a tie, your bet is returned." + payout = bet_per_hand + result = "tie" + outcomes.append(outcome) + payouts.append(payout) game_state["status"] = "complete" - wallet["balance"] = wallet["balance"] - game_state["bet"] + payout + total_payout = sum(payouts) + wallet["balance"] = wallet["balance"] - game_state["bet"] + total_payout wallet["last_transaction"] = { "game": "blackjack", "bet": game_state["bet"], - "payout": payout, + "payout": total_payout, "timestamp": datetime.now().isoformat(), } update_resource(f"casino/wallet/agent_{agent_id}", wallet) @@ -561,37 +645,41 @@ def play_blackjack(bet, agent_id, game_id=None, action=None): stats = get_or_create_stats("blackjack", agent_id) stats["games_played"] += 1 stats["total_bet"] += game_state["bet"] - stats["total_won"] += payout - if result == "win": - stats["wins"] += 1 - elif result == "loss": - stats["losses"] += 1 - else: - stats["ties"] += 1 + stats["total_won"] += total_payout + for result in [o.split(": ")[1].split("!")[0] for o in outcomes]: + if "win" in result.lower(): + stats["wins"] += 1 + elif "lose" in result.lower(): + stats["losses"] += 1 + else: + stats["ties"] += 1 update_resource(f"casino/blackjack/stats/agent_{agent_id}", stats) update_resource(game_key, game_state) explanation = ( "Blackjack: You chose to stand. " - f"Your hand: {game_state['player_hand']} (Total: {game_state['player_total']}). " - f"Dealer’s hand: {game_state['dealer_hand']} (Total: {game_state['dealer_total']}). {outcome}" + f"Your hands: {', '.join([f'Hand {i+1}: {h} (Total: {t})' for i, (h, t) in enumerate(zip(game_state['player_hands'], game_state['player_totals']))])}. " + f"Dealer’s hand: {game_state['dealer_hand']} (Total: {game_state['dealer_total']}). " + f"{' '.join(outcomes)}" ) return { "explanation": explanation, "game_id": game_id, "game_state": { - "player_hand": game_state["player_hand"], - "player_total": game_state["player_total"], + "player_hands": game_state["player_hands"], + "player_totals": game_state["player_totals"], "dealer_hand": game_state["dealer_hand"], "dealer_total": game_state["dealer_total"], + "can_split": False, }, - "payout": payout, + "payout": total_payout, "bet": game_state["bet"], "agent_id": agent_id, "new_balance": wallet["balance"], "game_complete": True, + "outcomes": outcomes, } diff --git a/streamlit_slop_with_models.py b/streamlit_slop_with_models.py index 0757d0e..73cb6fc 100644 --- a/streamlit_slop_with_models.py +++ b/streamlit_slop_with_models.py @@ -199,7 +199,7 @@ def tools_interface(): ) st.write(f"**Game Started**: {result['explanation']}") st.write( - f"**Your Hand**: {result['game_state']['player_hand']} (Total: {result['game_state']['player_total']})" + f"**Your Hand**: {result['game_state']['player_hands'][0]} (Total: {result['game_state']['player_totals'][0]})" ) st.write( f"**Dealer’s Up Card**: {result['game_state']['dealer_hand']}" @@ -209,10 +209,7 @@ def tools_interface(): st.error(f"Error starting blackjack: {str(e)}") logger.error(f"Error starting blackjack: {str(e)}", exc_info=True) else: - # Display current game state and allow hit/stand - logger.debug( - f"Fetching game state for game_id: {st.session_state.blackjack_game_id}" - ) + # Display current game state and allow hit/stand/split try: response = requests.get( f"{BASE_URL}/resources/casino/blackjack/games/{st.session_state.blackjack_game_id}", @@ -226,98 +223,151 @@ def tools_interface(): st.write( f"**Current Game (ID: {st.session_state.blackjack_game_id})**:" ) - st.write( - f"**Your Hand**: {game_state['player_hand']} (Total: {game_state['player_total']})" - ) + for i, (hand, total) in enumerate( + zip(game_state["player_hands"], game_state["player_totals"]) + ): + active = ( + " (Active)" + if i == game_state["active_hand"] + and game_state["status"] == "active" + else "" + ) + st.write(f"**Hand {i + 1}{active}**: {hand} (Total: {total})") st.write(f"**Dealer’s Up Card**: {game_state['dealer_hand']}") - st.write(f"**Bet**: {game_state['bet']}") + st.write(f"**Total Bet**: {game_state['bet']}") - col1, col2 = st.columns(2) - with col1: - if st.button("Hit"): - logger.debug( - f"Sending hit action for game_id: {st.session_state.blackjack_game_id}" - ) - try: - response = requests.post( - f"{BASE_URL}/tools/blackjack", - json={ - "agent_id": agent_id, - "game_id": st.session_state.blackjack_game_id, - "action": "hit", - }, - timeout=5, - ) + if game_state["status"] == "active": + col1, col2, col3 = st.columns(3) + with col1: + if st.button("Hit"): logger.debug( - f"POST /tools/blackjack (hit) status: {response.status_code}, content: {response.text}" + f"Sending hit action for game_id: {st.session_state.blackjack_game_id}" ) - response.raise_for_status() - result = response.json() - if "error" in result: - st.error(f"Error: {result['error']}") - logger.error(f"Hit error: {result['error']}") - else: - st.write(f"**Result**: {result['explanation']}") - if result["game_complete"]: - st.write( - f"**Payout**: {result.get('payout', 'N/A')}" - ) - st.write( - f"**New Balance**: {result['new_balance']}" - ) - st.session_state.blackjack_game_id = None - logger.debug( - "Game completed, reset blackjack_game_id to None" - ) - st.rerun() - except requests.RequestException as e: - st.error(f"Error during hit: {str(e)}") - logger.error(f"Error during hit: {str(e)}", exc_info=True) - with col2: - if st.button("Stand"): - logger.debug( - f"Sending stand action for game_id: {st.session_state.blackjack_game_id}" - ) - try: - response = requests.post( - f"{BASE_URL}/tools/blackjack", - json={ - "agent_id": agent_id, - "game_id": st.session_state.blackjack_game_id, - "action": "stand", - }, - timeout=5, - ) - logger.debug( - f"POST /tools/blackjack (stand) status: {response.status_code}, content: {response.text}" - ) - response.raise_for_status() - result = response.json() - if "error" in result: - st.error(f"Error: {result['error']}") - logger.error(f"Stand error: {result['error']}") - else: - st.write(f"**Result**: {result['explanation']}") - st.write( - f"**Your Hand**: {result['game_state']['player_hand']} (Total: {result['game_state']['player_total']})" + try: + response = requests.post( + f"{BASE_URL}/tools/blackjack", + json={ + "agent_id": agent_id, + "game_id": st.session_state.blackjack_game_id, + "action": "hit", + }, + timeout=5, ) - st.write( - f"**Dealer’s Hand**: {result['game_state']['dealer_hand']} (Total: {result['game_state']['dealer_total']})" - ) - st.write(f"**Payout**: {result['payout']}") - st.write(f"**New Balance**: {result['new_balance']}") - st.session_state.blackjack_game_id = None logger.debug( - "Game completed, reset blackjack_game_id to None" + f"POST /tools/blackjack (hit) status: {response.status_code}, content: {response.text}" + ) + response.raise_for_status() + result = response.json() + if "error" in result: + st.error(f"Error: {result['error']}") + logger.error(f"Hit error: {result['error']}") + else: + st.write(f"**Result**: {result['explanation']}") + if result["game_complete"]: + st.write(f"**Payout**: {result['payout']}") + st.write( + f"**New Balance**: {result['new_balance']}" + ) + st.session_state.blackjack_game_id = None + logger.debug( + "Game completed, reset blackjack_game_id to None" + ) + st.rerun() + except requests.RequestException as e: + st.error(f"Error during hit: {str(e)}") + logger.error( + f"Error during hit: {str(e)}", exc_info=True + ) + with col2: + if st.button("Stand"): + logger.debug( + f"Sending stand action for game_id: {st.session_state.blackjack_game_id}" + ) + try: + response = requests.post( + f"{BASE_URL}/tools/blackjack", + json={ + "agent_id": agent_id, + "game_id": st.session_state.blackjack_game_id, + "action": "stand", + }, + timeout=5, + ) + logger.debug( + f"POST /tools/blackjack (stand) status: {response.status_code}, content: {response.text}" + ) + response.raise_for_status() + result = response.json() + if "error" in result: + st.error(f"Error: {result['error']}") + logger.error(f"Stand error: {result['error']}") + else: + st.write(f"**Result**: {result['explanation']}") + if result["game_complete"]: + for outcome in result["outcomes"]: + if "win" in outcome.lower(): + st.success(outcome) + elif "lose" in outcome.lower(): + st.error(outcome) + else: + st.warning(outcome) + st.write( + f"**Total Payout**: {result['payout']}" + ) + st.write( + f"**New Balance**: {result['new_balance']}" + ) + st.session_state.blackjack_game_id = None + logger.debug( + "Game completed, reset blackjack_game_id to None" + ) + st.rerun() + except requests.RequestException as e: + st.error(f"Error during stand: {str(e)}") + logger.error( + f"Error during stand: {str(e)}", exc_info=True + ) + with col3: + can_split = ( + len(game_state["player_hands"]) == 1 + and len(game_state["player_hands"][0]) == 2 + and game_state["player_hands"][0][0] + == game_state["player_hands"][0][1] + ) + if can_split and st.button("Split"): + logger.debug( + f"Sending split action for game_id: {st.session_state.blackjack_game_id}" + ) + try: + response = requests.post( + f"{BASE_URL}/tools/blackjack", + json={ + "agent_id": agent_id, + "game_id": st.session_state.blackjack_game_id, + "action": "split", + }, + timeout=5, + ) + logger.debug( + f"POST /tools/blackjack (split) status: {response.status_code}, content: {response.text}" + ) + response.raise_for_status() + result = response.json() + if "error" in result: + st.error(f"Error: {result['error']}") + logger.error(f"Split error: {result['error']}") + else: + st.write(f"**Result**: {result['explanation']}") + st.rerun() + except requests.RequestException as e: + st.error(f"Error during split: {str(e)}") + logger.error( + f"Error during split: {str(e)}", exc_info=True ) - st.rerun() - except requests.RequestException as e: - st.error(f"Error during stand: {str(e)}") - logger.error(f"Error during stand: {str(e)}", exc_info=True) except requests.RequestException as e: st.error(f"Error fetching game state: {str(e)}") logger.error(f"Error fetching game state: {str(e)}", exc_info=True) - st.session_state.blackjack_game_id = None # Reset if game not found + st.session_state.blackjack_game_id = None logger.debug("Reset blackjack_game_id to None due to fetch error")