Skip to content

Instantly share code, notes, and snippets.

@mtcmorris
Last active May 19, 2018 00:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mtcmorris/82bb025a2d70186e0ea43e3e95671b1c to your computer and use it in GitHub Desktop.
Save mtcmorris/82bb025a2d70186e0ea43e3e95671b1c to your computer and use it in GitHub Desktop.
Always lynch randomly
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