open util/ordering[Gnome] as Lineup
-- Disable ordering on KS for debugging as needed
open util/ordering[KnowledgeState] as KS
-- Gnomes are partitioned into 2 separate rooms
-- and, in each room, lined up in (arbitrary) order
-- AN INSTANCE HAS A FIXED ROOM SETUP
sig Gnome {
room: Room
}
abstract sig Room {}
one sig LeftRoom extends Room {}
one sig RightRoom extends Room {}
-- Hats are either red or blue
abstract sig HatColor {}
one sig Red extends HatColor {}
one sig Blue extends HatColor {}
-- A possible world is an allocation of hats
sig World {
hats: Gnome -> one HatColor
}
-- no two worlds have the same hat allocation
fact canonicalWorlds {
all disj w1, w2: World |
some g: Gnome | w1.hats[g] != w2.hats[g]
}
fact halfRedHalfBlue {
all w: World |
#{g: Gnome | w.hats[g] = Blue} =
#{g: Gnome | w.hats[g] = Red}
}
-- Before every question, gnomes have a certain knowledge state
-- "State" and "World" are *different concepts*
sig KnowledgeState {
-- Read as: poss[g][w1][w2] means
-- "If g is in w1, they believe w2 is possible."
poss: Gnome -> World -> World,
justAsked: lone Gnome
} {
this = KS/first implies no justAsked
this != KS/first implies some justAsked
-- no repeats (note: still safe even for KS/first)
no ks: KnowledgeState - this |
ks.@justAsked = justAsked
}
-- Who can the gnomes see in this instance?
fun canSee[g: Gnome]: set Gnome {
-- FILL
}
pred initialKnowledge[s: KnowledgeState] {
-- Each gnome can see those later in their ordering
-- So some gnomes know that /some/ worlds are impossible right away
-- FILL
}
-- You'll need to add a fact that describes what's learned over time, too.
-- I suggest writing initialKnowledge, constraining the initial state to obey it,
-- and then doing some sanity-checking before moving on to what gets learned over time.