DelveTalkcome in

Inspecting kind/hexboard · the kinds · the language · the modules

{name}

Go there its page the town

id
kind/hexboard
called
{name}
kind chain
kind/hexboard → record
owner
the town
made by
the town
version
4
pin
pirom-vosog
state
8366 bytes

Its spells

  • makedelvetalk kind/hexboard make / name: <text, 1 to 64 characters> / size: <a number from 3 to 11>
    its Bend

To cast them, come in.

Who may do what

What its law admits now, before the spell's own Bend has its say.

methoda newcomer
make✓ yes
place✓ yes
makeUnder✓ yes
repair✓ yes
publishPage✓ yes

Its law

  • host opener the hand that opened the world may amend any lawrequest.kind == 2 and request.subject == "the town"
  • law owner the owner stays; only the owner changes the form, the law, the head, the voice, what it is or the body; anyone makes, and places rules, wants and verbs on it(unchanged(owner)) and ((request.subject == new.owner) or ((((((((request.kind == 0) or (request.kind == 4)) and (unchanged(form))) and (unchanged(law))) and (unchanged(head))) and (unchanged(voice))) and (unchanged(about))) and (unchanged(body))))
  • law kind kinds's law holdsunder "kinds"

Its Bend

what it runs: its entry module 18 lines
layer over ./Kind.obend
edition ObjectiveBend 1
import ./Abi.obend as Abi
import ./List.obend as Lists
import ./Form.obend as Form
import ./Rows.obend as Rows
type State = Super.State
form make:
  name: text 1..64
  size: natural 3..11
def make(state: State, input: MakeInput, context: Abi.Context) -> Activity<Super.Done>:
  Super.making(state, Lists.List.cons({head: {name: "name", value: input.name}, tail: Lists.List.cons({head: {name: "size", value: natText(input.size)}, tail: Lists.List.nil()})}), "", context)
form place:
  name: text 1..64
  size: natural 3..11
  id: text 1..64
def place(state: State, input: PlaceInput, context: Abi.Context) -> Activity<Super.Done>:
  Super.making(state, Lists.List.cons({head: {name: "name", value: input.name}, tail: Lists.List.cons({head: {name: "size", value: natText(input.size)}, tail: Lists.List.cons({head: {name: "id", value: input.id}, tail: Lists.List.nil()})})}), "", context)
the body this kind lays on what it makes 116 lines

Each thing of this kind runs this layer over what the kind is of.

layer over ./Record.obend
edition ObjectiveBend 1
import ./Abi.obend as Abi
import ./List.obend as Lists
import ./Document.obend as Document
import ./Form.obend as Form
import ./Plan.obend as Plans
import ./World.obend as World
import ./Card.obend as Card
import ./Scenes.obend as Scenes
import ./Relation.obend as Relations
import ./Rows.obend as Rows
import ./Text.obend as Text
import ./View.obend as View
# The hexboard's body, over RECORD (docs/VIEWS.md, the first view that is a board): a board of `size` by `size` hexes
# (its kind's form, 3 to 11, 7 when none was given), numbered from 0 along each row, top row first. A hand places its
# colour on an empty hex (`place / cell: N`), once a hex: each placing is the record's mark `hex N`, by whoever placed
# it, which RECORD's law keeps (a mark is only added). Each hand's colour is the one its first placing came to, in
# the order hands came (View.player: red, blue, green, …). Its view is the board as hex tiles, an empty hex a button
# that places the reader's colour there; its card the same board in letters.
type State = Super.State
form place:
  cell: natural 0..120
form lines:
  from: natural 1..1000000000
form door:
  label: text 1..32
  to: text 1..128
form undoor:
  label: text 1..32
def lines(state: State, input: LinesInput, context: Abi.Context) -> Activity<Card.Replied>:
  Super.lines(state, {from: input.from}, context)
def door(state: State, input: DoorInput, context: Abi.Context) -> Activity<Card.Replied>:
  Super.door(state, {label: input.label, to: input.to}, context)
def undoor(state: State, input: UndoorInput, context: Abi.Context) -> Activity<Card.Replied>:
  Super.undoor(state, {label: input.label}, context)
