Partake, A Formal Language for Board Games and Other Interactions

Abstract

TODO: update

Board games are not just for fun: they seriously exercise our reasoning abilities and prepare players for “real-world” activities that require problem solving.

Turn-based board games, regarded as formal systems, form an interesting computation - ? avoid debate ^ - emphasize computational model/interaction between state and people

There is much recent interest in complex games that include large libraries of cards and scenarios in order to combinatorially increase gameplay variety. Regarded as formal systems, these games are a legitimate challenge to represent using software.

We introduce a language, Partake, which allows for compositional development of games using programs that match the conciseness of natural language. Going beyond traditional monist object-oriented systems, Partake recognizes a basic duality between situations and actors, which clarifies the role of each in specifying gameplay. Game rules typically specify complex situations in which players act, so we focus on the task of specifying situations. Situations unfold over time into choice-points to be decided by various actors, be they people, randomizers, rulings, or strategic heuristics. We present a temporal semantic model based on episode segments that naturally group together these choices. We introduce two intertwined new languages: a declarative relational language for defining concepts and a procedural one for episodes.

Finally, our approach allows us to decouple low-level input/output issues like event handling and rendering from the high-level input/output specified by game logic. We demonstrate this with a novel GUI generation algorithm, which provides a way of smoothly interpolating between a minimalist menu-based GUI all the way to fully custom GUIs, while significantly reducing the effort needed for practical board-game style GUIs.

Relational Model Design

We propose a relational object-oriented model for defining games and other interactive software.

summary of the aspects of board games as a model of computation that we must capture in the language:

Objects

(Comparison to traditional OO model)

The original Smalltalk system was designed to support the human creative spirit by attempting to reflect human communication patterns onto those of the computer. The central metaphor was that of the physical object, a restricted area of space with definite affordances. A central focus was on formally capturing affordances and needs; any object with affordances appropriate for a particular need could be used to satisfy that need. For instance, many file-system implementations might be hidden behind a particular interface that represents a need to list files within a directory and access particular files by name. Uniformity of representation was emphasized by ensuring that all programmer-facing value types were objects todo.

Game objects, however, do not have a function-oriented nature, instead being purely symbolic. The collection of game objects takes on meaning based on rules that impose particular relationships among them and between them and the players’ goal(s). A typical game token is an entity without internal structure: it is merely distinct from other tokens and occupies some physical space. However, it may take on an arbitrarily large salience due to attributes granted it by game rules.

In order to design a programming language that reflects the natural way that people combine and learn about game rules, we must begin by reflecting the basic values that rules refer to and manipulate.

In light of the reasons and examples just given, we propose that a relational model for game entities is necessary. Relations do not impose a fixed up-front structure on entities. For instance, the statement

token P
located P -> L

asserts merely that P is a token with a location L. Additional facts may or may not be asserted and updated later:

health P -> 10
has-ability P 'attack-right
has-ability P 'flee
...
health P -> 8

Syntax note: We use the traditional logic-programming style syntax for tuples and queries, with lower-case predicates and upper-case variables (e.g. predicate(X, A+B)), except written in the style of ML function application (e.g. predicate X (A+B)).

State

A second core observation about the board game domain is that almost the entirety of the game state must live on the board. This is a simple reflection of human short-term memory limitations: a well-designed game and game board should impose minimal unnecessary cognitive burden on the players.

However, there are two issues that conflict with this:

However, a high-level view of gameplay suggests that typical games require players to make choices and then promptly unfold the consequences of those choices as determined by the relevant game rules. The process of unfolding the rules takes time, and we note that the intermediate points may not always have a literal board representation. For instance, when playing a card that says “draw a card, then discard a card from your hand”, it is clear that

The computational state needed to carry out this action is simple for a player to carry mentally, and we wish to reflect this in our mechanism for representing rules.

Procedural languages have a simple notion of time during execution: the program counter and call-stack. Reasoning about program behavior at this level is notoriously tedious, but programming an application such as a board game engine requires carefully mapping game time onto execution time in some way. The procedural model is poorly suited to the task of representing computations mainly consist of cycles of interaction between several actors.

Instead, we propose an objective representation of time that captures a basic way that people group situations into periods of time. We refer to a period of time formally as an episode. Episodes can contain other episodes (such as when a player’s turn consists of two phases) and may be ordered temporally (such as when a player’s turn must fully elapse before another player’s turn may begin). Episodes can also be concurrent (such as when two players in a cooperative game may take their turns in an arbitrarily interleaved fashion) (or in a simultaneous moves game, where players must make certain decisions and then reveal them simultaneously).

More formally, we assume an infinite set E of episodes, and equip them with the following structure:

Examples

(ignore)

Rules that match one attribute need not refer to others:

has-ability P 'attack-right, located P -> L,
adjacent-right L L', located P' L'
-----------------------------------------
may-attack P P'.

But may if they wish to:

has-ability P 'flee, health P -> HP, HP > 5
---------------------------------------
may-flee P.

The most important consequence of this choice is that rules combine commutatively.

Intro

