commit d31d755055ba94255b776c0a4571885485b50fe8
parent d4b00146f6a117a368697ac6b0ac890d07449e89
Author: n0tr1v <n0tr1v@protonmail.com>
Date: Mon, 12 Jun 2023 09:58:20 -0700
calculate and display advantage
Diffstat:
2 files changed, 105 insertions(+), 15 deletions(-)
diff --git a/pkg/web/handlers/handlers.go b/pkg/web/handlers/handlers.go
@@ -5192,6 +5192,11 @@ Loop:
send(fmt.Sprintf(`<style>#%s { display: none; }</style>`, payload.EnPassant))
}
+ // Render advantages
+ whiteAdv, blackAdv := interceptors.CalcAdvantage(g.Game.Position())
+ send(fmt.Sprintf(`<style>#white-advantage:after { content: "%s" !important; }</style>`, whiteAdv))
+ send(fmt.Sprintf(`<style>#black-advantage:after { content: "%s" !important; }</style>`, blackAdv))
+
// Render last move
send(`<style>.square { background-color: transparent !important; }</style>`)
send(fmt.Sprintf(`<style>.square_%d, .square_%d { background-color: %s !important; }</style>`,
diff --git a/pkg/web/handlers/interceptors/chess.go b/pkg/web/handlers/interceptors/chess.go
@@ -20,6 +20,7 @@ import (
"image/png"
"sort"
"strconv"
+ "strings"
"sync"
"time"
)
@@ -317,6 +318,8 @@ func (g *ChessGame) drawPlayerCard(key string, isBlack, isSpectator, isYourTurn
background-color: darkred;
display: inline-block;
}
+#white-advantage:after { content: "{{ .WhiteAdvantage }}"; }
+#black-advantage:after { content: "{{ .BlackAdvantage }}"; }
</style>
<table style="width: 100%; height: 100%;">
<tr>
@@ -340,13 +343,23 @@ func (g *ChessGame) drawPlayerCard(key string, isBlack, isSpectator, isYourTurn
</tr>
<tr>
<td>
- {{ if or .IsSpectator .GameOver }}
- {{ .Table }}
- {{ else }}
- <form method="post">
+ {{ if not (and .IsSpectator .GameOver) }}
+ <form method="post" style="display: inline-block;">
<input type="hidden" name="message" value="resign" />
<button type="submit" style="background-color: #aaa; margin: 5px 0;">Resign</button>
</form>
+ {{ end }}
+ <span style="color: #eee; display: inline-block;">
+ (<span id="white-advantage" style="color: #888;" title="white advantage"></span> |
+ <span id="black-advantage" style="color: #888;" title="black advantage"></span>)
+ </span>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ {{ if or .IsSpectator .GameOver }}
+ {{ .Table }}
+ {{ else }}
<div style="position: relative;">
<iframe src="/chess/{{ .Key }}/form" style="position: absolute; top: 0; left: 0; border: 0px solid red; z-index: 999; width: 100%; height: 100%;"></iframe>
<div style="aspect-ratio: 1/1; height: 70%;">
@@ -371,19 +384,22 @@ func (g *ChessGame) drawPlayerCard(key string, isBlack, isSpectator, isYourTurn
enemy := utils.Ternary(isBlack, g.Player1, g.Player2)
imgB64 := g.renderBoardB64(isBlack)
+ whiteAdvantage, blackAdvantage := CalcAdvantage(g.Game.Position())
data := map[string]any{
- "Key": key,
- "IsFlipped": isBlack,
- "IsSpectator": isSpectator,
- "White": g.Player1,
- "Black": g.Player2,
- "Username": enemy.Username,
- "Table": template.HTML(g.renderBoardHTML(isBlack, imgB64)),
- "ImgB64": imgB64,
- "Outcome": g.Game.Outcome().String(),
- "GameOver": g.Game.Outcome() != chess.NoOutcome,
- "PGN": g.Game.String(),
+ "Key": key,
+ "IsFlipped": isBlack,
+ "IsSpectator": isSpectator,
+ "White": g.Player1,
+ "Black": g.Player2,
+ "Username": enemy.Username,
+ "Table": template.HTML(g.renderBoardHTML(isBlack, imgB64)),
+ "ImgB64": imgB64,
+ "Outcome": g.Game.Outcome().String(),
+ "GameOver": g.Game.Outcome() != chess.NoOutcome,
+ "PGN": g.Game.String(),
+ "WhiteAdvantage": whiteAdvantage,
+ "BlackAdvantage": blackAdvantage,
}
fns := template.FuncMap{
@@ -585,3 +601,72 @@ func (g *ChessGame) updatePiecesCache(mov chess.Move) {
g.PiecesCache[chess.D8] = "img_56"
}
}
+
+func pieceMap(board *chess.Board) map[chess.Piece]int {
+ m := board.SquareMap()
+ out := make(map[chess.Piece]int)
+ for _, piece := range m {
+ out[piece]++
+ }
+ return out
+}
+
+/**
+white chess king ♔ U+2654 ♔ ♔
+white chess queen ♕ U+2655 ♕ ♕
+white chess rook ♖ U+2656 ♖ ♖
+white chess bishop ♗ U+2657 ♗ ♗
+white chess knight ♘ U+2658 ♘ ♘
+white chess pawn ♙ U+2659 ♙ ♙
+black chess king ♚ U+265A ♚ ♚
+black chess queen ♛ U+265B ♛ ♛
+black chess rook ♜ U+265C ♜ ♜
+black chess bishop ♝ U+265D ♝ ♝
+black chess knight ♞ U+265E ♞ ♞
+black chess pawn ♟︎ U+265F ♟ ♟
+*/
+
+// CalcAdvantage ...
+func CalcAdvantage(position *chess.Position) (string, string) {
+ m := pieceMap(position.Board())
+ var whiteAdvantage, blackAdvantage string
+ var whiteScore, blackScore int
+ diff := m[chess.WhiteQueen] - m[chess.BlackQueen]
+ whiteScore += diff * 9
+ blackScore += -diff * 9
+ whiteAdvantage += strings.Repeat("♕", utils.MaxInt(diff, 0))
+ blackAdvantage += strings.Repeat("♛", utils.MaxInt(-diff, 0))
+ diff = m[chess.WhiteRook] - m[chess.BlackRook]
+ whiteScore += diff * 5
+ blackScore += -diff * 5
+ whiteAdvantage += strings.Repeat("♖", utils.MaxInt(diff, 0))
+ blackAdvantage += strings.Repeat("♜", utils.MaxInt(-diff, 0))
+ diff = m[chess.WhiteBishop] - m[chess.BlackBishop]
+ whiteScore += diff * 3
+ blackScore += -diff * 3
+ whiteAdvantage += strings.Repeat("♗", utils.MaxInt(diff, 0))
+ blackAdvantage += strings.Repeat("♝", utils.MaxInt(-diff, 0))
+ diff = m[chess.WhiteKnight] - m[chess.BlackKnight]
+ whiteScore += diff * 3
+ blackScore += -diff * 3
+ whiteAdvantage += strings.Repeat("♘", utils.MaxInt(diff, 0))
+ blackAdvantage += strings.Repeat("♞", utils.MaxInt(-diff, 0))
+ diff = m[chess.WhitePawn] - m[chess.BlackPawn]
+ whiteScore += diff * 1
+ blackScore += -diff * 1
+ whiteAdvantage += strings.Repeat("♙", utils.MaxInt(diff, 0))
+ blackAdvantage += strings.Repeat("♟", utils.MaxInt(-diff, 0))
+ if whiteScore > 0 {
+ whiteAdvantage += fmt.Sprintf("+%d", whiteScore)
+ }
+ if blackScore > 0 {
+ blackAdvantage += fmt.Sprintf("+%d", blackScore)
+ }
+ if whiteAdvantage == "" {
+ whiteAdvantage = "-"
+ }
+ if blackAdvantage == "" {
+ blackAdvantage = "-"
+ }
+ return whiteAdvantage, blackAdvantage
+}