game: tictactoe
label: Tic-tac-toe
players: "2 players"
mode: competitive
num_players: 2
demonstrates: "basics · lower bound · executable"
summary: >
  Perfect information, no chance, one decision per turn. The lower bound of the metamodel,
  and the first fully executable model: every rule has an `_x` expression.

constants:
  SYMBOL: ["X", "O"]
  LINES: [[0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]]

state:
  entity_types:
    mark: {attrs: {symbol: "enum[X, O]"}}
  zones:
    board: {kind: grid, size: [3, 3], owner: global, visibility: public, holds: mark, init_x: "[None] * 9"}
  vars:
    current: {scope: global, type: ref, init: 0, note: "0 = X, 1 = O"}

flow:
  id: game
  label: Game
  kind: loop
  over: players
  over_x: players
  as: current
  order: fixed
  note: "ends through the end conditions"
  children:
    - id: place
      label: Place your mark on an empty square
      kind: step
      actor: current
      actor_x: current
      do: place_mark

actions:
  place_mark:
    actor: current
    pre: "at least one empty square"
    pre_x: "None in board"
    effect:
      - op: choose
        actor: current
        options: "empty squares"
        options_x: "[i for i in range(9) if board[i] is None]"
        bind: cell
      - {op: place, what: "mark of current", what_x: "SYMBOL[current]", to: board, at_x: cell}
      - {op: emit, event: mark_placed}

triggers:
  - {id: check_line, source: rule, event: mark_placed, timing: after, do: [{op: emit, event: end_check}]}

end:
  - id: three_in_row
    check: immediate
    if: "three in a row for current"
    if_x: "any(all(board[i] == SYMBOL[current] for i in L) for L in LINES)"
    who_x: current
    result: win
  - id: full
    check: immediate
    if: "board full without a line"
    if_x: "None not in board"
    result: draw
