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}