# Seedbed: an original tile-laying game. Each gardener fills a 6×6 bed with flower tiles bought from
# a shared nursery; tiles are polyominoes placed with `shape` (any rotation, no overlap). Full rows
# and columns bloom. Our own game.
game: seedbed
label: Seedbed
players: "2 players"
num_players: 2
mode: competitive
summary: >
  Two gardeners fill a 6×6 bed each. On your turn you either gather two seeds, or buy a flower
  tile from the nursery (four tiles on show), turn it as you like and plant it in your bed where it
  fits. Every full row or column of your bed blooms for 3 points. After twelve rounds each
  covered cell scores 1, each bloom 3, and every unspent seed 1. The richer bed wins.
scope: >
  Tiles may be planted anywhere they fit; they need not touch. A tile that fits nowhere in your
  bed cannot be bought. Colours are decoration only.

boards:
  bed: {kind: square, width: 6, height: 6, neighbours: 4, label: flower bed}

constants:
  ROUNDS: 12
  NURSERY: 4
  GATHER: 2
  BLOOM: 3
  SHAPES:
    domino: [[0, 0], [1, 0]]
    row3: [[0, 0], [1, 0], [2, 0]]
    corner: [[0, 0], [1, 0], [0, 1]]
    row4: [[0, 0], [1, 0], [2, 0], [3, 0]]
    hook: [[0, 0], [1, 0], [2, 0], [0, 1]]
    tee: [[0, 0], [1, 0], [2, 0], [1, 1]]
    step: [[0, 0], [1, 0], [1, 1], [2, 1]]
    square: [[0, 0], [1, 0], [0, 1], [1, 1]]
    plus: [[1, 0], [0, 1], [1, 1], [2, 1], [1, 2]]
  COLOURS: [rose, sun, sky]

content:
  tiles:
    - {id: domino_rose, label: Rose pair, shape: domino, size: 2, cost: 1, color: rose, status: verified}
    - {id: domino_sun, label: Sun pair, shape: domino, size: 2, cost: 1, color: sun, status: verified}
    - {id: domino_sky, label: Sky pair, shape: domino, size: 2, cost: 1, color: sky, status: verified}
    - {id: row3_rose, label: Rose row, shape: row3, size: 3, cost: 2, color: rose, status: verified}
    - {id: row3_sun, label: Sun row, shape: row3, size: 3, cost: 2, color: sun, status: verified}
    - {id: row3_sky, label: Sky row, shape: row3, size: 3, cost: 2, color: sky, status: verified}
    - {id: corner_rose, label: Rose corner, shape: corner, size: 3, cost: 2, color: rose, status: verified}
    - {id: corner_sun, label: Sun corner, shape: corner, size: 3, cost: 2, color: sun, status: verified}
    - {id: corner_sky, label: Sky corner, shape: corner, size: 3, cost: 2, color: sky, status: verified}
    - {id: row4_rose, label: Rose hedge, shape: row4, size: 4, cost: 3, color: rose, status: verified}
    - {id: row4_sun, label: Sun hedge, shape: row4, size: 4, cost: 3, color: sun, status: verified}
    - {id: row4_sky, label: Sky hedge, shape: row4, size: 4, cost: 3, color: sky, status: verified}
    - {id: hook_rose, label: Rose hook, shape: hook, size: 4, cost: 3, color: rose, status: verified}
    - {id: hook_sun, label: Sun hook, shape: hook, size: 4, cost: 3, color: sun, status: verified}
    - {id: hook_sky, label: Sky hook, shape: hook, size: 4, cost: 3, color: sky, status: verified}
    - {id: tee_rose, label: Rose tee, shape: tee, size: 4, cost: 3, color: rose, status: verified}
    - {id: tee_sun, label: Sun tee, shape: tee, size: 4, cost: 3, color: sun, status: verified}
    - {id: tee_sky, label: Sky tee, shape: tee, size: 4, cost: 3, color: sky, status: verified}
    - {id: step_rose, label: Rose steps, shape: step, size: 4, cost: 3, color: rose, status: verified}
    - {id: step_sun, label: Sun steps, shape: step, size: 4, cost: 3, color: sun, status: verified}
    - {id: step_sky, label: Sky steps, shape: step, size: 4, cost: 3, color: sky, status: verified}
    - {id: square_rose, label: Rose patch, shape: square, size: 4, cost: 3, color: rose, status: verified}
    - {id: square_sun, label: Sun patch, shape: square, size: 4, cost: 3, color: sun, status: verified}
    - {id: square_sky, label: Sky patch, shape: square, size: 4, cost: 3, color: sky, status: verified}
    - {id: plus_rose, label: Rose bloom, shape: plus, size: 5, cost: 4, color: rose, status: verified}
    - {id: plus_sun, label: Sun bloom, shape: plus, size: 5, cost: 4, color: sun, status: verified}
    - {id: plus_sky, label: Sky bloom, shape: plus, size: 5, cost: 4, color: sky, status: verified}

functions:
  pattern:
    params: [tile]
    x: "SHAPES[tile['shape']]"
  turned:
    text: "the pattern turned k quarter turns, as offsets from its top-left corner (the same shape wherever it lies)"
    params: [pat, k]
    x: >-
      [(x - min(q[0] for q in ps), y - min(q[1] for q in ps)) for ps in [[[(p[0], p[1]), (-p[1], p[0]), (-p[0], -p[1]), (p[1], -p[0])][k] for p in pat]] for x, y in sorted(ps)]
  turns_of:
    text: "the distinct rotations of a tile (a square has one, a row two, most have four)"
    params: [tile]
    x: "[k for k in range(4) if all(turned(pattern(tile), k) != turned(pattern(tile), j) for j in range(k))]"
  anchors:
    text: "the cells where the tile, turned k times, fits in bed b without overlap"
    params: [b, tile, k]
    x: >-
      [c for c in cells('bed')
       if len(shape('bed', c, pattern(tile), k)) == tile['size'] and not any(x in b for x in shape('bed', c, pattern(tile), k))]
  fits:
    text: "can the tile be planted anywhere in bed b?"
    params: [b, tile]
    x: "any(len(anchors(b, tile, k)) > 0 for k in turns_of(tile))"
  buyable:
    text: "the nursery tiles the player can pay for and plant"
    params: [p]
    x: "[t for t in nursery if t['cost'] <= seeds[p] and fits(bed[p], t)]"
  blooms:
    text: "full rows and columns of bed b"
    params: [b]
    x: >-
      sum(1 for y in range(6) if all(cell('bed', x, y) in b for x in range(6)))
      + sum(1 for x in range(6) if all(cell('bed', x, y) in b for y in range(6)))
  score_of:
    params: [p]
    x: "len(bed[p]) + BLOOM * blooms(bed[p]) + seeds[p]"

state:
  zones:
    bag: {kind: stack, owner: global, visibility: hidden, shuffled: true, holds: tile, init_x: "content['tiles']"}
    nursery: {kind: set, owner: global, visibility: public, holds: tile, note: "the four tiles on show"}
    planted_tiles: {kind: set, owner: global, visibility: public, holds: tile, note: "tiles already in a bed"}
  vars:
    current: {scope: global, type: ref, init: 0}
    round_no: {scope: global, type: int, init: 1}
    seeds: {scope: player, type: int, init: 3}
    bed: {scope: player, type: dict, init_x: "[{} for q in players]", note: "cell → {tile, color}"}
    score: {scope: player, type: int, init: 3, note: "cells + 3 per bloom + unspent seeds; starts at the three seeds"}
    planted: {scope: player, type: int, init: 0}

flow:
  id: game
  label: Game
  kind: loop
  until: twelve rounds
  until_x: "round_no > ROUNDS"
  children:
    - {id: setup, label: Fill the nursery, kind: step, do: setup}
    - id: round
      label: Round
      kind: loop
      over: the gardeners
      over_x: players
      as: current
      once: true
      children:
        - {id: turn, label: "Gather seeds, or buy and plant a tile", kind: step, actor: current gardener, actor_x: current, do: [gather, plant]}
    - {id: next_round, label: Next round, kind: step, do: next_round}

actions:
  setup:
    effect:
      - op: if
        cond: the nursery is not full yet
        cond_x: "len(nursery) < NURSERY and len(bag) > 0"
        then:
          - {op: draw, n: the missing tiles, n_x: "min(NURSERY - len(nursery), len(bag))", from: bag, to: nursery}
  gather:
    label: Gather two seeds
    effect:
      - {op: add, var: "seeds[current]", amount: 2, amount_x: GATHER}
      - {op: set, var: "score[current]", value_x: "score_of(current)"}
  plant:
    label: Buy a tile and plant it
    pre: a nursery tile you can pay for fits in your bed
    pre_x: "len(buyable(current)) > 0"
    effect:
      - {op: choose, options: "a tile you can afford and plant", options_x: "buyable(current)", bind: tile}
      - op: choose
        options: "how to turn it"
        options_x: >-
          [{'label': ['as it is', 'turned once', 'turned twice', 'turned three times'][k], 'k': k, 'pattern': pattern(tile), 'anchors': anchors(bed[current], tile, k)}
           for k in turns_of(tile) if len(anchors(bed[current], tile, k)) > 0]
        bind: turn
      - op: choose
        options: "where its anchor cell goes (tap a highlighted cell; the tile covers the cells shown)"
        options_x: "[{'label': c, 'cell': c, 'cells': shape('bed', c, pattern(tile), turn['k'])} for c in anchors(bed[current], tile, turn['k'])]"
        bind: at
      - {op: add, var: "seeds[current]", amount: minus the cost, amount_x: "-tile['cost']"}
      - {op: move, what: the tile, what_x: tile, from: nursery, to: planted_tiles}
      - op: set
        var: "bed[current]"
        value_x: "{**bed[current], **{c: {'tile': tile['id'], 'color': tile['color']} for c in at['cells']}}"
      - {op: add, var: "planted[current]", amount: 1}
      - {op: set, var: "score[current]", value_x: "score_of(current)"}
      - op: if
        cond: the bag still has tiles
        cond_x: "len(bag) > 0"
        then:
          - {op: draw, n: 1, from: bag, to: nursery}
      - {op: emit, event: planted}
  next_round:
    effect:
      - {op: add, var: round_no, amount: 1}

end:
  - id: done
    if: "twelve rounds played: the richer bed wins"
    if_x: "round_no > ROUNDS"
    result: score
    returns_x: "[1 if score[q] > score[1 - q] else -1 if score[q] < score[1 - q] else 0 for q in players]"

tutorial:
  - {at: turn, text: "Gather gives two seeds. Planting costs a tile's seeds (its size minus one). Tiles can be turned; they must fit inside your bed without overlapping. Full rows and columns bloom for 3 points each."}
