json.gno

4.44 Kb ยท 183 lines
  1package chess
  2
  3import (
  4	"bytes"
  5	"errors"
  6	"std"
  7	"strconv"
  8	"time"
  9
 10	"gno.land/p/morgan/chess"
 11	"gno.land/p/morgan/chess/glicko2"
 12	"gno.land/r/sys/users"
 13)
 14
 15// This file contains a bunch of JSON marshalers.
 16// These should disappear eventually!
 17// https://github.com/gnolang/gno/issues/1655
 18
 19func (g Game) MarshalJSON() (retBytes []byte, err error) {
 20	var b bytes.Buffer
 21	b.WriteByte('{')
 22
 23	nilAddr := func(na *std.Address) string {
 24		if na == nil {
 25			return `null`
 26		}
 27		return `"` + na.String() + `"`
 28	}
 29	mjson := func(s string, val interface{ MarshalJSON() ([]byte, error) }, comma bool) {
 30		if err != nil {
 31			return
 32		}
 33		var res []byte
 34		res, err = val.MarshalJSON()
 35		if err != nil {
 36			return
 37		}
 38		b.WriteString(`"` + s + `":`)
 39		b.Write(res)
 40		if comma {
 41			b.WriteByte(',')
 42		}
 43	}
 44
 45	b.WriteString(`"id":"` + g.ID + `",`)
 46	b.WriteString(`"white":"` + g.White.String() + `",`)
 47	b.WriteString(`"black":"` + g.Black.String() + `",`)
 48
 49	mjson("position", jsonPosition{g.Position}, true)
 50	mjson("state", g.State, true)
 51	mjson("winner", g.Winner, true)
 52	if err != nil {
 53		return
 54	}
 55
 56	b.WriteString(`"creator":"` + g.Creator.String() + `",`)
 57	b.WriteString(`"created_at":"` + g.CreatedAt.Format(time.RFC3339) + `",`)
 58	b.WriteString(`"draw_offerer":` + nilAddr(g.DrawOfferer) + ",")
 59	b.WriteString(`"concluder":` + nilAddr(g.Concluder) + ",")
 60
 61	mjson("time", g.Time, false)
 62	if err != nil {
 63		return
 64	}
 65
 66	b.WriteByte('}')
 67	return b.Bytes(), nil
 68}
 69
 70type jsonPosition struct {
 71	chess.Position
 72}
 73
 74func (p jsonPosition) MarshalJSON() ([]byte, error) {
 75	var b bytes.Buffer
 76	b.WriteByte('{')
 77
 78	bfen := p.EncodeFEN()
 79	b.WriteString(`"fen":"` + bfen + `",`)
 80
 81	b.WriteString(`"moves":[`)
 82
 83	for idx, m := range p.Moves {
 84		b.WriteString(`"` + m.String() + `"`)
 85		if idx != len(p.Moves)-1 {
 86			b.WriteByte(',')
 87		}
 88	}
 89
 90	b.WriteByte(']')
 91	b.WriteByte('}')
 92	return b.Bytes(), nil
 93}
 94
 95func (w Winner) MarshalJSON() ([]byte, error) {
 96	if n := int(w); n < len(winnerString) {
 97		return []byte(`"` + winnerString[n] + `"`), nil
 98	}
 99	return nil, errors.New("invalid winner value")
100}
101
102func (g GameState) MarshalJSON() ([]byte, error) {
103	if int(g) >= len(gameStatesSnake) {
104		return nil, errors.New("invalid game state")
105	}
106	return []byte(`"` + gameStatesSnake[g] + `"`), nil
107}
108
109func (tc *TimeControl) MarshalJSON() ([]byte, error) {
110	if tc == nil {
111		return []byte("null"), nil
112	}
113	var buf bytes.Buffer
114
115	buf.WriteByte('{')
116	buf.WriteString(`"seconds":` + strconv.Itoa(tc.Seconds) + `,`)
117	buf.WriteString(`"increment":` + strconv.Itoa(tc.Increment) + `,`)
118	buf.WriteString(`"started_at":"` + tc.StartedAt.Format(time.RFC3339) + `",`)
119
120	buf.WriteString(`"move_timestamps":[`)
121	for idx, mt := range tc.MoveTimestamps {
122		buf.WriteString(`"` + mt.Format(time.RFC3339) + `"`)
123		if idx != len(tc.MoveTimestamps)-1 {
124			buf.WriteByte(',')
125		}
126	}
127	buf.WriteString("],")
128
129	buf.WriteString(`"white_time":` + strconv.FormatInt(tc.WhiteTime.Milliseconds(), 10) + ",")
130	buf.WriteString(`"black_time":` + strconv.FormatInt(tc.BlackTime.Milliseconds(), 10))
131	buf.WriteByte('}')
132
133	return buf.Bytes(), nil
134}
135
136func (p Player) MarshalJSON() ([]byte, error) {
137	u := users.ResolveAddress(p.Address)
138
139	var buf bytes.Buffer
140	buf.WriteByte('{')
141
142	buf.WriteString(`"address":"` + p.Address.String() + `",`)
143	if u == nil {
144		buf.WriteString(`"username":"",`)
145	} else {
146		buf.WriteString(`"username":"` + u.Name() + `",`)
147	}
148
149	for idx, cat := range categoryList {
150		stat := p.CategoryInfo[cat]
151		buf.WriteString(`"` + cat.String() + `":{`)
152		buf.WriteString(`"wins":` + strconv.Itoa(stat.Wins) + ",")
153		buf.WriteString(`"losses":` + strconv.Itoa(stat.Losses) + ",")
154		buf.WriteString(`"draws":` + strconv.Itoa(stat.Draws) + ",")
155		buf.WriteString(`"rating":`)
156		if res, err := (jsonPlayerRating{stat.PlayerRating}).MarshalJSON(); err != nil {
157			return nil, err
158		} else {
159			buf.Write(res)
160		}
161		buf.WriteByte(',')
162		buf.WriteString(`"position":` + strconv.Itoa(p.LeaderboardPosition(cat)))
163		buf.WriteByte('}')
164		if idx != len(categoryList)-1 {
165			buf.WriteByte(',')
166		}
167	}
168
169	buf.WriteByte('}')
170	return buf.Bytes(), nil
171}
172
173type jsonPlayerRating struct{ *glicko2.PlayerRating }
174
175func (p jsonPlayerRating) MarshalJSON() ([]byte, error) {
176	var buf bytes.Buffer
177	buf.WriteByte('{')
178	buf.WriteString(`"rating":` + strconv.FormatFloat(p.Rating, 'f', 5, 64) + `,`)
179	buf.WriteString(`"deviation":` + strconv.FormatFloat(p.RatingDeviation, 'f', 5, 64) + `,`)
180	buf.WriteString(`"volatility":` + strconv.FormatFloat(p.RatingVolatility, 'f', 5, 64))
181	buf.WriteByte('}')
182	return buf.Bytes(), nil
183}