Turn-based board games represent an interesting computational paradigm. We are interested in games with fully explicit rules, so that they can be formalized as transition systems.

Story Design

The episode language unfolds into a tree of episodes.

type Pattern = (Name, List Term)

def Episode :=
  | Node Name Episode

  | Observe      Query Episode
  | Choose Actor Query Episode
  | Branch Actor (List (Name, Episode))

  | Assert Pattern
  | Begin Name Episode

Name, Term = ...
Actor = ...

basic actors:

- all at once
- this before that
- player's choice
- up to N

forms of input: - label, C (choose which child to go down) and then C - map (label -> C) (do C_l for each label) - pragmatic thing (for incrementally resolving choice) -

Evaluation

language part

challenges to demonstrate:

GUI generation

TODO

Simultaneity

What should happen if two rules attempt to simultaneously move a token from its current location to different target locations? For this simple reason, a language cannot universally provide both state manipulation and simultaneity. Simultaneity still provides a useful increase in expressivity: it allows for games such as rock-paper-scissors, and even in perfect-information games, it enables transitions which are distinct from doing either one of the two actions in series. It can be provided so long as the game rules only introduce simultaneous episodes that mutate independent aspects of the game board.

Software Cultivation

…In particular, an append-only language makes no gaurantees that reading earlier code will have any benefit for understanding current code, as it might have been wholesale replaced. …introduction of a new concept that refines or unifies prior concepts. …most important learning is what happens, not the syntax of how that is specified. refinements preserve a player’s understanding of what happens. there are always many ways to specify, and those ways can only be distinguished when new behavior is added.

This work is motivated by the desire to increase the of software, both for games as well as interactive software more generally. We note that software systems can be generally decomposed into three sorts of parts: \begin{itemize}

Base components (graphics rendering, networking, hardware drivers) that are not application specific and usually irrelevant to the user’s understanding of a particular system. - Code defining the software is arranged in a manner that is most conducive to learning about the totality of its behavior - When new features are to be added, modifications to existing code must be limited to refinement or unification

Languages for software engineering often focus on modularity, which can be regarded as a variant of the two points. Modularity assists software understanding by forcing decoupling of implementation choices from clients [cite 70s module paper]. Ideally, a module is understood by understanding its code along with the interfaces of any modules its code refers to (but not their code). Modules assist development by guiding the modifier to relevant parts of the code Software development relies on the following key phenomenon: when code is split into modules “well”, it generalizes to new tasks (modifications to be made for a new feature are limited to a small set of modules).

Faced with the task of developing open games, our criteria are somewhat more stringent at the cost of being less feasible to uphold for software at large. In particular, the second bullet point is very stringent. An example of a hypothetical system that trivially satisfies only the second point would be any “append only” programming language, where a codebase can only be modified by appending new code. New code would contain directives over older code to ignore, satisfying the letter of the rule if not the spirit. Such a system would entirely violate the first point, however: an append-only language would make no gaurantees that reading earlier code would have any benefit for understanding current code, as it might have been wholesale replaced.

We emphasize totality of behavior in the first point because games must be fully understood to be played. This is in contrast to usual technology development, where it is often seen as a merit if a system has been decomposed so that only small parts need be understood to be operated or modified.

Vs economics

competitive (dominion, MtG) coop (SI, gloomhaven, D&D) story oriented

debruijn factor

no more, (! no less !) no opaque encoding scheme need indexicals for this

"creature gains +1/+1 for each spell cast this turn"
   1       2     3 3'  4   5    6     7   8    9

1           8  9      6   45
creature C, *~turn [ cast C ],
---------------------
2 3
boost-attack C -> 1,
2 3'
boost-toughness C -> 1,
.

creature C, type C 'slime,
~turn = T, T [ ~cast

atoms vs tuples

story +foo atoms never go away dynamic ... --- foo atoms are maintained

Stuff

Our goal is to provide a language that is appropriate for direct encoding of game rules, including the calculation of game-state dependent options, rules that automatically trigger upon occurrence of particular patterns in the game state, rules that refer to recent events that have transpired, rules that can be resolved concurrently by different players, and rules that rely on linguistic indexicality to refer to dynamically changing context (such as the current turn, a particular game object implicitly denoted by its relevancy, or terms that change depending on where the rule is printed). We find that these difficulties can be handled by a fairly small set of concepts, the most fundamental being expressions that branch based on the result of a logical query. Queries are used in Partake to represent choice sets, branches in the episode tree, and patterns that guard rule triggers.

Because we use incremental database evaluation and timestamp tuples, it is trivial to rewind the last several inputs, so we can use speculative execution when designing a GUI, provide universal undo by construction, and

SAD intro

If we want a binary relation that relates a card to its cost, we might name it card/cost. If the cost is a static property, then we’ll use a normal tuple card/cost Card Cost, but if it’s something that dynamically changes according to some aggregate we’ll use card/cost Card -> Cost. Static information about a card is typically best attached to a static name for that card. Say we want a card named

Performance

make sure to mention that SAD is used in the implementation of Partake.

Observations

Games as computation:

https://cutfree.net