render.gno
2.16 Kb · 77 lines
1package pingpong
2
3import (
4 "chain/runtime/unsafe"
5 "strconv"
6 "strings"
7)
8
9const pageSize = 50
10
11// Render serves "" (the first page), "page/N" and "game/<id>".
12func Render(path string) string {
13 switch {
14 case path == "":
15 return renderPage(1)
16 case strings.HasPrefix(path, "page/"):
17 n, err := strconv.Atoi(strings.TrimPrefix(path, "page/"))
18 if err != nil || n < 1 {
19 return "Not found."
20 }
21 return renderPage(n)
22 case strings.HasPrefix(path, "game/"):
23 id := strings.TrimPrefix(path, "game/")
24 if !games.Has(id) {
25 return "Not found."
26 }
27 return renderGame(games.Get(id).(*Game))
28 }
29 return "Not found."
30}
31
32// renderPage lists the games newest first, pageSize to a page.
33func renderPage(n int) string {
34 var b strings.Builder
35 b.WriteString("# pingpong\n\n")
36 pages := (games.Size() + pageSize - 1) / pageSize
37 if n > pages {
38 b.WriteString("No games on this page.\n")
39 return b.String()
40 }
41 games.ReverseIterateByOffset((n-1)*pageSize, pageSize, func(_ string, v any) bool {
42 g := v.(*Game)
43 b.WriteString("- [**" + g.ID + "**](" + selfPath + ":game/" + g.ID + ") " +
44 g.First.String() + " vs " + g.Second.String() + " · " + status(g) + "\n")
45 return false
46 })
47 if n < pages {
48 b.WriteString("\n[Next page](" + selfPath + ":page/" + strconv.Itoa(n+1) + ")\n")
49 }
50 return b.String()
51}
52
53func renderGame(g *Game) string {
54 var b strings.Builder
55 b.WriteString("# Game " + g.ID + "\n\n")
56 b.WriteString("- First: " + g.First.String() + "\n")
57 b.WriteString("- Second: " + g.Second.String() + "\n")
58 b.WriteString("- Status: " + status(g) + "\n")
59 if g.Started {
60 b.WriteString("- Turn: " + strconv.Itoa(g.Turn) + "\n")
61 b.WriteString("- Next: " + g.Next.String() + "\n")
62 }
63 b.WriteString("\n[All games](" + selfPath + ")\n")
64 return b.String()
65}
66
67func status(g *Game) string {
68 if !g.Started {
69 return "pending"
70 }
71 return "started · turn " + strconv.Itoa(g.Turn) + " · next " + g.Next.String()
72}
73
74// selfPath is this realm's path on gnoweb. It is read at package init, where
75// the realm itself is current; Render is not crossing, so reading it there
76// would give the caller's path. It only builds links.
77var selfPath = strings.TrimPrefix(unsafe.CurrentRealm().PkgPath(), "gno.land")