Created
September 17, 2023 09:18
-
-
Save cschubiner/43f14d166248e23e10d23957dd07cb51 to your computer and use it in GitHub Desktop.
love letter simulator from GPT https://chat.openai.com/share/6e8762ec-e59f-41e5-afbd-252fceda9b30
This file contains 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
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