96// The coins are already at the realm's address: the chain moved them
97// before the call. All that is left is to write down who they belong to.
98 a.lobby = withAddr(a.lobby, player)
99 a.tickets = withString(a.tickets, ticket)
100 arenas.Set(id, a)
101 hold(a.stake)
102// The guard above says the coins arrived. This looks at the balance.
103 assertSolvent(0, cur)
104
105 chain.Emit("Entered",
106"arena", id,
107"player", player.String(),
108"stake", itoa(a.stake),
109"ticket", ticket,
110"lobby", itoa(int64(len(a.lobby))),
111 )
112return id
113}
114
115// Leave takes the caller out of the lobby of an arena and sends their stake
116// back. It works until the game starts. The last player out deletes the
117// arena: nothing is left on chain of a game nobody played.
118func Leave(cur realm, id string) {
119 player := callerOf(0, cur)
120 a := mustArena(id)
121 seat := indexOfAddr(a.lobby, player)
122if seat < 0 {
123 panic(errNotInLobby)
124 }
125 a.lobby = withoutAddr(a.lobby, seat)
126 a.tickets = withoutString(a.tickets, seat)
127if len(a.lobby) == 0 {
128 arenas.Remove(id)
129 }
130 release(a.stake)
131
132 pay(0, cur, player, a.stake)
133 assertSolvent(0, cur)
134
135 chain.Emit("Left",
136"arena", id,
137"player", player.String(),
138"stake", itoa(a.stake),
139 )
140}
141
142// ExpireLobby closes an arena whose game never started: every player in the
143// lobby gets their stake back, and the arena is deleted. Anyone can call it
144// once the arena stopped taking entries, an hour after it was created.
145func ExpireLobby(cur realm, id string) {
146 caller := callerOf(0, cur)
147 a := mustArena(id)
148if a.round != nil {
149 panic(errRoundRunning)
150 }
151if now() <= a.created+entryWindow {
152 panic(errNotExpired)
153 }
154 players := a.lobby
155 arenas.Remove(id)
156 release(a.stake * int64(len(players)))
157for _, p := range players {
158 pay(0, cur, p, a.stake)
159 }
160 assertSolvent(0, cur)
161
162 chain.Emit("LobbyExpired",
163"arena", id,
164"players", itoa(int64(len(players))),
165"caller", caller.String(),
166 )
167}
168
169// The four helpers below return a new slice of exactly the length of its
170// content, so that nothing else stays in storage. They return nil for an
171// empty list.
172
173// withAddr returns list with v added at the end.
174func withAddr(list []address, v address) []address {
175 out := make([]address, len(list), len(list)+1)
176 copy(out, list)
177return append(out, v)
178}
179
180// withString returns list with v added at the end.
181func withString(list []string, v string) []string {
182 out := make([]string, len(list), len(list)+1)
183 copy(out, list)
184return append(out, v)
185}
186
187// withoutAddr returns list without the element at index at.
188func withoutAddr(list []address, at int) []address {
189if len(list) == 1 {
190returnnil
191 }
192 out := make([]address, 0, len(list)-1)
193 out = append(out, list[:at]...)
194return append(out, list[at+1:]...)
195}
196
197// withoutString returns list without the element at index at.
198func withoutString(list []string, at int) []string {
199if len(list) == 1 {
200returnnil
201 }
202 out := make([]string, 0, len(list)-1)
203 out = append(out, list[:at]...)
204return append(out, list[at+1:]...)
205}
206
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.