Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

README.md

3.35 Kb · 65 lines

gno.land/p/moul/x/games/clock/v0

A deadline that actions push forward, and that still ends: New, Bump, BumpBy, BumpShare, Expired, Remaining, Deadline, HardEnd, Final.

1import "gno.land/p/moul/x/games/clock/v0"
2
3c, _ := clock.New(height, 2000, 300, 100000) // now, window, floor, life
4c.Deadline()          // height+2000
5c.BumpShare(h, 20)    // a write buys a fifth of the gap to the hard end
6c.Expired(h)          // the game is over, and cannot be reopened
7c.Final()             // the deadline has hit the hard end: holding now beats acting

Every last-action-wins game has this clock, and written the obvious way it fails in one of two opposite directions.

With a constant extension it never ends. The pot grows faster than the price of the next action, so the pot-to-price ratio rises, there is always a rational next action, and the second-to-last actor is always the mark. life is the terminator: an absolute end, fixed when the clock opens, that no bump can pass.

With a decaying extension it ends too suddenly. A grant that shrinks toward zero makes the last stretch shorter than the time a transaction needs to land, so whoever is holding at that moment wins by being unreachable rather than by paying. floor is the anti-snipe: a bump always leaves at least that much on the clock.

Four invariants, deliberately in the library and not in the caller:

  • An expired clock never restarts. A late action cannot reopen a settled game, which is the difference between a closed pot and a stolen one.
  • The deadline never moves backwards. A small grant late in the game leaves the existing deadline alone instead of shortening it.
  • A bump always leaves at least the floor, however little there was to share.
  • The deadline never passes the hard end, against any grant, including one that would overflow an int64.

The caller owns the policy, the clock owns the guards. BumpBy takes whatever grant the game computed: a constant, a function of the amount paid, anything. BumpShare is the one worth knowing, and it is a share of the distance to the hard end, not of the time remaining: now + (deadline-now)*pct/100 is always before the deadline, so the obvious formula extends nothing at all. A share of the gap to the hard end makes each action close a fraction of what is left, so the grants shrink as the game runs, which is the pressure a constant grant never relieves.

Times are int64 and the unit is the caller's, block heights or unix seconds, as long as it is consistent. Nothing here reads the chain, so a realm can test its whole endgame without one.

Live game: r/moul/x/games/lastwords · render it at /r/moul/x/games/lastwords/v0.


Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.

🧪 Highly experimental — potentially vibe-coded. Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: DISCLAIMER.