Skip to content

Instantly share code, notes, and snippets.

@cschubiner
Created September 17, 2023 09:18
Show Gist options
  • Save cschubiner/43f14d166248e23e10d23957dd07cb51 to your computer and use it in GitHub Desktop.
Save cschubiner/43f14d166248e23e10d23957dd07cb51 to your computer and use it in GitHub Desktop.
from random import shuffle, choice
# Initialize players and cards
players = [{'hand': [], 'protected': False, 'eliminated': False} for _ in range(4)]
initial_deck = [1] * 5 + [2] * 2 + [3] * 2 + [4] * 2 + [5] * 2 + [6] * 1 + [7] * 1 + [
8] * 1 # Card counts based on Love Letter rules
def simulate_one_round(starting_card):
# Shuffle the deck and draw initial cards for players
deck = initial_deck.copy()
shuffle(deck)
deck.pop() # Remove one card from play
# Reset players
for player in players:
player['hand'] = []
player['protected'] = False
player['eliminated'] = False
# Give the first player the starting card of choice
players[0]['hand'] = [starting_card]
# Draw initial card for other players
for i, player in enumerate(players[1:]):
player['hand'] = [deck.pop()]
# Main game loop
while len(deck) > 0 and sum([not p['eliminated'] for p in players]) > 1:
for i, player in enumerate(players):
if player['eliminated'] or len(deck) == 0:
continue
# Draw a card
player['hand'].append(deck.pop() if len(deck) > 0 else None)
# Must play Countess if holding King or Prince
if 7 in player['hand'] and (5 in player['hand'] or 6 in player['hand']):
card_to_play = 7
else:
# Player would never choose to play the princess
# Check if there are cards other than 8 in the player's hand
valid_cards = [x for x in player['hand'] if x != 8]
if valid_cards:
card_to_play = choice(valid_cards)
else:
# If only card 8 is present, play it
card_to_play = 8
# Remove the played card from hand
player['hand'].remove(card_to_play)
# Card effects
available_targets = [p for j, p in enumerate(players) if
j != i and not p['eliminated'] and not p['protected']]
if card_to_play == 1 and available_targets: # Guard
target = choice(available_targets)
guess = choice([x for x in range(2, 9)])
if guess in target['hand']:
target['eliminated'] = True
elif card_to_play == 2: # Priest
pass
elif card_to_play == 3 and available_targets: # Baron
target = choice(available_targets)
if player['hand'][0] < target['hand'][0]:
player['eliminated'] = True
else:
target['eliminated'] = True
elif card_to_play == 4: # Handmaid
player['protected'] = True
elif card_to_play == 5: # Prince
target = choice(players)
# If the Prince discards someone else's princess that target is eliminated
if 8 in target['hand']:
target['eliminated'] = True
else:
target['hand'] = [deck.pop() if len(deck) > 0 else None]
elif card_to_play == 6 and available_targets: # King
target = choice(available_targets)
player['hand'], target['hand'] = target['hand'], player['hand']
elif card_to_play == 7: # Countess
pass
elif card_to_play == 8: # Princess
player['eliminated'] = True
# Reset protection for all players
for p in players:
p['protected'] = False
# Determine winner
remaining_players = [p for p in players if not p['eliminated']]
if len(remaining_players) > 1:
winner_card = max([p['hand'][0] for p in remaining_players if p['hand'][0] is not None])
winner = [i for i, p in enumerate(players) if p['hand'][0] == winner_card][0]
elif len(remaining_players) == 1:
winner = [i for i, p in enumerate(players) if not p['eliminated']][0]
else:
winner = None
return winner
if __name__ == '__main__':
# Run the full simulation based on the updated rules and effects of the cards
# Initialize win count dictionary for each possible starting card for the first player
win_counts_starting_card = {card: 0 for card in range(1, 9)}
# Run the simulation 5,000 times for each of the 9 possible starting cards for the first player
n_simulations = 5000*20
for starting_card in range(1, 9):
for _ in range(n_simulations):
winner = simulate_one_round(starting_card)
if winner == 0: # Check if the first player won
win_counts_starting_card[starting_card] += 1
# Print the results
card_to_pretty_name = {
1: 'Guard',
2: 'Priest',
3: 'Baron',
4: 'Handmaid',
5: 'Prince',
6: 'King',
7: 'Countess',
8: 'Princess',
}
print(f'Win counts for {n_simulations} simulations:')
for starting_card, win_count in win_counts_starting_card.items():
print(f'Starting card: {card_to_pretty_name[starting_card]} ({starting_card}) - {win_count} wins')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment