Skip to content

Instantly share code, notes, and snippets.

@dado3212
Created September 7, 2026 20:29
Show Gist options
  • Select an option

  • Save dado3212/2b7a36f571b0a5a112ab72fe393c2a64 to your computer and use it in GitHub Desktop.

Select an option

Save dado3212/2b7a36f571b0a5a112ab72fe393c2a64 to your computer and use it in GitHub Desktop.
Ride the Bus testing v2.0
import itertools, random
from statistics import mean, median, pstdev
suits = ["Spades", "Diamonds", "Hearts", "Clubs"]
values = ["Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"]
class InfiDeck:
def __init__(self):
self.deck = self.new_deck()
self.new_decks = 0
self.cards = 0
def new_deck(self):
cards = list(itertools.product(suits, values))
random.shuffle(cards)
deck = []
for card in cards:
deck.append(Card(card[0], card[1]))
return deck
def get_card(self):
self.cards += 1
card = self.deck.pop()
if len(self.deck) == 0:
self.deck = self.new_deck()
self.new_decks += 1
return card
class Card:
def __init__(self, suit, value):
self.suit = suit
self.value = value
if (suit in ["Hearts", "Diamonds"]):
self.color = "Red"
else:
self.color = "Black"
def val(self):
return values.index(self.value)
def __repr__(self):
return self.value + " of " + self.suit
class Game:
def __init__(self):
self.first = 0
self.first_correct = 0
self.second = 0
self.second_correct = 0
self.third = 0
self.third_correct = 0
self.fourth = 0
self.fourth_correct = 0
def stats(self):
return {
'first': self.first,
'first_correct': self.first_correct,
'second': self.second,
'second_correct': self.second_correct,
'third': self.third,
'third_correct': self.third_correct,
'fourth': self.fourth,
'fourth_correct': self.fourth_correct,
}
# Color needs to match
def correct_color(self, card, choice):
self.first += 1
correct = card.color == choice
if (correct):
self.first_correct += 1
return correct
def over_under(self, card1, card2, over = True):
self.second += 1
# Ties are failures
if card2.val() == card1.val():
return False
if over:
correct = card2.val() > card1.val()
else:
correct = card2.val() < card1.val()
if (correct):
self.second_correct += 1
return correct
def inside_outside(self, card1, card2, card3, outside = True):
self.third += 1
# Ties are failures
if card3.val() == card1.val() or card3.val() == card2.val():
return False
if card1.val() < card2.val():
inside_range = range(card1.val() + 1, card2.val())
else:
inside_range = range(card2.val() + 1, card1.val())
if outside:
correct = card3.val() not in inside_range
else:
correct = card3.val() in inside_range
if (correct):
self.third_correct += 1
return correct
def correct_suit(self, card, guess):
self.fourth += 1
correct = (card.suit == guess)
if (correct):
self.fourth_correct += 1
return correct
class DumbPlayer:
def choose_color(self, deck):
return random.choice(["Red", "Black"])
# Above 7 guess lower, below 7 guess higher, 7 guess randomly
def guess_higher(self, deck, card1):
if (card1.val() == 6):
return random.choice([True, False])
else:
return card1.val() < 6
def guess_outside(self, deck, card1, card2):
return (abs(card2.val() - card1.val()) <= 6)
def guess_suit(self, deck):
return random.choice(suits)
class SmartPlayer:
def choose_color(self, deck):
num_red = 0
num_black = 0
for card in deck.deck:
if card.color == "Red":
num_red += 1
else:
num_black += 1
if num_red > num_black:
return "Red"
else:
return "Black"
def guess_higher(self, deck, card1):
higher = 0
lower = 0
for card in deck.deck:
if card.val() > card1.val():
higher += 1
elif card.val() < card1.val():
lower += 1
# equal = dead card, counts for neither
return higher > lower
def guess_outside(self, deck, card1, card2):
low, high = sorted([card1.val(), card2.val()])
in_range = 0
out_of_range = 0
for card in deck.deck:
v = card.val()
if v == low or v == high:
continue # dead card
elif low < v < high:
in_range += 1
else:
out_of_range += 1
return in_range < out_of_range
def guess_suit(self, deck):
suits_count = {
"Diamonds": 0,
"Hearts": 0,
"Spades": 0,
"Clubs": 0
}
for card in deck.deck:
suits_count[card.suit] += 1
return max(suits_count, key=suits_count.get)
def play_game():
game = Game()
deck = InfiDeck()
player = SmartPlayer() # or DumbPlayer()
drinks = 0
finished = False
while not finished:
# Guess the suit
color = player.choose_color(deck)
card1 = deck.get_card()
if (game.correct_color(card1, color)):
# Guess higher/lower
guess_higher = player.guess_higher(deck, card1)
card2 = deck.get_card()
if game.over_under(card1, card2, guess_higher):
# Guess inside_outside
guess_outside = player.guess_outside(deck, card1, card2)
card3 = deck.get_card()
if game.inside_outside(card1, card2, card3, guess_outside):
# Guess the suit
guess_suit = player.guess_suit(deck)
card4 = deck.get_card()
if game.correct_suit(card4, guess_suit):
finished = True
else:
drinks += 1
else:
drinks += 1
else:
drinks += 1
else:
drinks += 1
stats = {
'drinks': drinks,
'cards': deck.cards,
}
stats.update(game.stats())
return stats
aggregated_results = {}
all_results = []
count = 1000000
for i in range(count):
result = play_game()
all_results.append(result)
for stat in result:
if stat in aggregated_results:
aggregated_results[stat] += result[stat]
else:
aggregated_results[stat] = result[stat]
for key in sorted(all_results[0].keys()):
col = [r[key] for r in all_results]
print(key)
print(" mean: %.4f" % mean(col))
print(" median: %s" % median(col))
print(" stdev: %.4f" % pstdev(col))
if 'correct' in key:
base = key[:-8]
print(" rate: %d%%" % round(sum(col) / sum(r[base] for r in all_results) * 100))
print("")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment