mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-02 00:00:14 -08:00
Remove tests and alternative Python implementations
Ad discussed here: https://github.com/coding-horror/basic-computer-games/issues/548#issuecomment-1081008471
This commit is contained in:
@@ -1,136 +0,0 @@
|
||||
"""
|
||||
AceyDuchy
|
||||
|
||||
From: BASIC Computer Games (1978)
|
||||
Edited by David Ahl
|
||||
|
||||
"The original BASIC program author was Bill Palmby
|
||||
of Prairie View, Illinois."
|
||||
|
||||
Python port by Aviyam Fischer, 2022
|
||||
"""
|
||||
|
||||
from typing import List, Literal, TypeAlias, get_args
|
||||
|
||||
Suit: TypeAlias = Literal["\u2665", "\u2666", "\u2663", "\u2660"]
|
||||
Rank: TypeAlias = Literal[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
|
||||
|
||||
|
||||
class Card:
|
||||
def __init__(self, suit: Suit, rank: Rank) -> None:
|
||||
self.suit = suit
|
||||
self.rank = rank
|
||||
|
||||
def __str__(self) -> str:
|
||||
r = str(self.rank)
|
||||
r = {"11": "J", "12": "Q", "13": "K", "14": "A"}.get(r, r)
|
||||
return f"{r}{self.suit}"
|
||||
|
||||
|
||||
class Deck:
|
||||
def __init__(self) -> None:
|
||||
self.cards: List[Card] = []
|
||||
self.build()
|
||||
|
||||
def build(self) -> None:
|
||||
for suit in get_args(Suit):
|
||||
for rank in get_args(Rank):
|
||||
self.cards.append(Card(suit, rank))
|
||||
|
||||
def shuffle(self) -> None:
|
||||
import random
|
||||
|
||||
random.shuffle(self.cards)
|
||||
|
||||
def deal(self) -> Card:
|
||||
return self.cards.pop()
|
||||
|
||||
|
||||
class Game:
|
||||
def __init__(self) -> None:
|
||||
self.deck = Deck()
|
||||
self.deck.shuffle()
|
||||
self.card_a = self.deck.deal()
|
||||
self.card_b = self.deck.deal()
|
||||
self.money = 100
|
||||
self.not_done = True
|
||||
|
||||
def play(self) -> None:
|
||||
while self.not_done:
|
||||
while self.money > 0:
|
||||
card_a = self.card_a
|
||||
card_b = self.card_b
|
||||
|
||||
if card_a.rank > card_b.rank:
|
||||
card_a, card_b = card_b, card_a
|
||||
|
||||
if card_a.rank == card_b.rank:
|
||||
self.card_b = self.deck.deal()
|
||||
card_b = self.card_b
|
||||
|
||||
print(f"You have:\t ${self.money} ")
|
||||
print(f"Your cards:\t {card_a} {card_b}")
|
||||
|
||||
bet = int(input("What is your bet? "))
|
||||
player_card = self.deck.deal()
|
||||
if 0 < bet <= self.money:
|
||||
|
||||
print(f"Your deal:\t {player_card}")
|
||||
if card_a.rank < player_card.rank < card_b.rank:
|
||||
print("You Win!")
|
||||
self.money += bet
|
||||
else:
|
||||
print("You Lose!")
|
||||
self.money -= bet
|
||||
self.not_done = False
|
||||
else:
|
||||
print("Chicken!")
|
||||
print(f"Your deal should have been: {player_card}")
|
||||
if card_a.rank < player_card.rank < card_b.rank:
|
||||
print("You could have won!")
|
||||
else:
|
||||
print("You would lose, so it was wise of you to chicken out!")
|
||||
|
||||
self.not_done = False
|
||||
break
|
||||
|
||||
if len(self.deck.cards) <= 3:
|
||||
print("You ran out of cards. Game over.")
|
||||
self.not_done = False
|
||||
break
|
||||
|
||||
self.card_a = self.deck.deal()
|
||||
self.card_b = self.deck.deal()
|
||||
|
||||
if self.money == 0:
|
||||
self.not_done = False
|
||||
|
||||
|
||||
def game_loop() -> None:
|
||||
game_over = False
|
||||
|
||||
while not game_over:
|
||||
game = Game()
|
||||
game.play()
|
||||
print(f"You have ${game.money} left")
|
||||
print("Would you like to play again? (y/n)")
|
||||
if input() == "n":
|
||||
game_over = True
|
||||
|
||||
|
||||
def main():
|
||||
print(
|
||||
"""
|
||||
Acey Ducey is a card game where you play against the computer.
|
||||
The Dealer(computer) will deal two cards facing up.
|
||||
You have an option to bet or not bet depending on whether or not you
|
||||
feel the card will have a value between the first two.
|
||||
If you do not want to bet input a 0
|
||||
"""
|
||||
)
|
||||
game_loop()
|
||||
print("\nThanks for playing!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,212 +0,0 @@
|
||||
"""aceyducey.py contains game code"""
|
||||
########################################################
|
||||
#
|
||||
# Acey Ducey
|
||||
#
|
||||
# From: BASIC Computer Games (1978)
|
||||
# Edited by David Ahl
|
||||
#
|
||||
# "This is a simulation of the Acey Ducey card game.
|
||||
# In the game, the dealer (the computer) deals two
|
||||
# cards face up. You have an option to bet or not to
|
||||
# bet depending on whether or not you feel the next
|
||||
# card dealt will have a value between the first two.
|
||||
#
|
||||
# "Your initial money is set to $100. The game keeps
|
||||
# going on until you lose all your money or interrupt
|
||||
# the program.
|
||||
#
|
||||
# "The original BASIC program author was Bill Palmby
|
||||
# of Prairie View, Illinois."
|
||||
#
|
||||
# Python port by Jeff Jetton, 2019
|
||||
#
|
||||
########################################################
|
||||
|
||||
|
||||
import random
|
||||
|
||||
# "You may alter [the following statement] if you want
|
||||
# to start with more or less than $100."
|
||||
DEFAULT_BANKROLL = 100
|
||||
|
||||
|
||||
def deal_card_num() -> int:
|
||||
"""Get card number"""
|
||||
return random.randint(0, 12)
|
||||
|
||||
|
||||
def get_card_name(number: int) -> str:
|
||||
"""Get card name"""
|
||||
card_names = (
|
||||
" 2",
|
||||
" 3",
|
||||
" 4",
|
||||
" 5",
|
||||
" 6",
|
||||
" 7",
|
||||
" 8",
|
||||
" 9",
|
||||
" 10",
|
||||
"Jack",
|
||||
"Queen",
|
||||
"King",
|
||||
"Ace",
|
||||
)
|
||||
return card_names[number]
|
||||
|
||||
|
||||
def display_bankroll(bank_roll: int) -> None:
|
||||
"""Print current bankroll"""
|
||||
if bank_roll > 0:
|
||||
print(f"You now have {bank_roll} dollars\n")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Display initial title and instructions."""
|
||||
print("\n Acey Ducey Card Game")
|
||||
print("Creative Computing Morristown, New Jersey")
|
||||
print("\n\n")
|
||||
print("Acey-Ducey is played in the following manner")
|
||||
print("The dealer (computer) deals two cards face up")
|
||||
print("You have an option to bet or not bet depending")
|
||||
print("on whether or not you feel the card will have")
|
||||
print("a value between the first two.")
|
||||
print("If you do not want to bet, input a 0")
|
||||
|
||||
multiple_game_loop()
|
||||
|
||||
print("OK Hope you had fun\n")
|
||||
|
||||
|
||||
def multiple_game_loop() -> None:
|
||||
"""Loop for series of multiple games."""
|
||||
keep_playing = True
|
||||
while keep_playing:
|
||||
# Initialize bankroll at start of each game
|
||||
BANK_ROLL = DEFAULT_BANKROLL
|
||||
display_bankroll(BANK_ROLL)
|
||||
|
||||
single_round(BANK_ROLL)
|
||||
|
||||
print("\n\nSorry, friend but you blew your wad")
|
||||
player_response = input("Try again (yes or no) ")
|
||||
if player_response.lower() == "yes":
|
||||
print()
|
||||
else:
|
||||
keep_playing = False
|
||||
|
||||
|
||||
def single_round(BANK_ROLL: int) -> None:
|
||||
"""Loop for a single round. Repeat until out of money."""
|
||||
while BANK_ROLL > 0:
|
||||
# Deal out dealer cards
|
||||
print("Here are your next two cards")
|
||||
dealer1 = deal_card_num()
|
||||
# If the cards match, we redeal 2nd card until they don't
|
||||
dealer2 = dealer1
|
||||
while dealer1 == dealer2:
|
||||
dealer2 = deal_card_num()
|
||||
# Organize the cards in order if they're not already
|
||||
if dealer1 >= dealer2:
|
||||
(dealer1, dealer2) = (dealer2, dealer1) # Ya gotta love Python!
|
||||
# Show dealer cards to the player
|
||||
# (use card name rather than internal number)
|
||||
print(get_card_name(dealer1))
|
||||
print(get_card_name(dealer2) + "\n")
|
||||
|
||||
# Get and handle player bet choice
|
||||
BET_IS_VALID = False
|
||||
while not BET_IS_VALID:
|
||||
curr_bet_str = input("What is your bet? ")
|
||||
try:
|
||||
curr_bet = int(curr_bet_str)
|
||||
except ValueError:
|
||||
# Bad input? Just loop back up and ask again...
|
||||
pass
|
||||
else:
|
||||
if curr_bet == 0:
|
||||
BET_IS_VALID = True
|
||||
print("Chicken!!\n")
|
||||
elif curr_bet > BANK_ROLL:
|
||||
print("Sorry, my friend but you bet too much")
|
||||
print(f"You have only {BANK_ROLL} dollars to bet\n")
|
||||
else:
|
||||
# Deal player card
|
||||
BET_IS_VALID = True
|
||||
player = deal_card_num()
|
||||
print(get_card_name(player))
|
||||
|
||||
# Did we win?
|
||||
if dealer1 < player < dealer2:
|
||||
print("You win!!!")
|
||||
BANK_ROLL += curr_bet
|
||||
else:
|
||||
print("Sorry, you lose")
|
||||
BANK_ROLL -= curr_bet
|
||||
|
||||
# Update player on new bankroll level
|
||||
display_bankroll(BANK_ROLL)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
########################################################
|
||||
#
|
||||
# Porting notes:
|
||||
#
|
||||
# The original BASIC version had a variable named N
|
||||
# that was initialized to 100 and then never used.
|
||||
# Maybe it did something in feature that was edited
|
||||
# out of the final version used in the book?
|
||||
#
|
||||
# The original program simply generated random numbers
|
||||
# for each card. It did not simulate a true card deck,
|
||||
# where the dealing of a card eliminates it from the
|
||||
# deck and reduces the chances of the same value
|
||||
# being drawn. This "infinite deck" logic (or "deal,
|
||||
# with replacement after") has NOT been changed.
|
||||
#
|
||||
# In the interests of historical fidelity, the bug
|
||||
# in the original BASIC listing that let you input a
|
||||
# negative bet value has been faithfully reproduced.
|
||||
# This lets the player lose money when they win and
|
||||
# earn money when they lose! :-)
|
||||
#
|
||||
#
|
||||
# Ideas for Modifications
|
||||
#
|
||||
# Give the user the ability to quit the game, perhaps
|
||||
# by typing "quit" instead of making a bet. Provide a
|
||||
# final assessment based on how much of the original
|
||||
# bankroll they have left.
|
||||
#
|
||||
# Or have the game run for a set number of rounds or
|
||||
# until a certain bankroll goal is attained.
|
||||
#
|
||||
# Implement an "ante"--a set amount the player has to
|
||||
# bet each time rather than having the option to lay
|
||||
# out entirely.
|
||||
#
|
||||
# See "porting notes" above about negative bet values.
|
||||
# How would you fix this?
|
||||
#
|
||||
# When the player "chickens out", show them what the
|
||||
# next card would've been and point out whether they
|
||||
# made a good or bad decision.
|
||||
#
|
||||
# In what situations are the odds of winning high
|
||||
# enough to justify making a bet? Create a cheat mode
|
||||
# where the program identifies these situations and
|
||||
# lets the player know.
|
||||
#
|
||||
# Change the card dealing to simulate deals from a
|
||||
# single deck (or a user-selectable number of decks).
|
||||
#
|
||||
# Implement a two-player mode where players take turns
|
||||
# betting (or both bet on the same dealer cards and
|
||||
# get their own player card dealt).
|
||||
#
|
||||
########################################################
|
||||
@@ -1,29 +0,0 @@
|
||||
import io
|
||||
from unittest import mock
|
||||
from typing import TypeVar
|
||||
from _pytest.capture import CaptureFixture
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
|
||||
from acey_ducey import play_game
|
||||
|
||||
|
||||
@mock.patch("random.shuffle")
|
||||
def test_play_game_lose(
|
||||
mock_random_shuffle, monkeypatch: MonkeyPatch, capsys: CaptureFixture
|
||||
) -> None:
|
||||
monkeypatch.setattr("sys.stdin", io.StringIO("100\n100"))
|
||||
T = TypeVar("T")
|
||||
|
||||
def identity(x: T) -> T:
|
||||
return x
|
||||
|
||||
mock_random_shuffle = identity # noqa: F841
|
||||
play_game()
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == (
|
||||
"You now have 100 dollars\n\n"
|
||||
"Here are you next two cards\n King\n Ace\n\n"
|
||||
"What is your bet? Queen\n"
|
||||
"Sorry, you lose\n"
|
||||
"Sorry, friend, but you blew your wad\n"
|
||||
)
|
||||
@@ -1,36 +0,0 @@
|
||||
from acey_ducey_oo import Card, Deck, Game
|
||||
|
||||
|
||||
def test_card_init() -> None:
|
||||
card = Card("\u2665", 2)
|
||||
assert card.suit == "\u2665"
|
||||
assert card.rank == 2
|
||||
|
||||
|
||||
def test_card_str() -> None:
|
||||
card = Card("\u2665", 2)
|
||||
assert str(card) == "2\u2665"
|
||||
|
||||
|
||||
def test_deck_init() -> None:
|
||||
deck = Deck()
|
||||
assert len(deck.cards) == 52
|
||||
assert deck.cards[0].suit == "\u2665"
|
||||
assert deck.cards[0].rank == 2
|
||||
|
||||
|
||||
def test_deck_shuffle() -> None:
|
||||
deck = Deck()
|
||||
deck.shuffle()
|
||||
|
||||
|
||||
def test_deck_deal() -> None:
|
||||
deck = Deck()
|
||||
card = deck.deal()
|
||||
assert card.rank == 14
|
||||
assert card.suit == "\u2660"
|
||||
|
||||
|
||||
def test_game_init() -> None:
|
||||
game = Game()
|
||||
assert len(game.deck.cards) == 50 # two are already dealt
|
||||
Reference in New Issue
Block a user