Skip to content

Commit

Permalink
feat: Updated to fix bug #3, and added pre-commit linting, type check…
Browse files Browse the repository at this point in the history
…, and pytests, complete with refactor to make the codebase compliant.
  • Loading branch information
samholt committed Dec 26, 2024
1 parent c16dc44 commit 2ad39de
Show file tree
Hide file tree
Showing 39 changed files with 5,263 additions and 2,770 deletions.
51 changes: 45 additions & 6 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
default_stages: [ commit ]
default_stages: [pre-commit]
exclude: '.*__init__\.py$'

# Install
Expand All @@ -21,10 +21,49 @@ repos:
rev: v0.0.284
hooks:
- id: ruff
args: [ --fix ]
args: [--fix]

- repo: https://github.com/psf/black
rev: 23.3.0
# - repo: https://github.com/psf/black
# rev: 23.3.0
# hooks:
# - id: black
# args: ['--line-length', '80'] # Adhere to Google Style Guide

- repo: https://github.com/pre-commit/mirrors-yapf
rev: v0.32.0
hooks:
- id: yapf
args: ['--style', '{based_on_style: google, column_limit: 80, indent_width: 2}'] # Google Style with 2 spaces
additional_dependencies: [configparser] # Ensures compatibility

- repo: local
hooks:
- id: pylint
name: Pylint (Google Style)
entry: pylint
args: ['--rcfile=pylintrc']
language: system
types: [python]


- repo: https://github.com/google/pytype
rev: 2024.10.11
hooks:
- id: pytype
name: Pytype (Type Checking)
entry: pytype
args: ['--disable=import-error', '--config=pytype.cfg']
language: python
types: [python]
always_run: true

- repo: local
hooks:
- id: black
args: ['--line-length', '120']
- id: pytest
name: Run Pytest
entry: pytest
args: ['tests']
language: system
pass_filenames: false
always_run: true
verbose: true
2 changes: 2 additions & 0 deletions .style.yapf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[style]
indent_width = 2
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ For detailed installation guidance, please refer to [installation](https://samho
You can init the config of L2MAC by running the following command, or manually create `~/.L2MAC/config.yaml` file:
```bash
# Check https://samholt.github.io/L2MAC/guide/get_started/configuration.html for more details
l2mac --init-config # it will create ~/.l2mac/config.yaml, just modify it to your needs
l2mac --init-config "" # it will create ~/.l2mac/config.yaml, just modify it to your needs
```

You can configure `~/.l2mac/config.yaml` according to the [example](https://github.com/samholt/L2MAC/blob/master/config/config.yaml) and [doc](https://samholt.github.io/L2MAC/guide/get_started/configuration.html):
Expand Down
204 changes: 108 additions & 96 deletions docs/generated_examples/blackjack_game/blackjack.py
Original file line number Diff line number Diff line change
@@ -1,119 +1,131 @@
# pylint: skip-file
# pytype: skip-file
import random


# Define the Card class
class Card:
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank

@property
def value(self):
return {
"2": 2,
"3": 3,
"4": 4,
"5": 5,
"6": 6,
"7": 7,
"8": 8,
"9": 9,
"10": 10,
"J": 10,
"Q": 10,
"K": 10,
"A": 11,
}[self.rank]
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank

@property
def value(self):
return {
"2": 2,
"3": 3,
"4": 4,
"5": 5,
"6": 6,
"7": 7,
"8": 8,
"9": 9,
"10": 10,
"J": 10,
"Q": 10,
"K": 10,
"A": 11,
}[self.rank]


# Define the Deck class
class Deck:
def __init__(self):
self.cards = [
Card(suit, rank)
for suit in ["Hearts", "Diamonds", "Clubs", "Spades"]
for rank in [str(n) for n in range(2, 11)] + ["J", "Q", "K", "A"]
]
random.shuffle(self.cards)
def __init__(self):
self.cards = [
Card(suit, rank) for suit in ["Hearts", "Diamonds", "Clubs", "Spades"]
for rank in [str(n) for n in range(2, 11)] + ["J", "Q", "K", "A"]
]
random.shuffle(self.cards)

def deal_card(self):
return self.cards.pop()
def deal_card(self):
return self.cards.pop()


# Define the Hand class
class Hand:
def __init__(self):
self.cards = []
self.value = 0
self.aces = 0
def __init__(self):
self.cards = []
self.value = 0
self.aces = 0

def add_card(self, card):
self.cards.append(card)
self.value += card.value
if card.rank == "A":
self.aces += 1
def add_card(self, card):
self.cards.append(card)
self.value += card.value
if card.rank == "A":
self.aces += 1

def adjust_for_ace(self):
while self.value > 21 and self.aces:
self.value -= 10
self.aces -= 1
def adjust_for_ace(self):
while self.value > 21 and self.aces:
self.value -= 10
self.aces -= 1


# Define the Game class
class Game:
def __init__(self):
self.deck = Deck()
self.player_hand = Hand()
self.dealer_hand = Hand()

def start_game(self):
print("Welcome to Blackjack!")
self.player_hand.add_card(self.deck.deal_card())
self.player_hand.add_card(self.deck.deal_card())
self.dealer_hand.add_card(self.deck.deal_card())
self.dealer_hand.add_card(self.deck.deal_card())
self.show_hands()
self.player_turn()
self.dealer_turn()
self.show_result()

def player_turn(self):
while input("Hit or Stand? (h/s): ").lower() == "h":
self.player_hand.add_card(self.deck.deal_card())
self.player_hand.adjust_for_ace()
self.show_hands()
if self.player_hand.value > 21:
print("Player busts!")
return
self.dealer_turn()

def dealer_turn(self):
while self.dealer_hand.value < 17:
self.dealer_hand.add_card(self.deck.deal_card())
self.dealer_hand.adjust_for_ace()

def show_hands(self):
print("Player's Hand:", *[f"{card.rank} of {card.suit}" for card in self.player_hand.cards])
print("Dealer's Hand:", *[f"{card.rank} of {card.suit}" for card in self.dealer_hand.cards[:1]], "and [HIDDEN]")

def show_result(self):
self.adjust_final_hands()
print("Final Hands:")
self.show_hands()
if self.player_hand.value > 21:
print("Dealer wins!")
elif self.dealer_hand.value > 21 or self.player_hand.value > self.dealer_hand.value:
print("Player wins!")
elif self.player_hand.value < self.dealer_hand.value:
print("Dealer wins!")
else:
print("It's a tie!")

def adjust_final_hands(self):
self.player_hand.adjust_for_ace()
self.dealer_hand.adjust_for_ace()
def __init__(self):
self.deck = Deck()
self.player_hand = Hand()
self.dealer_hand = Hand()

def start_game(self):
print("Welcome to Blackjack!")
self.player_hand.add_card(self.deck.deal_card())
self.player_hand.add_card(self.deck.deal_card())
self.dealer_hand.add_card(self.deck.deal_card())
self.dealer_hand.add_card(self.deck.deal_card())
self.show_hands()
self.player_turn()
self.dealer_turn()
self.show_result()

def player_turn(self):
while input("Hit or Stand? (h/s): ").lower() == "h":
self.player_hand.add_card(self.deck.deal_card())
self.player_hand.adjust_for_ace()
self.show_hands()
if self.player_hand.value > 21:
print("Player busts!")
return
self.dealer_turn()

def dealer_turn(self):
while self.dealer_hand.value < 17:
self.dealer_hand.add_card(self.deck.deal_card())
self.dealer_hand.adjust_for_ace()

def show_hands(self):
print(
"Player's Hand:",
*[f"{card.rank} of {card.suit}" for card in self.player_hand.cards],
)
print(
"Dealer's Hand:",
*[
f"{card.rank} of {card.suit}"
for card in self.dealer_hand.cards[:1]
],
"and [HIDDEN]",
)

def show_result(self):
self.adjust_final_hands()
print("Final Hands:")
self.show_hands()
if self.player_hand.value > 21:
print("Dealer wins!")
elif (self.dealer_hand.value > 21
or self.player_hand.value > self.dealer_hand.value):
print("Player wins!")
elif self.player_hand.value < self.dealer_hand.value:
print("Dealer wins!")
else:
print("It's a tie!")

def adjust_final_hands(self):
self.player_hand.adjust_for_ace()
self.dealer_hand.adjust_for_ace()


if __name__ == "__main__":
game = Game()
game.start_game()
game = Game()
game.start_game()
60 changes: 32 additions & 28 deletions docs/generated_examples/blackjack_game/test_blackjack.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,45 @@
# pylint: skip-file
# pytype: skip-file
from blackjack import Card, Deck, Game, Hand


def test_card_value():
assert Card("Hearts", "2").value == 2
assert Card("Hearts", "A").value == 11
assert Card("Hearts", "2").value == 2
assert Card("Hearts", "A").value == 11


def test_deck_deal_card():
deck = Deck()
assert isinstance(deck.deal_card(), Card)
assert len(deck.cards) == 51
deck = Deck()
assert isinstance(deck.deal_card(), Card)
assert len(deck.cards) == 51


def test_hand_add_card_and_value():
hand = Hand()
hand.add_card(Card("Hearts", "2"))
hand.add_card(Card("Hearts", "3"))
assert hand.value == 5
assert hand.aces == 0
hand.add_card(Card("Hearts", "A"))
assert hand.value == 16
assert hand.aces == 1
hand = Hand()
hand.add_card(Card("Hearts", "2"))
hand.add_card(Card("Hearts", "3"))
assert hand.value == 5
assert hand.aces == 0
hand.add_card(Card("Hearts", "A"))
assert hand.value == 16
assert hand.aces == 1


def test_game_flow():
game = Game()
# Mocking the player and dealer turns to simulate game flow without user input
game.player_turn = lambda: None
game.dealer_turn = lambda: None
game.start_game()
# Assuming the game starts with two cards each for player and dealer
assert len(game.player_hand.cards) == 2
assert len(game.dealer_hand.cards) == 2
# Adjusting for ace should be tested in a scenario where it affects the outcome
hand = Hand()
hand.add_card(Card("Hearts", "A"))
hand.add_card(Card("Hearts", "9"))
hand.add_card(Card("Hearts", "2")) # Total would be 22, but ace adjustment should bring it to 12
hand.adjust_for_ace()
assert hand.value == 12
game = Game()
# Mocking the player and dealer turns to simulate game flow without user input
game.player_turn = lambda: None
game.dealer_turn = lambda: None
game.start_game()
# Assuming the game starts with two cards each for player and dealer
assert len(game.player_hand.cards) == 2
assert len(game.dealer_hand.cards) == 2
# Adjusting for ace should be tested in a scenario where it affects the outcome
hand = Hand()
hand.add_card(Card("Hearts", "A"))
hand.add_card(Card("Hearts", "9"))
hand.add_card(
Card("Hearts",
"2")) # Total would be 22, but ace adjustment should bring it to 12
hand.adjust_for_ace()
assert hand.value == 12
Loading

0 comments on commit 2ad39de

Please sign in to comment.