Begin
This commit is contained in:
130
Masons.qnt
Normal file
130
Masons.qnt
Normal file
@ -0,0 +1,130 @@
|
||||
module mafia {
|
||||
import basicSpells.* from "basicspells"
|
||||
const players : Set[str]
|
||||
type Alignment = Scum | Town
|
||||
type Role = Mafia | Banana | Doctor | Mover | Gunsmith | Vigilante(int) | Mason | Villager
|
||||
type Phase = Day | Night
|
||||
type LifeState = Alive | Dead
|
||||
type Status = Pending | Done(Alignment)
|
||||
type PlayerFeatures = {
|
||||
name: str,
|
||||
alignment: Alignment,
|
||||
role: Role,
|
||||
status: LifeState,
|
||||
voted: bool,
|
||||
mascot: bool,
|
||||
nominated: bool,
|
||||
}
|
||||
|
||||
var players_to_features: str -> PlayerFeatures
|
||||
var votes_by_player: str -> int
|
||||
var game_phase: Phase
|
||||
var game_status: Status
|
||||
var last_saved: str
|
||||
|
||||
pure def all_voted(players: str -> PlayerFeatures): bool =
|
||||
players.values().filter(p => p.status == Alive).forall(p => p.voted == true)
|
||||
|
||||
pure def alive_mafia(players: str -> PlayerFeatures): int =
|
||||
size(players.values().filter((p) => p.status == Alive and p.alignment == Scum))
|
||||
|
||||
pure def alive_town(players: str -> PlayerFeatures): int =
|
||||
size(players.values().filter((p) => p.status == Alive and p.alignment == Town))
|
||||
|
||||
pure def mascots_alive(players: str -> PlayerFeatures): int =
|
||||
size(players.values().filter((p) => p.status == Alive and p.mascot))
|
||||
|
||||
pure def doc_alive(players: str -> PlayerFeatures): int =
|
||||
size(players.values().filter((p) => p.status == Alive and p.role == Doctor))
|
||||
|
||||
pure def vig0_alive(players: str -> PlayerFeatures): int =
|
||||
size(players.values().filter((p) => p.status == Alive and p.role == Vigilante(0)))
|
||||
|
||||
pure def vig1_alive(players: str -> PlayerFeatures): int =
|
||||
size(players.values().filter((p) => p.status == Alive and p.role == Vigilante(1)))
|
||||
|
||||
pure def mafia_lose_condition_active(players: str -> PlayerFeatures):bool = {
|
||||
val mafias = alive_mafia(players)
|
||||
val mafia_aligned = if (size(keys(players)) < 11)
|
||||
(mafias + mascots_alive(players))
|
||||
else mafias
|
||||
2 > mafia_aligned
|
||||
}
|
||||
|
||||
pure def mafia_win_condition_active(players: str -> PlayerFeatures): bool = alive_mafia(players) == alive_town(players)
|
||||
|
||||
pure def gen_list_of_roles(n: int): List[Role] = {
|
||||
val special: List[Role] =
|
||||
if (Set(7).contains(n)) [Banana]
|
||||
else if (Set(8).contains(n)) [Doctor]
|
||||
else if (Set(9).contains(n)) [Mover]
|
||||
else if (Set(10).contains(n)) [Doctor]
|
||||
else if (Set(11,12).contains(n)) [Doctor, Gunsmith]
|
||||
else if (Set(13,14).contains(n)) [Doctor, Banana]
|
||||
else if (Set(15,16).contains(n)) [Mason, Mason, Gunsmith]
|
||||
else if (Set(17,18).contains(n)) [Mover, Gunsmith]
|
||||
else if (Set(19,20).contains(n)) [Mason,Mason,Doctor,Vigilante(0)]
|
||||
else if (Set(21,22).contains(n)) [Vigilante(0), Vigilante(0), Doctor, Gunsmith]
|
||||
else if (Set(23,24,25,26).contains(n)) [Vigilante(0), Vigilante(0), Vigilante(1), Vigilante(1), Banana]
|
||||
else []
|
||||
val mafias: List [Role] = repeat((n+1)/4, Mafia)
|
||||
if (n < 7 or n > 26) [] else
|
||||
special.concat(mafias)
|
||||
.concat(repeat(n-length(special)-length(mafias),Villager))
|
||||
}
|
||||
|
||||
val get_most_voted_players = {
|
||||
if (all_voted(players_to_features)) {
|
||||
val max_votes = players.fold(-1, (acc, p) => {
|
||||
val votes = votes_by_player.get(p)
|
||||
max(votes,acc)
|
||||
})
|
||||
players.filter(p => votes_by_player.get(p) == max_votes)
|
||||
} else Set() // Return an empty set if not all players have voted
|
||||
}
|
||||
|
||||
pure def update_status(players: str -> PlayerFeatures): Status =
|
||||
if (mafia_lose_condition_active(players)) Done(Town) else
|
||||
if (mafia_win_condition_active(players)) Done(Scum) else
|
||||
Pending
|
||||
|
||||
pure def update_after_kill(victims: List[str], players: str -> PlayerFeatures): str -> PlayerFeatures =
|
||||
victims.foldl(players, (curr, victim) => curr.setBy(victim, p => {...p, status: Dead}))
|
||||
|
||||
pure def update_after_hanging(victim: str, players: str -> PlayerFeatures): str -> PlayerFeatures = {
|
||||
val playersNew = update_after_kill([victim], players)
|
||||
playersNew.transformValues(p => {... p, voted: false})
|
||||
}
|
||||
|
||||
action nightPhase = all {
|
||||
nondet victimScum = players_to_features.values().filter(p => p.status == Alive and p.alignment == Town).oneOf()
|
||||
nondet doctorSave = players_to_features.values().filter(p => p.status == Alive and p.role != Doctor and p.name != last_saved).oneOf()
|
||||
nondet victimVig0 = players_to_features.values().filter(p => p.status == Alive and p.role != Vigilante(0)).oneOf()
|
||||
nondet victimVig1 = players_to_features.values().filter(p => p.status == Alive and p.role != Vigilante(1)).oneOf()
|
||||
val victim = if (victimScum == doctorSave and doc_alive(players_to_features) > 0) [] else [victimScum]
|
||||
val victims: List[PlayerFeatures] = {
|
||||
val temp = if (vig0_alive(players_to_features) > 0) victim.append(victimVig0) else victim
|
||||
if (vig1_alive(players_to_features) > 0) temp.append(victimVig1) else temp
|
||||
}
|
||||
val updated_features = update_after_kill(victims.listMap(p => p.name),players_to_features)
|
||||
val new_game_status = update_status(updated_features)
|
||||
all {
|
||||
players_to_features.values().exists(p => p.status == Alive and p.role == Mafia),
|
||||
game_phase == Night,
|
||||
players_to_features' = updated_features,
|
||||
game_status' = new_game_status,
|
||||
game_phase' = Day,
|
||||
votes_by_player' = votes_by_player
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Nomination, Voting, Execution, in that order
|
||||
|
||||
|
||||
// TODO: invariants
|
||||
// TODO: Win rates
|
||||
}
|
||||
module play_mafia {
|
||||
import mafia(players = Set("Pingu", "T-Dor", "Prince", "Benjamin", "Barwe", "Draken", "Ikka", "Krig", "Izza", "Underhill", "Geting", "Igelkott", "Ugglan", "Joppe", "Människan", "Wisdom")).*
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user