Created
September 7, 2026 20:29
-
-
Save dado3212/2b7a36f571b0a5a112ab72fe393c2a64 to your computer and use it in GitHub Desktop.
Ride the Bus testing v2.0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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