Last active
June 19, 2016 19:52
-
-
Save jido/9e34b7a5302654253be678ddbb221664 to your computer and use it in GitHub Desktop.
Hung program
This file contains hidden or 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
# 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