├── README.md ├── blackjack.py └── qlearning.py /README.md: -------------------------------------------------------------------------------- 1 | # AI-Blackjack 2 | 3 | # 💻 Launch Your Software Development Career Today! 4 | 5 | 🎓 **No degree? No problem!** My program equips you with everything you need to break into tech and land an entry-level software development role. 6 | 7 | 🚀 **Why Join?** 8 | - 💼 **$70k+ starting salary potential** 9 | - 🕐 **Self-paced:** Complete on your own time 10 | - 🤑 **Affordable:** Low risk compared to expensive bootcamps or degrees 11 | - 🎯 **45,000+ job openings** in the market 12 | 13 | 👉 **[Start your journey today!](https://techwithtim.net/dev)** 14 | No experience needed—just your determination. Future-proof your career and unlock six-figure potential like many of our students have! 15 | -------------------------------------------------------------------------------- /blackjack.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | class BlackjackGame: 4 | 5 | heart = "\u2665" 6 | spade = "\u2660" 7 | diamond = "\u2666" 8 | club = "\u2663" 9 | 10 | suits = { 11 | "diamonds": diamond, 12 | "hearts": heart, 13 | "spades": spade, 14 | "clubs": club 15 | } 16 | 17 | def __init__(self): 18 | self.deck = self.generate_deck() 19 | random.shuffle(self.deck) 20 | self.player_hand = [] 21 | self.dealer_hand = [] 22 | 23 | @staticmethod 24 | def generate_deck(): 25 | numbers = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'] 26 | suits = ['hearts', 'diamonds', 'clubs', 'spades'] 27 | deck = [{'number': number, 'suit': suit} for number in numbers for suit in suits] 28 | return deck 29 | 30 | def deal_card(self): 31 | return self.deck.pop() 32 | 33 | def start_game(self): 34 | self.player_hand = [self.deal_card(), self.deal_card()] 35 | self.dealer_hand = [self.deal_card(), self.deal_card()] 36 | 37 | @staticmethod 38 | def hand_value(hand): 39 | value = 0 40 | aces = 0 41 | for card in hand: 42 | if card['number'] in ['J', 'Q', 'K']: 43 | value += 10 44 | elif card['number'] == 'A': 45 | value += 11 46 | aces += 1 47 | else: 48 | value += int(card['number']) 49 | 50 | while value > 21 and aces: 51 | value -= 10 52 | aces -= 1 53 | return value 54 | 55 | def player_action(self, action): 56 | if action == "hit": 57 | self.player_hand.append(self.deal_card()) 58 | return self.game_status() 59 | 60 | def dealer_action(self, output=False): 61 | while self.hand_value(self.dealer_hand) < 17: 62 | self.dealer_hand.append(self.deal_card()) 63 | if output: 64 | print("Dealer hits and has:", self.format_cards(self.dealer_hand), self.hand_value(self.dealer_hand)) 65 | 66 | def game_status(self): 67 | player_value = self.hand_value(self.player_hand) 68 | if player_value > 21: 69 | return "player_bust" 70 | elif player_value == 21: 71 | return "player_blackjack" 72 | else: 73 | return "continue" 74 | 75 | def game_result(self): 76 | self.dealer_action() 77 | player_value = self.hand_value(self.player_hand) 78 | dealer_value = self.hand_value(self.dealer_hand) 79 | 80 | if player_value > 21: 81 | return "loss" 82 | elif dealer_value > 21 or player_value > dealer_value: 83 | return "win" 84 | elif player_value == dealer_value: 85 | return "draw" 86 | else: 87 | return "loss" 88 | 89 | @staticmethod 90 | def format_cards(cards): 91 | result = "" 92 | for card in cards: 93 | suit = BlackjackGame.suits[card["suit"]] 94 | result += f"{card['number']}{suit} " 95 | 96 | return result.strip() 97 | 98 | game = BlackjackGame() 99 | game.start_game() 100 | 101 | def main(): 102 | print("Dealer shows:", game.format_cards(game.dealer_hand[:1])) 103 | 104 | status = "continue" 105 | while status == "continue": 106 | print(game.format_cards(game.player_hand), game.hand_value(game.player_hand)) 107 | action = input("Enter an action (hit/stay): ") 108 | status = game.player_action(action) 109 | 110 | if action == "stay": 111 | break 112 | 113 | if status == "continue": 114 | print("Dealer has:", game.format_cards(game.dealer_hand), game.hand_value(game.dealer_hand)) 115 | game.dealer_action() 116 | 117 | print(game.game_result()) 118 | 119 | if __name__ == "__main__": 120 | main() 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /qlearning.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from blackjack import BlackjackGame 3 | 4 | class BlackjackQLearning: 5 | def __init__(self, alpha=0.1, gamma=0.9, epsilon=0.1): 6 | self.alpha = alpha 7 | self.gamma = gamma 8 | self.epsilon = epsilon 9 | 10 | # Initialize Q-table 11 | self.Q = np.zeros((33, 12, 2, 2)) # Player sum, dealer card, action 12 | 13 | def choose_action(self, player_sum, dealer_card, usable_ace): 14 | if np.random.uniform(0, 1) < self.epsilon: 15 | return np.random.choice(["hit", "stay"]) 16 | else: 17 | return "hit" if self.Q[player_sum, dealer_card, usable_ace, 0] > self.Q[player_sum, dealer_card, usable_ace, 1] else "stay" 18 | 19 | def update(self, player_sum, dealer_card, usable_ace, action, reward, new_player_sum, new_dealer_card, new_usable_ace): 20 | action_idx = 0 if action == "hit" else 1 21 | old_value = self.Q[player_sum, dealer_card, usable_ace, action_idx] 22 | future_max = np.max(self.Q[new_player_sum, new_dealer_card, new_usable_ace]) 23 | self.Q[player_sum, dealer_card, usable_ace, action_idx] = old_value + self.alpha * (reward + self.gamma * future_max - old_value) 24 | 25 | @staticmethod 26 | def has_usable_ace(hand): 27 | """Check if the hand has a usable ace.""" 28 | value, ace = 0, False 29 | for card in hand: 30 | card_number = card['number'] 31 | value += min(10, int(card_number) if card_number not in ['J', 'Q', 'K', 'A'] else 11) 32 | ace |= (card_number == 'A') 33 | return int(ace and value + 10 <= 21) 34 | 35 | def train(self, episodes): 36 | one_percent = round(episodes / 100) 37 | 38 | for ep in range(episodes): 39 | game = BlackjackGame() 40 | game.start_game() 41 | 42 | if ep % one_percent == 0: 43 | progress = (ep/episodes) * 100 44 | print(f"Training progress: {progress:.2f}%") 45 | 46 | 47 | dealer_card = int(game.dealer_hand[0]['number']) if game.dealer_hand[0]['number'] not in ['J', 'Q', 'K', 'A'] else (10 if game.dealer_hand[0]['number'] != 'A' else 11) 48 | status = "continue" 49 | 50 | while status == "continue": 51 | player_sum = game.hand_value(game.player_hand) 52 | usable_ace = self.has_usable_ace(game.player_hand) 53 | action = self.choose_action(player_sum, dealer_card, usable_ace) 54 | status = game.player_action(action) 55 | new_player_sum = game.hand_value(game.player_hand) 56 | new_usable_ace = self.has_usable_ace(game.player_hand) 57 | 58 | reward = 0 # Intermediate reward, only final matters 59 | 60 | if status == "player_blackjack": 61 | reward = 1 62 | elif status == "player_bust": 63 | reward = -1 64 | 65 | if reward != 0: 66 | self.update(player_sum, dealer_card, usable_ace, action, reward, new_player_sum, dealer_card, new_usable_ace) 67 | 68 | if action == "stay": 69 | break 70 | 71 | final_result = game.game_result() 72 | final_reward = 1 if final_result == "win" else (-1 if final_result == "loss" else 0) 73 | self.update(player_sum, dealer_card, usable_ace, action, final_reward, new_player_sum, dealer_card, new_usable_ace) 74 | 75 | def play(self): 76 | game = BlackjackGame() 77 | game.start_game() 78 | 79 | print("Dealer shows:", game.format_cards(game.dealer_hand[:1])) 80 | 81 | status = "continue" 82 | print(game.format_cards(game.player_hand), game.hand_value(game.player_hand)) 83 | while status == "continue": 84 | player_sum = game.hand_value(game.player_hand) 85 | usable_ace = self.has_usable_ace(game.player_hand) 86 | dealer_card = int(game.dealer_hand[0]['number']) if game.dealer_hand[0]['number'] not in ['J', 'Q', 'K', 'A'] else (10 if game.dealer_hand[0]['number'] != 'A' else 11) 87 | action = "hit" if self.Q[player_sum, dealer_card, usable_ace, 0] > self.Q[player_sum, dealer_card, usable_ace, 1] else "stay" 88 | status = game.player_action(action) 89 | 90 | if action == "stay": 91 | break 92 | 93 | print(game.format_cards(game.player_hand), game.hand_value(game.player_hand)) 94 | 95 | 96 | if status == "continue": 97 | print("Dealer has:", game.format_cards(game.dealer_hand), game.hand_value(game.dealer_hand)) 98 | game.dealer_action() 99 | 100 | final_result = game.game_result() 101 | return final_result 102 | 103 | 104 | # Train the agent 105 | agent = BlackjackQLearning() 106 | agent.train(5000000) 107 | 108 | test_games = 1000000 109 | wins = 0 110 | losses = 0 111 | draws = 0 112 | 113 | for _ in range(test_games): 114 | print("-----") 115 | result = agent.play() 116 | print(result) 117 | if result == "win": 118 | wins += 1 119 | elif result == "loss": 120 | losses += 1 121 | else: 122 | draws += 1 123 | 124 | print(f"Wins: {wins}, Losses: {losses}, Draws: {draws}") 125 | print(f"Win rate: {wins/(wins + losses)*100:.2f}%") 126 | --------------------------------------------------------------------------------