Skip to content

Instantly share code, notes, and snippets.

@jido
Last active June 19, 2016 19:52
Show Gist options
  • Save jido/9e34b7a5302654253be678ddbb221664 to your computer and use it in GitHub Desktop.
Save jido/9e34b7a5302654253be678ddbb221664 to your computer and use it in GitHub Desktop.
Hung program
# An implementation of the Mafia party game state machine.
import "lib/enum" =~ [=> makeEnum]
exports (makeMafia, DAY, NIGHT)
def [MafiaState :DeepFrozen,
DAY :DeepFrozen,
NIGHT :DeepFrozen] := makeEnum(["day", "night"])
def makeMafia(var players :Set, randgen) as DeepFrozen:
# Initial mafioso count.
def mafiosoCount :Int := players.size() // 3
def sample(population :List, k :(Int <= population.size())) :List: # Why : not as?
def n := population.size()
def indexes := [].diverge()
while (indexes.size() < k):
if (!indexes.contains(def index := randgen.nextInt(n))):
indexes.push(index)
return [for index in (indexes) population[index]]
var mafiosi :Set := sample(players.asList(), mafiosoCount).asSet()
var innocents :Set := players - mafiosi # Set arithmetic
var state :MafiaState := NIGHT
var day := 0
var votes :Map := [].asMap() # Empty Map
object mafia:
to _printOn(out) :Void:
def mafiaSize :Int := mafiosi.size()
def playerSize :Int := players.size()
out.print(`<Mafia: $playerSize players, `)
def winner := mafia.getWinner()
if (winner == null):
out.print(`$state $day>`)
else:
out.print(`winner $winner>`)
to getState() :MafiaState:
return state
to getQuorum() :Int:
return switch (state) {
match ==DAY { (mafiosi.size() + innocents.size() + 1) // 2 }
match ==NIGHT { mafiosi.size() }
}
to getMafiaCount() :Int:
return mafiosoCount
to getWinner() :Str:
if (mafiosi.size() == 0):
return "village"
if (mafiosi.size() > innocents.size()):
return "mafia"
else:
return null
to advance() :Str:
if (mafia.getWinner() =~ outcome ? (outcome != null)):
return outcome
if ([state, day] == [NIGHT, 0]) { # Using brackets
state := DAY
day += 1
return "It's morning on the first day."
}
if (mafia.lynch =~ note ? (note != null)):
state := switch (state) {
match ==DAY { NIGHT }
match ==NIGHT { day += 1; DAY }
}
votes := [].asMap()
return note
return `${votes.size()} votes cast.`
to vote(player ? (players.contains(player)),
choice ? (players.contains(choice))) :Void:
switch (state):
match ==DAY:
votes with= (player, choice)
match ==NIGHT:
if (mafiosi.contains(player)):
votes with= (player, choice)
to lynch() :NullOk[Str]:
def quorum :Int := mafia.getQuorum()
def counter := [].asMap().diverge()
for _ => v in (votes):
if (counter.contains(v)):
counter[v] += 1
else:
counter[v] := 1
traceln(`Counted votes as $counter`)
escape ej:
def [victim] exit ej := [for k => v in (counter) ? (v >= quorum) k ]
def count := counter[victim]
def side := mafiosi.contains(victim).pick("mafioso", "innocent")
players without= (victim)
mafiosi without= (victim)
innocents without= (victim)
return `With $count votes, $side $victim was lynched.`
catch _:
return null
return ["game" => mafia, "mafiosi" => mafiosi]
// game.mt
import "lib/entropy/entropy" =~ [=> makeEntropy :DeepFrozen]
import "lib/entropy/pcg" =~ [=> makePCG :DeepFrozen]
import "mafia2" =~ [=> makeMafia :DeepFrozen]
exports (main)
def playGame(seed :Int) as DeepFrozen:
def names := ["Alicia", "Beppo", "Carlo", "Doria", "Elena", "Flavio", "Guido"]
def rng := makeEntropy(makePCG(seed, 0))
def aName := fn { names[rng.nextInt(names.size())] }
def [=> game, => mafiosi] := makeMafia(names.asSet(), rng)
def steps := [game.advance()].diverge()
while (game.getWinner() == null):
try:
game.vote(aName(), aName())
catch e:
traceln(e)
continue
def step := game.advance()
traceln(step)
traceln(game)
def main(argv) as DeepFrozen:
playGame(731)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment