1
0
mirror of https://github.com/maaslalani/gambit.git synced 2025-10-08 22:31:53 +02:00

feat: highlight king when in check and notify checkmates

* Implement Piece type

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
This commit is contained in:
Ayman Bagabas
2022-02-12 19:22:57 -05:00
committed by Maas Lalani
parent 19181d4ada
commit 478d8110e9
2 changed files with 100 additions and 14 deletions

View File

@@ -24,9 +24,11 @@ type MoveMsg struct {
// NotifyMsg is a message that gets emitted when the user makes a move.
type NotifyMsg struct {
From string
To string
Turn bool
From string
To string
Turn bool
Check bool
Checkmate bool
}
// Game stores the state of the chess game.
@@ -105,12 +107,12 @@ func (m *Game) View() string {
var rows = fen.Grid(m.board.ToFen())
for r := board.FirstRow; r < board.Rows; r++ {
row := rows[r]
row := pieces.ToPieces(rows[r])
rr := board.LastRow - r
// reverse the row if the board is flipped
if m.flipped {
row = rows[board.LastRow-r]
row = pieces.ToPieces(rows[board.LastRow-r])
for i, j := 0, len(row)-1; i < j; i, j = i+1, j-1 {
row[i], row[j] = row[j], row[i]
}
@@ -119,20 +121,26 @@ func (m *Game) View() string {
s.WriteString(Faint(fmt.Sprintf(" %d ", rr+1)) + border.Vertical)
for c, cell := range row {
display := pieces.Display[cell]
for c, piece := range row {
whiteTurn := m.board.Wtomove
display := piece.Display()
check := m.board.OurKingInCheck()
selected := position.ToSquare(r, c, m.flipped)
// The user selected the current cell, highlight it so they know it is
// selected.
// selected. If it is a check, highlight the king in red.
if m.selected == selected {
display = Cyan(display)
} else if check && piece.IsKing() {
if (whiteTurn && piece.IsWhite()) || (!whiteTurn && piece.IsBlack()) {
display = Red(display)
}
}
// Show all the cells to which the piece may move. If it is an empty cell
// we present a coloured dot, otherwise color the capturable piece.
if moves.IsLegal(m.pieceMoves, selected) {
if cell == "" {
if piece.IsEmpty() {
display = "."
}
display = Magenta(display)
@@ -190,9 +198,12 @@ func (m *Game) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}
func (m *Game) Notify(from, to string, turn bool) tea.Cmd {
func (m *Game) Notify(from, to string, turn, check, checkmate bool) tea.Cmd {
return func() tea.Msg {
return NotifyMsg{From: from, To: to, Turn: turn}
return NotifyMsg{
From: from, To: to, Turn: turn,
Check: check, Checkmate: checkmate,
}
}
}
@@ -211,16 +222,20 @@ func (m *Game) Select(square string) (tea.Model, tea.Cmd) {
for _, move := range m.pieceMoves {
if move.String() == from+to {
var cmds []tea.Cmd
m.board.Apply(move)
// We have applied a new move and the chess board is in a new state.
// We must generate the new legal moves for the new state.
m.moves = m.board.GenerateLegalMoves()
check := m.board.OurKingInCheck()
checkmate := check && len(m.moves) == 0
// We have made a move, so we no longer have a selected piece or
// legal moves for any selected pieces.
g, cmd := m.Deselect()
return g, tea.Batch(m.Notify(from, to, m.board.Wtomove), cmd)
cmds = append(cmds, cmd, m.Notify(from, to, m.board.Wtomove, check, checkmate))
return g, tea.Batch(cmds...)
}
}

View File

@@ -1,8 +1,13 @@
package pieces
// Display maps pieces from their FEN representations to their ASCII
import "strings"
// Piece represents a chess piece.
type Piece string
// display maps pieces from their FEN representations to their ASCII
// representations for a more human readable experience.
var Display = map[string]string{
var display = map[Piece]string{
"": " ",
"B": "♝",
"K": "♚",
@@ -17,3 +22,69 @@ var Display = map[string]string{
"q": "♕",
"r": "♖",
}
// IsWhite returns true if the piece is white.
func (p Piece) IsWhite() bool {
s := p.String()
return strings.ToUpper(s) == s
}
// IsBlack returns true if the piece is black.
func (p Piece) IsBlack() bool {
s := p.String()
return strings.ToLower(s) == s
}
// Display returns the ASCII representation of the piece.
func (p Piece) Display() string {
return display[p]
}
// String implements the stringer interface.
func (p Piece) String() string {
return string(p)
}
// IsKing returns true if the piece is a king.
func (p Piece) IsKing() bool {
return p == "K" || p == "k"
}
// IsPawn returns true if the piece is a pawn.
func (p Piece) IsPawn() bool {
return p == "P" || p == "p"
}
// IsRook returns true if the piece is a rook.
func (p Piece) IsRook() bool {
return p == "R" || p == "r"
}
// IsBishop returns true if the piece is a bishop.
func (p Piece) IsBishop() bool {
return p == "B" || p == "b"
}
// IsKnight returns true if the piece is a knight.
func (p Piece) IsKnight() bool {
return p == "N" || p == "n"
}
// IsQueen returns true if the piece is a queen.
func (p Piece) IsQueen() bool {
return p == "Q" || p == "q"
}
// IsEmpty returns true if the piece is empty.
func (p Piece) IsEmpty() bool {
return p == ""
}
// ToPieces converts a slice of FEN string to a slice of pieces.
func ToPieces(r [8]string) [8]Piece {
var p [8]Piece
for i, s := range r {
p[i] = Piece(s)
}
return p
}