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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

store.gno

3.71 Kb · 152 lines
  1package arena
  2
  3import (
  4	"encoding/binary"
  5
  6	"gno.land/p/g188vafzutzvlfw6wt7u3s62xtuvm0epmu8ufmfz/gnomepit/engine"
  7	"gno.land/p/nt/avl/v0"
  8)
  9
 10var (
 11	chunks      avl.Tree  // 4-byte chunk number → chunk string
 12	players     avl.Tree  // address → player string
 13	ladder      *avl.Node // ladderKey of every rated player → nil
 14	clanRecords string
 15	openList    string
 16)
 17
 18func chunkKey(id int) string {
 19	var k [4]byte
 20	binary.BigEndian.PutUint32(k[:], uint32((id-1)/chunkSize))
 21	return string(k[:])
 22}
 23
 24// loadMatch returns match id, or false when it does not exist or was removed.
 25func loadMatch(rules *engine.Ruleset, id int) (record, bool) {
 26	if id < 1 || id > lastID {
 27		return record{}, false
 28	}
 29	rec := chunkRecord(stringAt(&chunks, chunkKey(id)), (id-1)%chunkSize)
 30	if rec == "" {
 31		return record{}, false
 32	}
 33	return decodeMatch(rules, rec), true
 34}
 35
 36func saveMatch(rules *engine.Ruleset, id int, m record) {
 37	putRecord(id, encodeMatch(rules, m))
 38}
 39
 40// dropMatch removes match id; an absent id is left alone.
 41func dropMatch(id int) {
 42	if id < 1 {
 43		return
 44	}
 45	if chunkRecord(stringAt(&chunks, chunkKey(id)), (id-1)%chunkSize) != "" {
 46		putRecord(id, "")
 47	}
 48}
 49
 50func putRecord(id int, rec string) {
 51	chunks.Set(chunkKey(id), withChunkRecord(stringAt(&chunks, chunkKey(id)), (id-1)%chunkSize, rec))
 52}
 53
 54// stringAt returns the string under key, "" when there is none.
 55func stringAt(t *avl.Tree, key string) string {
 56	v := t.Get(key)
 57	if v == nil {
 58		return ""
 59	}
 60	return v.(string)
 61}
 62
 63func loadPlayer(a address) playerRecord {
 64	return decodePlayer(stringAt(&players, string(a)))
 65}
 66
 67func savePlayer(a address, p playerRecord) {
 68	players.Set(string(a), encodePlayer(p))
 69}
 70
 71// loadStanding returns a's standing, nil before their first rated match.
 72func loadStanding(a address) *standing {
 73	return decodeStanding(stringAt(&players, string(a)))
 74}
 75
 76func saveStanding(a address, st *standing) {
 77	players.Set(string(a), withStanding(stringAt(&players, string(a)), st))
 78}
 79
 80// add appends id unless the player already has it.
 81func (p *playerRecord) add(id int) {
 82	for _, have := range p.ids {
 83		if have == id {
 84			return
 85		}
 86	}
 87	p.ids = append(p.ids, id)
 88}
 89
 90func (p *playerRecord) remove(id int) {
 91	for i, have := range p.ids {
 92		if have == id {
 93			p.ids = append(p.ids[:i:i], p.ids[i+1:]...)
 94			return
 95		}
 96	}
 97}
 98
 99// newest returns up to limit ids, newest first, after skipping offset of them.
100func (p playerRecord) newest(offset, limit int) []int {
101	var out []int
102	for i := len(p.ids) - 1 - offset; i >= 0 && len(out) < limit; i-- {
103		out = append(out, p.ids[i])
104	}
105	return out
106}
107
108// ceiling: each change rewrites the whole open list, 8 bytes per open challenge, so its gas
109// grows with the board; an avl index keyed by expiry and id if the board holds thousands.
110func openAdd(id int, expires int64) {
111	openList += encodeOpen([]openEntry{{id: id, expires: expires}})
112}
113
114func openRemove(id int) {
115	entries := openEntries(openList)
116	for i, e := range entries {
117		if e.id == id {
118			openList = encodeOpen(append(entries[:i:i], entries[i+1:]...))
119			return
120		}
121	}
122}
123
124// openNewest returns up to limit unexpired ids, newest first, after skipping offset of them.
125func openNewest(now int64, offset, limit int) []int {
126	entries := openEntries(openList)
127	var out []int
128	for i := len(entries) - 1; i >= 0 && entries[i].expires >= now; i-- {
129		if offset > 0 {
130			offset--
131			continue
132		}
133		if len(out) == limit {
134			break
135		}
136		out = append(out, entries[i].id)
137	}
138	return out
139}
140
141// openClear removes up to max expired entries from the front and returns their ids.
142func openClear(now int64, max int) []int {
143	entries := openEntries(openList)
144	n := 0
145	var ids []int
146	for n < len(entries) && n < max && entries[n].expires < now {
147		ids = append(ids, entries[n].id)
148		n++
149	}
150	openList = encodeOpen(entries[n:])
151	return ids
152}