-
Notifications
You must be signed in to change notification settings - Fork 1
GGDL syntax
GGDL is based on GDL which in turn is based on Datalog, a logic programming language.
There are two variants of GDL in the wild, the prefix-formatted one that is constructed from s-expressions, and the infix-formatted one that looks more like a subset of KIF with prolog/datalog inference operator :- for defining relations that imply. The prefix-formatted version is found in rulesheets defined for Stanford's collection of games, the infix notation is more human-readable and what is typically found in academic journals and other offshoots that derived from GDL.
While making GGDL a superset of GDL, I also noticed that the player responses and server updates are a further restricted subset of GDL. Indeed, the possible strings (after normalization) that a player could legally submit as an action are countably finite, and typically a trivially small quantity. It occurred to me, since you would not want to allow the full strength of the interpreter system, that you would either need a sufficiently constrained parser or an interpreter with enough context to know not to evaluate certain otherwise well-formed sentences, nor include them in any unification passes. Indeed, with enough knowledge of the game definition, a compiler could produce a parser that would only accept legal moves from the player, and that it would be much smaller than even a ground-statement parser since all symbolic and relational names would be known beforehand, and that there would be no need to warily evaluate its contents after a successful parse.
So, when defining the syntax, it is important to call out which parts are core GDL, which parts are extensions of that language, and which parts influence the construction of a custom move-accepting parser. And, because GDL is powerful enough to define a broad set of game rules as it is, the language used when conveying the game rules can be interpreted with only GDL syntax and a small runtime library, provided here as a typescript imlplementation.
...
Provides a starting point for the game state and board state, asserting certain facts and relations to be true.
init GroundObjectIsTrue
An initial atomic value is the simplest init statement. These facts evaluate to true and persist until they are negated. An init statement can set up an object or functional relation as well:
init Cell(?i:index, ?j:index) := blank
Here, index is a type that has elsewhere been defined as between 1 and BoardSize. Internally, a Cell\2 instance of size blank is a member of (i.e., marking), defined as a base relation it has only three values (itself and the two roles). An interpreter could define a state representation that can be compactly defined in range
Multiple init statements can be combined in wrapping parentheses:
init (
Cell(?i:index, ?j:index) := blank
BoardControl := x
)
Init statements can be combined with the ^ operator to set up parameters at the game's scope, defining its type and default values. The associated comment can be extracted for documenting this parameter in clients as well.
// Size, both width and height, of the board.
init ^ BoardSize :: int >= 3 <= 20 default 3