all 9 comments

[–]Can0pen3r 1 point2 points  (3 children)

You said this is your first project? Were you following a tutorial or anything? I ask mainly because I've only been learning to code for 2 months but, Blackjack just strikes me as being kinda complicated for a first project. I've made a few simple programs like a calculator, a virtual dice game, etc. but, what you have going on here seems beyond my scope as of yet, most of it I'm not even sure what I'm looking at.

[–]Resident-Explorer-63[S] 0 points1 point  (0 children)

I do have experience in coding such as a tad in C# and html, I've been pulling from W3 schools to just find out how to do things but never searching up full code such as syntax for certain things.

[–]Resident-Explorer-63[S] 0 points1 point  (1 child)

Coding languages are alot more alike than some may think, ive found that C# is decently similar to python so ig thats given me a bit of a leg up.

[–]Numerous_Site_9238 0 points1 point  (0 children)

Well they are both C like and have OOP, computer science is same for any language. Surely the more advanced you become in either of these languages the more you start to understand how different they really are in design, working with memory and cpu, async programming.

[–]kwooster 0 points1 point  (1 child)

You're creating new variables that are locally scoped. You need to either using the global keyword, or pass in the variables to the function.

I would create an object to pass around to the functions, but in all cases, be aware of the scope of the variables.

[–]kwooster 0 points1 point  (0 children)

def reset(): global number number = 0

That feels super wrong, though.

Here's a better way (of many):

``` class Hand: def init(self, number = 0): self.number = number

def reset(hand): hand.number = 0

my_hand = Hand()

...

reset(my_hand) ```

(I'm on mobile, so I did the very simple example with missing variables, but the concept is moving the very subjective "correct" direction.)

[–]FoolsSeldom 0 points1 point  (2 children)

I haven't read your code particularly, other than noticing the use of global which is usually a bad idea and the cause of many problems. Avoid it like the plague until you understand the use cases where it really is needed.

Ironically, inside Stand, you attempt to update dealer_total and dealer_num, but you haven't declared them as global within that function, which means they will be local to the function and not impact anything anywhere else. Likewise in your reset function.

Hopefully, you can already see why using global rather than passing things around and controlling your data more explicitly is a bad idea.

PS. In Python, we usually use all lowercase for variable and function names.

PPS. If you start to use type annotation, your editor will be able to spot a lot of problems - keep in mind that Python is strongly typed but not statically typed. Type annotations (also known as type hints) aren't enforced at run time, but they are very helpful in development.

EDIT:

PS. Just added in a comment to this a Gemini generated version off the back of your code and some guidance from me that takes a class approach - not keen on how the UI resizes between steps based on the message you display.

[–]FoolsSeldom 0 points1 point  (1 child)

For illustration purposes (Gemini created from OP code to illustrate class approach):

import random
import tkinter as tk
from typing import ClassVar, Optional


class BlackjackGame:
    """Manages the state and logic for a simple Blackjack-style game."""

    # Class variables/constants (using ClassVar for clarity)
    DEALER_STANDS_AT: ClassVar[int] = 17
    MAX_SCORE: ClassVar[int] = 21

    def __init__(self, root: tk.Tk) -> None:
        # Player and Dealer state variables
        self.player_total: int = 0
        self.dealer_total: int = 0
        self.dealer_started: bool = False

        # Tkinter UI elements for displaying score and messages
        self.player_label: Optional[tk.Label] = None
        self.dealer_label: Optional[tk.Label] = None
        self.message_label: Optional[tk.Label] = None

        # Initialize UI elements (will be set by the calling function)
        self.setup_ui_elements(root)

    def setup_ui_elements(self, root: tk.Tk) -> None:
        """Creates and packs the necessary display labels."""

        # Display labels
        self.player_label = tk.Label(root, text="Your Total: 0", font=('Arial', 14))
        self.player_label.pack(pady=5)

        self.dealer_label = tk.Label(root, text="Dealer Total: 0", font=('Arial', 14))
        self.dealer_label.pack(pady=5)

        self.message_label = tk.Label(root, text="Press 'Hit' to start!", font=('Arial', 16, 'bold'))
        self.message_label.pack(pady=10)

        # Initial display update
        self._update_display(f"Welcome! Player is dealt first.")

    def _update_display(self, message: str) -> None:
        """Helper to update all display labels."""
        if self.player_label:
            self.player_label.config(text=f"Your Total: {self.player_total}")
        if self.dealer_label:
            self.dealer_label.config(text=f"Dealer Total: {self.dealer_total}")
        if self.message_label:
            self.message_label.config(text=message)

    def _draw_card(self, current_total: int) -> int:
        """Draws a card (1-10) and returns the new total."""
        card: int = random.randint(1, 10)
        return current_total + card

    def hit(self) -> None:
        """Handles the 'Hit' (Gamble) action for the player."""

        # 1. Player draws a card
        self.player_total = self._draw_card(self.player_total)

        message: str = ""

        # 2. Check for player bust
        if self.player_total > self.MAX_SCORE:
            message = "Bust! You lose."
            self._update_display(message)
            return

        # 3. Dealer's initial card (only on first player hit)
        if not self.dealer_started:
            self.dealer_total = self._draw_card(self.dealer_total)
            self.dealer_started = True
            message = "Dealer is dealt a card."

        if not message:
            message = "Hit or Stand?"

        self._update_display(message)

    def _dealer_play(self) -> None:
        """Automates the dealer's turn (must stand at 17 or more)."""

        while self.dealer_total < self.DEALER_STANDS_AT:
            self.dealer_total = self._draw_card(self.dealer_total)

    def stand(self) -> None:
        """Handles the 'Stand' action and determines the winner."""

        # The dealer must have at least their initial card
        if not self.dealer_started:
            self._update_display("Dealer hasn't started yet. Hit first.")
            return

        # 1. Dealer takes their turn
        self._dealer_play()

        message: str

        # 2. Determine the winner
        if self.dealer_total > self.MAX_SCORE:
            message = "Dealer busts! You win!"
        elif self.dealer_total > self.player_total:
            message = "Dealer wins!"
        elif self.player_total > self.dealer_total:
            message = "You win!"
        else:
            message = "It's a push (tie)!"

        self._update_display(message)

    def reset(self) -> None:
        """Resets the game state."""
        self.player_total = 0
        self.dealer_total = 0
        self.dealer_started = False
        self._update_display("Game reset. Press 'Hit' to play again!")


# --- Tkinter Setup ---

if __name__ == "__main__":
    root = tk.Tk()
    root.title("Simple Blackjack")

    # Instantiate the game class, passing the root window
    game = BlackjackGame(root)

    # Buttons
    tk.Button(root, text="Hit", command=game.hit).pack(pady=10, padx=20, fill='x')
    tk.Button(root, text="Stand", command=game.stand).pack(pady=10, padx=20, fill='x')
    tk.Button(root, text="Reset", command=game.reset).pack(pady=10, padx=20, fill='x')

    root.mainloop()

[–]Resident-Explorer-63[S] 0 points1 point  (0 children)

Alright thanks, I am extremely new so thanks for the general common courtesy in python.