Gridworld Problem: Game on Graph

This example demonstrates how to construct a game on graph using a Gridworld transition system and an LTL specification for P1.

In general, there are three ways to define a game on graph, namely

  • By explicitly adding vertices and edges to the graph and marking the accepting states,
  • By providing a transition system and a formal specification,
  • By providing a game field and player objects.

Presently, in IGLSynth v0.2.3, only first two are supported. See Gridworld Problem: Game on Graph for an example of constructing game on graph by explicitly adding vertices and edges.

Define Transition System

To define a game using transition system and P1’s specification, first define the transition system. In general, a transition system may be defined using TSys class. In this example, we use a predefined Gridworld transition system from iglsynth.game.gridworld module:

from iglsynth.game.gridworld import *

# Define transition system
tsys = Gridworld(kind=TURN_BASED, dim=(3, 3), p1_actions=CONN_4, p2_actions=CONN_4)
tsys.generate_graph()

Define LTL Specification

To define P1’s objective using an LTL specification, import the logic module:

from iglsynth.logic.ltl import *

An LTL formula is defined over an alphabet. Hence, we start by defining AP objects using which we will construct an alphabet.

In this demo example, we will represent P1’s objective to reach to a goal. Such a reachability specification can be written as \(\varphi = \Diamond a\) where \(a\) is an AP representing goal. So, define the AP as:

GOAL = (0, 0)
a = AP("a", lambda st, *args, **kwargs: st.coordinate[0:2] == GOAL)

and the specification as:

spec = LTL("Fa", alphabet=Alphabet([a]))

Define Game Object

Given a transition system and specification, we will now define a game. To define game, we require the game module:

from iglsynth.game.game import *

Now, instantiate and define a game as follows:

game = Game(kind=TURN_BASED)
game.define(tsys, spec)

Solve the Game

The final step is to invoke a solver to solve the game. We will use Zielonka’s algorithm to solve the above game. Note that Zielonka’s algorithm computes winning region for P1 in a deterministic two-player zero-sum game.

In IGLSynth, Zielonka’s algorithm is implemented in zielonka module:

from iglsynth.solver.zielonka import ZielonkaSolver

To run the solver, first instantiate it and call the solve method:

solver = ZielonkaSolver(game)
solver.solve()

The solver.solve() runs the solver on the Game object game that encodes the game on graph. The solution of solver can be accessed using the properties:

print(solver.p1_win)
print(solver.p2_win)

which returns the winning sets for P1 and P2.