def actions(state: State, context: Abi.Context) -> Lists.List<String>:
  if context.principal == state.owner then Text.words("place lines door undoor") else Text.words("place lines")
def methods() -> Lists.List<String>:
  Text.words("~made ~act")
def views() -> Lists.List<String>:
  Text.words("view")
def size(state: State) -> Nat:
  match Text.number(Super.field(state, "size")):
    case yes(n): if n.value < 3n then 3n else if n.value > 11n then 11n else n.value
    case no(_): 7n
def cellName(n: Nat) -> String:
  "hex {natText(n)}"
def columns() -> String:
  "ABCDEFGHIJK"
# A hex as a person names it: its column's letter and its row from 1 (`D4`), and its number.
def where(n: Nat, size: Nat) -> String:
  "{textTake(textDrop(columns(), n % size), 1n)}{natText(n / size + 1n)}"
def placed(state: State, n: Nat) -> Lists.Maybe<Rows.Mark>:
  Relations.lookup(state.marks, {name: cellName(n)})
def place(state: State, input: PlaceInput, context: Abi.Context) -> Activity<Bool>:
  let id = Card.called(context, "hexboard")
  if input.cell >= size(state) * size(state) then Card.refusing(false, {clause: "offBoard", reading: "The board's hexes are 0 to {natText(size(state) * size(state) - 1n)}: delvetalk {id} place / cell: 0"}, context) else placing(state, input.cell, id, context)
def placing(state: State, n: Nat, id: String, context: Abi.Context) -> Activity<Bool>:
  match placed(state, n):
    case some(m): Card.refusing(false, {clause: "taken", reading: "{where(n, size(state))} is {Card.shown(m.value.who, m.value.handle, context)}'s already; an empty hex is a dot on the card: delvetalk {id} ?"}, context)
    case none(_): placedNow(state, n, context)
def placedNow(state: State, n: Nat, context: Abi.Context) -> Activity<Bool>:
  let written(_) = write {marks: insert {name: cellName(n), who: context.principal, handle: context.handle, at: context.height}, tended: set context.clock}
  Card.tell(true, Document.text("{toneOf(players(state), context.principal)} on {where(n, size(state))}.\n"))
def isHex(mark: Rows.Mark) -> Bool:
  Text.starts(mark.name, "hex ")
# The hands that have placed, in the order they first did (their colours' order).
def players(state: State) -> Lists.List<Rows.Mark>:
  firsts(Relations.order(state.marks, fn(m: Rows.Mark) -> Nat: m.at), Lists.List.nil())
def firsts(marks: Lists.List<Rows.Mark>, seen: Lists.List<Rows.Mark>) -> Lists.List<Rows.Mark>:
  match marks:
    case nil(_): seen
    case cons(c): firsts(c.tail, if isHex(c.head) == false || Lists.any(seen, fn(p: Rows.Mark) -> Bool: p.who == c.head.who) then seen else Lists.append(seen, c.head))
# A hand's colour: its place among the players, or the next colour for one who has not placed yet.
def toneOf(players: Lists.List<Rows.Mark>, who: String) -> String:
  match Lists.indexWhere(players, fn(p: Rows.Mark) -> Bool: p.who == who):
    case some(i): View.player(i.value)
    case none(_): View.player(Lists.length(players))
def name(state: State) -> String:
  if state.head == "" then "A HEXBOARD" else state.head
def count(state: State) -> Nat:
  Lists.length(Lists.filter(Relations.rows(state.marks), isHex))
def headLine(state: State, context: Abi.Context, id: String) -> Document.Document:
  let n = size(state)
  let ps = players(state)
  Document.Document.sequence({items: Document.Documents.cons({head: Document.text("{name(state)}, {natText(n)} by {natText(n)} hexes: {natText(count(state))} placed by {Text.countWord(Lists.length(ps))} hands. Your colour {yours(ps, context)}. Place it on an empty hex (a dot), numbered from 0 along each row: delvetalk {id} place / cell: <0 to {natText(n * n - 1n)}>\n"), tail: Document.Documents.cons({head: Document.text(board(state, ps, n, 0n)), tail: Document.Documents.cons({head: Document.text(Super.inactiveLine(state, id)), tail: Document.Documents.nil()})})})})
def yours(players: Lists.List<Rows.Mark>, context: Abi.Context) -> String:
  if Lists.any(players, fn(p: Rows.Mark) -> Bool: p.who == context.principal) then "is {toneOf(players, context.principal)}" else "will be {toneOf(players, context.principal)}"
# The board in letters, each placed hex its colour's first letter and an empty one a dot, odd rows set in by one.
def board(state: State, players: Lists.List<Rows.Mark>, n: Nat, y: Nat) -> String:
  if y >= n then "" else "{indent(y)}{rowText(state, players, n, y * n, n)}\n{board(state, players, n, y + 1n)}"
def indent(y: Nat) -> String:
  if y % 2n == 1n then " " else ""
def rowText(state: State, players: Lists.List<Rows.Mark>, n: Nat, at: Nat, left: Nat) -> String:
  if left == 0n then "" else "{glyph(state, players, at)}{gap(left)}{rowText(state, players, n, at + 1n, left - 1n)}"
def gap(left: Nat) -> String:
  if left > 1n then " " else ""
def glyph(state: State, players: Lists.List<Rows.Mark>, at: Nat) -> String:
  match placed(state, at):
    case some(m): textTake(toneOf(players, m.value.who), 1n)
    case none(_): "."
# What the page draws: the board as hex tiles, an empty one a button placing the reader's colour, and who is which.
def view(state: State, context: Abi.Context) -> View.View:
  let n = size(state)
  let ps = players(state)
  View.stack(View.three(View.heading(name(state)), View.hexes(n, View.tiles(0n, n * n, fn(i: Nat) -> View.Tile: tileAt(state, ps, n, i, context))), View.small(legend(state, ps, context))))
def tileAt(state: State, players: Lists.List<Rows.Mark>, n: Nat, i: Nat, context: Abi.Context) -> View.Tile:
  match placed(state, i):
    case some(m): View.tile("leaf", toneOf(players, m.value.who), "", "{where(i, n)}: {Card.shown(m.value.who, m.value.handle, context)}{Card.mine(m.value.who, context)}", View.nothing())
    case none(_): View.tile("leaf", "", "", "{where(i, n)}: place {toneOf(players, context.principal)} here", View.act("place", View.given("cell", natText(i))))
def legend(state: State, players: Lists.List<Rows.Mark>, context: Abi.Context) -> String:
  let hands = textJoin(Lists.map(players, fn(p: Rows.Mark) -> String: "{toneOf(players, p.who)}: {Card.shown(p.who, p.handle, context)}{Card.mine(p.who, context)}"), " · ")
  "Your colour {yours(players, context)}. {natText(count(state))} of {natText(size(state) * size(state))} placed{semi(hands)}{hands}."
def semi(hands: String) -> String:
  if hands == "" then "" else "; "

Amend it in the workshop

Its Bend is checked and amended by the workshop's own spell, with the Bend in its block. To send it, come in; the box is here then.

Its fields

owner
the town
ownerHandle
the town
name
hexboard
of
record
form
name: text 1..64 (36 characters)
name: text 1..64
size: natural 3..11
law
empty
head
{name}
voice
a board of hexes on a table, colours set down one at a time and never lifted
about
a board of hexes anyone sets their colour on, one hex a turn, drawn live on its page
body
layer over ./Record.obend (7982 characters)
layer over ./Record.obend
edition ObjectiveBend 1
import ./Abi.obend as Abi
import ./List.obend as Lists
import ./Document.obend as Document
import ./Form.obend as Form
import ./Plan.obend as Plans
import ./World.obend as World
import ./Card.obend as Card
import ./Scenes.obend as Scenes
import ./Relation.obend as Relations
import ./Rows.obend as Rows
import ./Text.obend as Text
import ./View.obend as View
# The hexboard's body, over RECORD (docs/VIEWS.md, the first view that is a board): a board of `size` by `size` hexes
# (its kind's form, 3 to 11, 7 when none was given), numbered from 0 along each row, top row first. A hand places its
# colour on an empty hex (`place / cell: N`), once a hex: each placing is the record's mark `hex N`, by whoever placed
# it, which RECORD's law keeps (a mark is only added). Each hand's colour is the one its first placing came to, in
# the order hands came (View.player: red, blue, green, …). Its view is the board as hex tiles, an empty hex a button
# that places the reader's colour there; its card the same board in letters.
type State = Super.State
form place:
  cell: natural 0..120
form lines:
  from: natural 1..1000000000
form door:
  label: text 1..32
  to: text 1..128
form undoor:
  label: text 1..32
def lines(state: State, input: LinesInput, context: Abi.Context) -> Activity<Card.Replied>:
  Super.lines(state, {from: input.from}, context)
def door(state: State, input: DoorInput, context: Abi.Context) -> Activity<Card.Replied>:
  Super.door(state, {label: input.label, to: input.to}, context)
def undoor(state: State, input: UndoorInput, context: Abi.Context) -> Activity<Card.Replied>:
  Super.undoor(state, {label: input.label}, context)
def actions(state: State, context: Abi.Context) -> Lists.List<String>:
  if context.principal == state.owner then Text.words("place lines door undoor") else Text.words("place lines")
def methods() -> Lists.List<String>:
  Text.words("~made ~act")
def views() -> Lists.List<String>:
  Text.words("view")
def size(state: State) -> Nat:
  match Text.number(Super.field(state, "size")):
    case yes(n): if n.value < 3n then 3n else if n.value > 11n then 11n else n.value
    case no(_): 7n
def cellName(n: Nat) -> String:
  "hex {natText(n)}"
def columns() -> String:
  "ABCDEFGHIJK"
# A hex as a person names it: its column's letter and its row from 1 (`D4`), and its number.
def where(n: Nat, size: Nat) -> String:
  "{textTake(textDrop(columns(), n % size), 1n)}{natText(n / size + 1n)}"
def placed(state: State, n: Nat) -> Lists.Maybe<Rows.Mark>:
  Relations.lookup(state.marks, {name: cellName(n)})
def place(state: State, input: PlaceInput, context: Abi.Context) -> Activity<Bool>:
  let id = Card.called(context, "hexboard")
  if input.cell >= size(state) * size(state) then Card.refusing(false, {clause: "offBoard", reading: "The board's hexes are 0 to {natText(size(state) * size(state) - 1n)}: delvetalk {id} place / cell: 0"}, context) else placing(state, input.cell, id, context)
def placing(state: State, n: Nat, id: String, context: Abi.Context) -> Activity<Bool>:
  match placed(state, n):
    case some(m): Card.refusing(false, {clause: "taken", reading: "{where(n, size(state))} is {Card.shown(m.value.who, m.value.handle, context)}'s already; an empty hex is a dot on the card: delvetalk {id} ?"}, context)
    case none(_): placedNow(state, n, context)
def placedNow(state: State, n: Nat, context: Abi.Context) -> Activity<Bool>:
  let written(_) = write {marks: insert {name: cellName(n), who: context.principal, handle: context.handle, at: context.height}, tended: set context.clock}
  Card.tell(true, Document.text("{toneOf(players(state), context.principal)} on {where(n, size(state))}.\n"))
def isHex(mark: Rows.Mark) -> Bool:
  Text.starts(mark.name, "hex ")
# The hands that have placed, in the order they first did (their colours' order).
def players(state: State) -> Lists.List<Rows.Mark>:
  firsts(Relations.order(state.marks, fn(m: Rows.Mark) -> Nat: m.at), Lists.List.nil())
def firsts(marks: Lists.List<Rows.Mark>, seen: Lists.List<Rows.Mark>) -> Lists.List<Rows.Mark>:
  match marks:
    case nil(_): seen
    case cons(c): firsts(c.tail, if isHex(c.head) == false || Lists.any(seen, fn(p: Rows.Mark) -> Bool: p.who == c.head.who) then seen else Lists.append(seen, c.head))
# A hand's colour: its place among the players, or the next colour for one who has not placed yet.
def toneOf(players: Lists.List<Rows.Mark>, who: String) -> String:
  match Lists.indexWhere(players, fn(p: Rows.Mark) -> Bool: p.who == who):
    case some(i): View.player(i.value)
    case none(_): View.player(Lists.length(players))
def name(state: State) -> String:
  if state.head == "" then "A HEXBOARD" else state.head
def count(state: State) -> Nat:
  Lists.length(Lists.filter(Relations.rows(state.marks), isHex))
def headLine(state: State, context: Abi.Context, id: String) -> Document.Document:
  let n = size(state)
  let ps = players(state)
  Document.Document.sequence({items: Document.Documents.cons({head: Document.text("{name(state)}, {natText(n)} by {natText(n)} hexes: {natText(count(state))} placed by {Text.countWord(Lists.length(ps))} hands. Your colour {yours(ps, context)}. Place it on an empty hex (a dot), numbered from 0 along each row: delvetalk {id} place / cell: <0 to {natText(n * n - 1n)}>\n"), tail: Document.Documents.cons({head: Document.text(board(state, ps, n, 0n)), tail: Document.Documents.cons({head: Document.text(Super.inactiveLine(state, id)), tail: Document.Documents.nil()})})})})
def yours(players: Lists.List<Rows.Mark>, context: Abi.Context) -> String:
  if Lists.any(players, fn(p: Rows.Mark) -> Bool: p.who == context.principal) then "is {toneOf(players, context.principal)}" else "will be {toneOf(players, context.principal)}"
# The board in letters, each placed hex its colour's first letter and an empty one a dot, odd rows set in by one.
def board(state: State, players: Lists.List<Rows.Mark>, n: Nat, y: Nat) -> String:
  if y >= n then "" else "{indent(y)}{rowText(state, players, n, y * n, n)}\n{board(state, players, n, y + 1n)}"
def indent(y: Nat) -> String:
  if y % 2n == 1n then " " else ""
def rowText(state: State, players: Lists.List<Rows.Mark>, n: Nat, at: Nat, left: Nat) -> String:
  if left == 0n then "" else "{glyph(state, players, at)}{gap(left)}{rowText(state, players, n, at + 1n, left - 1n)}"
def gap(left: Nat) -> String:
  if left > 1n then " " else ""
def glyph(state: State, players: Lists.List<Rows.Mark>, at: Nat) -> String:
  match placed(state, at):
    case some(m): textTake(toneOf(players, m.value.who), 1n)
    case none(_): "."
# What the page draws: the board as hex tiles, an empty one a button placing the reader's colour, and who is which.
def view(state: State, context: Abi.Context) -> View.View:
  let n = size(state)
  let ps = players(state)
  View.stack(View.three(View.heading(name(state)), View.hexes(n, View.tiles(0n, n * n, fn(i: Nat) -> View.Tile: tileAt(state, ps, n, i, context))), View.small(legend(state, ps, context))))
def tileAt(state: State, players: Lists.List<Rows.Mark>, n: Nat, i: Nat, context: Abi.Context) -> View.Tile:
  match placed(state, i):
    case some(m): View.tile("leaf", toneOf(players, m.value.who), "", "{where(i, n)}: {Card.shown(m.value.who, m.value.handle, context)}{Card.mine(m.value.who, context)}", View.nothing())
    case none(_): View.tile("leaf", "", "", "{where(i, n)}: place {toneOf(players, context.principal)} here", View.act("place", View.given("cell", natText(i))))
def legend(state: State, players: Lists.List<Rows.Mark>, context: Abi.Context) -> String:
  let hands = textJoin(Lists.map(players, fn(p: Rows.Mark) -> String: "{toneOf(players, p.who)}: {Card.shown(p.who, p.handle, context)}{Card.mine(p.who, context)}"), " · ")
  "Your colour {yours(players, context)}. {natText(count(state))} of {natText(size(state) * size(state))} placed{semi(hands)}{hands}."
def semi(hands: String) -> String:
  if hands == "" then "" else "; "
made
1 rows
  1. object
    hexboard
    n
    1
    about
    empty
count
1