Last active
May 19, 2018 00:42
-
-
Save mtcmorris/82bb025a2d70186e0ea43e3e95671b1c to your computer and use it in GitHub Desktop.
Always lynch randomly
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
require 'pry' | |
class Villager | |
def role_prevents_lynching? | |
false | |
end | |
def werewolf? | |
false | |
end | |
def seer? | |
false | |
end | |
end | |
class Seer < Villager | |
def initialize | |
@identified_players = [] | |
end | |
def role_prevents_lynching? | |
true | |
end | |
def identify_randomly(players) | |
identified_player = (players - @identified_players - [self]).sample | |
# We may have identified everyone... | |
if identified_player | |
@identified_players.push identified_player | |
end | |
end | |
def identified_werewolfs(active_players) | |
active_players.select{|p| | |
@identified_players.select(&:werewolf?).include?(p) | |
} | |
end | |
def identified_villagers(active_players) | |
active_players.select{|p| | |
@identified_players.reject(&:werewolf?).include?(p) | |
} | |
end | |
def seer? | |
true | |
end | |
def should_reveal?(players) | |
identified_werewolfs(players).count >= (players.select(&:werewolf?).count / 4) || | |
identified_villagers(players).count > (players.count / 4) | |
end | |
end | |
class Hunter < Villager | |
def role_prevents_lynching? | |
true | |
end | |
end | |
class Werewolf < Villager | |
def werewolf? | |
true | |
end | |
end | |
class Game | |
def initialize(werewolf_count:, villager_count:) | |
@players = [] | |
# A condemned villager has revealed their role and should be | |
# eaten next turn | |
@condemned_villagers = [] | |
# A condemned werewolf has been revealed by the seer and should | |
# be lynched next turn | |
@condemned_werewolfs = [] | |
werewolf_count.times do | |
@players << Werewolf.new | |
end | |
villager_count -= 1 | |
@players << Seer.new | |
villager_count -= 2 | |
@players << Hunter.new | |
@players << Hunter.new | |
villager_count.times do | |
@players << Villager.new | |
end | |
end | |
def run | |
while !game_over? do | |
eat_a_villager | |
identify_someone if seer | |
seer_reveals! if seer && seer.should_reveal?(@players) | |
lynch_someone | |
end | |
@outcome | |
end | |
def werewolfs | |
@players.select(&:werewolf?) | |
end | |
def villagers | |
@players.reject(&:werewolf?) | |
end | |
def seer | |
@players.detect(&:seer?) | |
end | |
def seer_reveals! | |
@condemned_villagers += seer.identified_villagers(@players) | |
@condemned_werewolfs += seer.identified_werewolfs(@players) | |
end | |
def eat_a_villager | |
eaten_villager = @condemned_villagers.shift || villagers.sample | |
@players = @players - [eaten_villager] | |
end | |
def identify_someone | |
seer.identify_randomly(@players) | |
end | |
def lynch_someone | |
lynched_person = @condemned_werewolfs.shift || (@players - @condemned_villagers).sample | |
if lynched_person.role_prevents_lynching? | |
@condemned_villagers.push lynched_person | |
lynched_person = (@players - [lynched_person]).sample | |
end | |
if lynched_person.seer? | |
seer_reveals! | |
end | |
@players = @players - [lynched_person] | |
end | |
def game_over? | |
if werewolfs.count >= villagers.count | |
@outcome = :werewolf_win | |
elsif @players.none?(&:werewolf?) | |
@outcome = :villagers_win | |
else | |
false | |
end | |
end | |
end | |
outcome = { | |
werewolf_win: 0, | |
villagers_win: 0 | |
} | |
10000.times do |t| | |
outcome[Game.new(werewolf_count: 4, villager_count: 16).run] += 1 | |
end | |
puts outcome.inspect |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment