nx_folkgame_lib.nx
buildroot/runtime/nx_folkgame_lib.nx
about
nx_folkgame_lib.nx -- THE LUDEME SUBSTRATE: one shared board-game core that reads a game as
DATA and plays it, so a new folk game is a SPEC and never a new organ. Named for the ludeme --
Browne's unit of game rule -- because the deliverable is the VOCABULARY, not the game list: the
117 rows of knowledge/compare/folkgames.registry exist to prove the vocabulary spans real human
game design well enough that novel games can later be SEARCHED out of it (the Ludi/Yavalath
result). A game that needs a new organ is a hole in the vocabulary and must be reported as one.
NO CAPS, BY CONSTRUCTION. Every array here is sized from the spec itself in a MEASURE pass and
filled in a SECOND pass, so there is no FG_MAX_CELLS to guess and none to raise later. This is
the estate law that a ceiling which has to be guessed is a defect generator in both directions:
too small truncates in silence, too large wastes memory, and raising it only moves the guess.
THE SPEC (rows, pipe-delimited, '#' comments). Every key is OPTIONAL except cells and linelen;
an unknown key is REFUSED BY NAME rather than ignored, because a silently-dropped rule is a game
that plays wrongly while looking parsed.
name|<slug>|<Title>
family|align
cells|<n> board size. REQUIRED.
linelen|<n> how many in a row makes a line. REQUIRED.
hand|<n> pieces each side places before movement. ABSENT = place until full.
win|line forming a line wins outright (Tic-Tac-Toe, Gomoku)
win|reduce|<n> reducing the opponent below <n> pieces wins (the Morris family)
capture|onmill completing a line removes one enemy piece
move|adj after hands are empty, step to an ADJACENT empty cell
fly|<n> at or below <n> pieces a side may move to ANY empty cell
lines|grid|<w>|<h>|<len> GENERATE every line on a w x h grid -- the generator, not 572 rows
line|a,b,c[,...] one explicit line (the Morris boards, which are not grids)
adj|grid|<w>|<h>|<mode> GENERATE grid adjacency. mode 0 orthogonal, 1 diagonal, 2 both
adj|<cell>|<n1,n2,...> one explicit adjacency row
xy|<cell>|<x>|<y> explicit draw position for a non-grid board
license_tier: ORIGINAL No hw writes (Rule 26). Sovereign syscalls only, integer only, no float.
dependencies 2 imports · 5 importers
imports: nx_syscalls.nxnx_estate_path.nx
imported by: nx_folkgame_ai_lib.nxnx_folkgame_align_gate.nxnx_folkgame_play.nxnx_folkgame_race_lib.nxnx_folkgame_sow_lib.nx
structs
| none |
consts
| 43 | const FG_PATHCAP: i64 = 1024 |
| 47 | const FG_HASH: i64 = 35 |
| 48 | const FG_NL: i64 = 10 |
| 49 | const FG_CR: i64 = 13 |
| 50 | const FG_PIPE: i64 = 124 |
| 51 | const FG_COMMA: i64 = 44 |
| 52 | const FG_MINUS: i64 = 45 |
| 53 | const FG_ZERO: i64 = 48 |
| 54 | const FG_NINE: i64 = 57 |
| 55 | const FG_DECIMAL: i64 = 10 |
| 56 | const FG_WORD: i64 = 8 |
| 59 | const FG_NUMSCRATCH: i64 = 28 |
| 60 | const FG_MISS: i64 = 0 - 999999 |
| 63 | const FG_H_CELLS: i64 = 0 |
| 64 | const FG_H_HAND: i64 = 1 |
| 65 | const FG_H_LINELEN: i64 = 2 |
| 66 | const FG_H_WINMODE: i64 = 3 |
| 67 | const FG_H_REDUCE: i64 = 4 |
| 68 | const FG_H_CAPTURE: i64 = 5 |
| 69 | const FG_H_MOVEADJ: i64 = 6 |
| 70 | const FG_H_FLYAT: i64 = 7 |
| 71 | const FG_H_NLINES: i64 = 8 |
| 72 | const FG_H_LINEW: i64 = 9 |
| 73 | const FG_H_ADJW: i64 = 10 |
| 74 | const FG_H_OFF_LINES: i64 = 11 |
| 75 | const FG_H_OFF_ADJ: i64 = 12 |
| 76 | const FG_H_OFF_ADJN: i64 = 13 |
| 77 | const FG_H_OFF_XY: i64 = 14 |
| 78 | const FG_H_OFF_STATE: i64 = 15 |
| 79 | const FG_H_OFF_SCAL: i64 = 16 |
| 80 | const FG_H_BYTES: i64 = 17 |
| 83 | const FG_H_GRIDW: i64 = 18 |
| 84 | const FG_H_GRIDH: i64 = 19 |
| 93 | const FG_H_FAMILY: i64 = 20 |
| 94 | const FG_H_PERSIDE: i64 = 21 |
| 95 | const FG_H_SEEDS: i64 = 22 |
| 96 | const FG_H_STORE: i64 = 23 |
| 97 | const FG_H_LAP: i64 = 24 |
| 98 | const FG_H_CAPMODE: i64 = 25 |
| 99 | const FG_H_CAPA: i64 = 26 |
| 100 | const FG_H_CAPB: i64 = 27 |
| 112 | const FG_H_TRACK: i64 = 28 |
| 113 | const FG_H_PIECES: i64 = 29 |
| 114 | const FG_H_DICEN: i64 = 30 |
| 115 | const FG_H_DICESIDES: i64 = 31 |
| 116 | const FG_H_ENTRY: i64 = 32 |
| 117 | const FG_H_BEAROFF: i64 = 33 |
| 118 | const FG_H_HIT: i64 = 34 |
| 119 | const FG_H_BLOCK: i64 = 35 |
| 124 | const FG_H_OFF_START: i64 = 36 |
| 125 | const FG_H_N: i64 = 40 |
| 127 | const FG_FAM_RACE: i64 = 2 |
| 129 | const FG_FAM_ALIGN: i64 = 0 |
| 130 | const FG_FAM_SOW: i64 = 1 |
| 133 | const FG_CAP_NONE: i64 = 0 |
| 134 | const FG_CAP_COUNT: i64 = 1 |
| 135 | const FG_CAP_EMPTY: i64 = 2 |
| 138 | const FG_S_SIDE: i64 = 0 |
| 139 | const FG_S_HAND1: i64 = 1 |
| 140 | const FG_S_HAND2: i64 = 2 |
| 141 | const FG_S_ON1: i64 = 3 |
| 142 | const FG_S_ON2: i64 = 4 |
| 143 | const FG_S_PHASE: i64 = 5 |
| 144 | const FG_S_WINNER: i64 = 6 |
| 145 | const FG_S_PLIES: i64 = 7 |
| 152 | const FG_S_N: i64 = 16 |
| 154 | const FG_PH_PLACE: i64 = 0 |
| 155 | const FG_PH_MOVE: i64 = 1 |
| 156 | const FG_PH_CAPTURE: i64 = 2 |
| 158 | const FG_WIN_LINE: i64 = 0 |
| 159 | const FG_WIN_REDUCE: i64 = 1 |
| 161 | const FG_MK_PLACE: i64 = 0 |
| 162 | const FG_MK_MOVE: i64 = 1 |
| 163 | const FG_MK_REMOVE: i64 = 2 |
| 164 | const FG_MV_KIND_SH: i64 = 32 |
| 165 | const FG_MV_FROM_SH: i64 = 16 |
| 166 | const FG_MV_MASK: i64 = 65535 |
| 169 | const FG_T_ONGOING: i64 = 0 |
| 170 | const FG_T_P1: i64 = 1 |
| 171 | const FG_T_P2: i64 = 2 |
| 172 | const FG_T_DRAW: i64 = 3 |
| 174 | const FG_ADJ_ORTH: i64 = 0 |
| 175 | const FG_ADJ_DIAG: i64 = 1 |
| 176 | const FG_ADJ_BOTH: i64 = 2 |
| 181 | const FG_LINE_ORTH: i64 = 0 |
| 182 | const FG_LINE_ALL: i64 = 1 |
| 183 | const FG_DEG_ORTH: i64 = 4 |
| 184 | const FG_DEG_BOTH: i64 = 8 |
functions
| 186 | func fg_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(2, s, n); return 0 } |
| 189 | func fg_num2(v: i64) -> i64 |
| 206 | func fg_lineend(buf: *u8, n: i64, i: i64) -> i64 |
| 214 | func fg_keyis(buf: *u8, ls: i64, le: i64, key: *u8) -> i64 |
| 225 | func fg_fieldoff(buf: *u8, ls: i64, le: i64, k: i64) -> i64 |
| 238 | func fg_wordis(buf: *u8, o: i64, le: i64, w: *u8) -> i64 |
| 248 | func fg_int_at(buf: *u8, o: i64, le: i64) -> i64 |
| 267 | func fg_field_int(buf: *u8, ls: i64, le: i64, k: i64) -> i64 |
| 271 | func fg_listn(buf: *u8, o: i64, le: i64) -> i64 called by 1: fg_parse_arena |
| 282 | func fg_listat(buf: *u8, o: i64, le: i64, k: i64) -> i64 |
| 295 | func fg_gridlines_n(w: i64, h: i64, l: i64, mode: i64) -> i64 |
| 305 | func fg_hdr(base: i64) -> *i64 { return base as *i64 } |
| 306 | func fg_cells(base: i64) -> i64 { let hd: *i64 = fg_hdr(base); return hd[FG_H_CELLS] } |
| 307 | func fg_linelen(base: i64) -> i64 { let hd: *i64 = fg_hdr(base); return hd[FG_H_LINELEN] } calls 1: fg_hdr |
| 308 | func fg_nlines(base: i64) -> i64 { let hd: *i64 = fg_hdr(base); return hd[FG_H_NLINES] } |
| 309 | func fg_bytes(base: i64) -> i64 { let hd: *i64 = fg_hdr(base); return hd[FG_H_BYTES] } calls 1: fg_hdr |
| 310 | func fg_state(base: i64) -> *i64 { let hd: *i64 = fg_hdr(base); return (base + hd[FG_H_OFF_STATE]) as *i64 } |
| 311 | func fg_scal(base: i64) -> *i64 { let hd: *i64 = fg_hdr(base); return (base + hd[FG_H_OFF_SCAL]) as *i64 } |
| 312 | func fg_at(base: i64, c: i64) -> i64 { let s: *i64 = fg_state(base); return s[c] } |
| 313 | func fg_side(base: i64) -> i64 { let s: *i64 = fg_scal(base); return s[FG_S_SIDE] } |
| 314 | func fg_phase(base: i64) -> i64 { let s: *i64 = fg_scal(base); return s[FG_S_PHASE] } |
| 315 | func fg_line_cell(base: i64, li: i64, k: i64) -> i64 |
| 320 | func fg_adj_n(base: i64, c: i64) -> i64 |
| 325 | func fg_adj_at(base: i64, c: i64, k: i64) -> i64 |
| 330 | func fg_xy_x(base: i64, c: i64) -> i64 |
| 335 | func fg_xy_y(base: i64, c: i64) -> i64 |
| 343 | func fg_setphase(base: i64) -> i64 |
| 357 | func fg_reset(base: i64) -> i64 |
| 374 | func fg_count(base: i64, side: i64) -> i64 |
| 389 | func fg_forms_line(base: i64, cell: i64, side: i64) -> i64 |
| 411 | func fg_maxmoves(base: i64) -> i64 |
| 416 | func fg_moves(base: i64, out: *i64) -> i64 |
| 489 | func fg_mv_kind(mv: i64) -> i64 { return mv >> FG_MV_KIND_SH } |
| 490 | func fg_mv_to(mv: i64) -> i64 { return mv & FG_MV_MASK } |
| 491 | func fg_mv_from(mv: i64) -> i64 { return (mv >> FG_MV_FROM_SH) & FG_MV_MASK } |
| 493 | func fg_apply(base: i64, mv: i64) -> i64 called by 6: fgai_searchfgai_bestfgai_selfplayfga_gamesmainmain calls 8: fg_hdrfg_statefg_scalfg_mv_kindfg_mv_tofg_mv_from+2 |
| 529 | func fg_terminal(base: i64, scratch: *i64) -> i64 |
| 557 | func fg_fill_gridlines(base: i64, gw: i64, gh: i64, gl: i64, mode: i64, at: i64) -> i64 |
| 611 | func fg_fill_gridadj(base: i64, gw: i64, gh: i64, mode: i64) -> i64 |
| 662 | func fg_parse_arena(buf: *u8, n: i64, arena: i64, cap: i64) -> i64 |
| 999 | func fg_parse(buf: *u8, n: i64) -> i64 { return fg_parse_arena(buf, n, 0, 0) } |
| 1005 | func fg_read_spec(path: *u8, lp: *i64) -> *u8 |
| 1017 | func fg_parse_file(path: *u8) -> i64 |
| 1026 | func fg_snapwords(base: i64) -> i64 |
| 1030 | func fg_save(base: i64, out: *i64) -> i64 |
| 1040 | func fg_load(base: i64, inp: *i64) -> i64 |
| 1053 | func fg_name_is(buf: *u8, ls: i64, le: i64, slug: *u8) -> i64 |
| 1072 | func fg_parse_named_at(buf: *u8, n: i64, slug: *u8, depth: i64) -> i64 called by 2: fg_parse_named_atfg_parse_named calls 8: fg_lineendfg_name_isfg_keyisfg_putsfg_fieldoffsys_mmap+2 |
| 1125 | func fg_parse_named(buf: *u8, n: i64, slug: *u8) -> i64 |
| 1128 | func fg_parse_named_file(path: *u8, slug: *u8) -> i64 |