dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

commit d46e69ecbdc761b09c613de4c05d51a762746a7b
parent 001cb7bcdf4ca6f74f99fd27a88906e91a8b3f54
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Wed, 14 Jun 2023 02:14:13 -0700

analyse game endpoint

Diffstat:
Mpkg/web/handlers/chess.go | 25+++++++++++++++++++++++++
Mpkg/web/handlers/interceptors/chess.go | 50++++++++++++++++++++++++++++++++++++--------------
Mpkg/web/web.go | 1+
3 files changed, 62 insertions(+), 14 deletions(-)

diff --git a/pkg/web/handlers/chess.go b/pkg/web/handlers/chess.go @@ -112,6 +112,31 @@ func ChessHandler(c echo.Context) error { return c.Render(http.StatusOK, "chess", data) } +func ChessGameAnalyseHandler(c echo.Context) error { + key := c.Param("key") + db := c.Get("database").(*database.DkfDB) + authUser := c.Get("authUser").(*database.User) + if !authUser.IsAdmin { + return c.Redirect(http.StatusFound, "/") + } + g, err := interceptors.ChessInstance.GetGame(key) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } + game := g.Game + if game.Outcome() == chess.NoOutcome { + return c.String(http.StatusOK, "no outcome") + } + res, err := interceptors.AnalyseGame(game.String()) + if err != nil { + return c.String(http.StatusOK, err.Error()) + } + g.DbChessGame.AccuracyWhite = res.WhiteAccuracy + g.DbChessGame.AccuracyBlack = res.BlackAccuracy + g.DbChessGame.DoSave(db) + return c.String(http.StatusOK, "done") +} + func ChessGameFormHandler(c echo.Context) error { key := c.Param("key") csrf, _ := c.Get("csrf").(string) diff --git a/pkg/web/handlers/interceptors/chess.go b/pkg/web/handlers/interceptors/chess.go @@ -387,7 +387,15 @@ func (g *ChessGame) drawPlayerCard(key string, isBlack, isSpectator, isYourTurn, {{ if .IsSpectator }} <tr><td style="padding: 10px 0;" colspan="2"><a href="?{{ if not .IsFlipped }}r=1{{ end }}" style="color: #eee;">Flip board</a></td></tr> {{ end }} - <tr style="height: 100%;"><td colspan="2"><div style="color: #eee;">Outcome: <span id="outcome"></span></div></td></tr> + <tr style="height: 100%;"> + <td colspan="2"> + <div style="color: #eee;">Outcome: <span id="outcome"></span></div> + {{ if .IsAnalysed }} + <div style="color: #eee;">White accuracy: <span id="white-accuracy">{{ .WhiteAccuracy }}</span></div> + <div style="color: #eee;">Black accuracy: <span id="black-accuracy">{{ .BlackAccuracy }}</span></div> + {{ end }} + </td> + </tr> {{ if .GameOver }}<tr><td colspan="2"><div><textarea>{{ .PGN }}</textarea></div></td></tr>{{ end }} </table> @@ -420,6 +428,9 @@ func (g *ChessGame) drawPlayerCard(key string, isBlack, isSpectator, isYourTurn, "WhiteScore": whiteScore, "BlackAdvantage": blackAdvantage, "BlackScore": blackScore, + "IsAnalysed": g.DbChessGame.AccuracyWhite != 0 && g.DbChessGame.AccuracyBlack != 0, + "WhiteAccuracy": g.DbChessGame.AccuracyWhite, + "BlackAccuracy": g.DbChessGame.AccuracyBlack, } fns := template.FuncMap{ @@ -742,20 +753,25 @@ func CalcAdvantage(position *chess.Position) (string, string, string, string) { return whiteAdvantage, whiteScoreLbl, blackAdvantage, blackScoreLbl } -func Test() { +type AnalyseResult struct { + WhiteAccuracy float64 + BlackAccuracy float64 +} + +func AnalyseGame(pgn string) (out AnalyseResult, err error) { // https://github.com/lichess-org/lila/blob/9204a337492c1be4b7b8dabd68941d8934439cbc/modules/analyse/src/main/AccuracyPercent.scala#L71 // sbt 'testOnly lila.analyse.AccuracyPercentTest' // lichess: 86% 97% (game against stockfish) // Lila: 26.036024039104852 25.007112871751964 // Ours: 28.07242196565701 25.629909658576725 // 35, -29, 37, -42, 31, -15, 28, -16, 16, -4, 30, -24, 13, -14, 0, -17, 9, 6, -17, 8, -3, -5, -1, 5, -13, 20, -21, 90, -59, 77, -55, 70, -84, 116, -97, 68, -50, 46, -54, 93, -53, 57, -62, 61, -18, 11, -17, 41, -15, 13, -19, 8, 0, 22, -76, 44, -46, 87, -62, 62, -56, 59, -28, 69, -50, 70, -63, 63, -27, 30, -53, 14, -65, 43, -17, 398, -430, 565, -597, 793, -802, 837, -821, 908, -915, 957, -984, 1073, -981, 1285 - pgn := "1. d4 Nf6 2. Nf3 e6 3. Bf4 { A46 Indian Defense: London System } c5 4. e3 d5 5. c3 Bd6 6. Bg3 O-O " + - "7. Bd3 Qc7 8. Bxd6 Qxd6 9. O-O Nbd7 10. Nbd2 e5 11. dxe5 Nxe5 12. Nxe5 Qxe5 13. Nf3 Qe7 14. b3 Rd8 " + - "15. Rc1 Bg4 16. Be2 Bf5 17. Bd3 Ne4 18. Qc2 Rd6 19. Rfd1 Re8 20. Bb5 Rc8 21. Bd3 Rcd8 22. Nd2 h6 " + - "23. Nxe4 dxe4 24. Bc4 b6 25. Rxd6 Qxd6 26. h3 a5 27. Qe2 Qd2 28. Qxd2 Rxd2 29. a4 Be6 30. Bxe6 fxe6 " + - "31. Rb1 Kf7 32. Kf1 Rc2 33. c4 h5 34. g4 hxg4 35. hxg4 Kf6 36. Kg2 Ke5 37. Kg3 Rd2 38. f3 Re2 39. f4+ Kf6 " + - "40. g5+ Kf5 41. Rh1 Rxe3+ 42. Kh4 Rxb3 43. g6 Kxf4 44. Kh5 Ra3 45. Rf1+ Rf3 46. Rxf3+ exf3 47. Kh4 f2 " + - "48. Kh3 Kf3 49. Kh2 f1=R 50. Kh3" // Rh1# { Black wins by checkmate. } 0-1" + //pgn := "1. d4 Nf6 2. Nf3 e6 3. Bf4 { A46 Indian Defense: London System } c5 4. e3 d5 5. c3 Bd6 6. Bg3 O-O " + + // "7. Bd3 Qc7 8. Bxd6 Qxd6 9. O-O Nbd7 10. Nbd2 e5 11. dxe5 Nxe5 12. Nxe5 Qxe5 13. Nf3 Qe7 14. b3 Rd8 " + + // "15. Rc1 Bg4 16. Be2 Bf5 17. Bd3 Ne4 18. Qc2 Rd6 19. Rfd1 Re8 20. Bb5 Rc8 21. Bd3 Rcd8 22. Nd2 h6 " + + // "23. Nxe4 dxe4 24. Bc4 b6 25. Rxd6 Qxd6 26. h3 a5 27. Qe2 Qd2 28. Qxd2 Rxd2 29. a4 Be6 30. Bxe6 fxe6 " + + // "31. Rb1 Kf7 32. Kf1 Rc2 33. c4 h5 34. g4 hxg4 35. hxg4 Kf6 36. Kg2 Ke5 37. Kg3 Rd2 38. f3 Re2 39. f4+ Kf6 " + + // "40. g5+ Kf5 41. Rh1 Rxe3+ 42. Kh4 Rxb3 43. g6 Kxf4 44. Kh5 Ra3 45. Rf1+ Rf3 46. Rxf3+ exf3 47. Kh4 f2 " + + // "48. Kh3 Kf3 49. Kh2 f1=R 50. Kh3" // Rh1# { Black wins by checkmate. } 0-1" pgnOpt, _ := chess.PGN(strings.NewReader(pgn)) g := chess.NewGame(pgnOpt) positions := g.Positions() @@ -763,11 +779,11 @@ func Test() { eng, err := uci.New("stockfish") if err != nil { logrus.Error(err) - return + return out, err } if err := eng.Run(uci.CmdUCI, uci.CmdIsReady, uci.CmdUCINewGame); err != nil { logrus.Error(err) - return + return out, err } defer eng.Close() @@ -789,15 +805,21 @@ func Test() { cp *= -1 } cps = append(cps, cp) - fmt.Printf("%d: %d/%d %d %d\n", idx/2, idx, len(positions), idx%2, cp) + //fmt.Printf("%d: %d/%d %d %d\n", idx/2, idx, len(positions), idx%2, cp) } s := make([]string, 0) for _, c := range cps { s = append(s, strconv.Itoa(c)) } - fmt.Println(strings.Join(s, ", ")) - fmt.Println(gameAccuracy(cps)) + + //fmt.Println(strings.Join(s, ", ")) + + wa, ba := gameAccuracy(cps) + return AnalyseResult{ + WhiteAccuracy: wa, + BlackAccuracy: ba, + }, nil } func standardDeviation(num []WinPercent) float64 { diff --git a/pkg/web/web.go b/pkg/web/web.go @@ -100,6 +100,7 @@ func getMainServer(db *database.DkfDB, i18nBundle *i18n.Bundle, renderer *tmp.Te authGroup.POST("/chess", handlers.ChessHandler) authGroup.GET("/chess/:key", handlers.ChessGameHandler) authGroup.POST("/chess/:key", handlers.ChessGameHandler) + authGroup.GET("/chess/:key/analyse", handlers.ChessGameAnalyseHandler) authGroup.GET("/chess/:key/form", handlers.ChessGameFormHandler) authGroup.POST("/chess/:key/form", handlers.ChessGameFormHandler) authGroup.GET("/settings/chat", handlers.SettingsChatHandler)