Skip to content

Commit

Permalink
chess: improve move encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
e0ff committed Nov 28, 2023
1 parent f27e2e2 commit 147383d
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 80 deletions.
12 changes: 6 additions & 6 deletions internal/chess/attackers.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ func generatePawnAttacks(position Position, color Color) []Move {
square := Square(pawnBB.PopLsb())

if square.File() != 1 {
move := NewMove(square, square+Square(direction)+Square(west), NormalMove, NoMoveFlag)
move := NewMove(square, square+Square(direction)+Square(west), CaptureMove)
attacks = append(attacks, move)
}

if square.File() != 8 {
move := NewMove(square, square+Square(direction)+Square(east), NormalMove, NoMoveFlag)
move := NewMove(square, square+Square(direction)+Square(east), CaptureMove)
attacks = append(attacks, move)
}
}
Expand All @@ -33,7 +33,7 @@ func generateKnightAttacks(position Position, color Color) []Move {

for moveBB > 0 {
toSquare := Square(moveBB.PopLsb())
move := NewMove(square, toSquare, NormalMove, NoMoveFlag)
move := NewMove(square, toSquare, CaptureMove)
attacks = append(attacks, move)
}
}
Expand All @@ -50,7 +50,7 @@ func generateBishopAttacks(pieceBB BitBoard, occupied BitBoard) []Move {
attackBB := getBishopAttacks(occupied, fromSquare)
for attackBB > 0 {
toSquare := Square(attackBB.PopLsb())
move := NewMove(fromSquare, toSquare, NormalMove, NoMoveFlag)
move := NewMove(fromSquare, toSquare, CaptureMove)
attacks = append(attacks, move)
}
}
Expand All @@ -67,7 +67,7 @@ func generateRookAttacks(pieceBB BitBoard, occupied BitBoard) []Move {
attackBB := getRookAttacks(occupied, fromSquare)
for attackBB > 0 {
toSquare := Square(attackBB.PopLsb())
move := NewMove(fromSquare, toSquare, NormalMove, NoMoveFlag)
move := NewMove(fromSquare, toSquare, CaptureMove)
attacks = append(attacks, move)
}
}
Expand Down Expand Up @@ -98,7 +98,7 @@ func generateKingAttacks(position Position, color Color) []Move {
moveBB := kingMoves[fromSquare]
for moveBB > 0 {
toSquare := Square(moveBB.PopLsb())
move := NewMove(fromSquare, toSquare, NormalMove, NoMoveFlag)
move := NewMove(fromSquare, toSquare, CaptureMove)
attacks = append(attacks, move)
}
}
Expand Down
35 changes: 19 additions & 16 deletions internal/chess/move.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ import (
type MoveType uint8

const (
NormalMove MoveType = iota
CastleMove
QuietMove MoveType = iota
CaptureMove
EnPassantMove
CastleMove
Null
)

func (t MoveType) String() string {
switch t {
case NormalMove:
return "Normal"
case QuietMove:
return "Quiet"
case CaptureMove:
return "Capture"
case CastleMove:
return "Castle"
case EnPassantMove:
Expand All @@ -29,14 +32,11 @@ func (t MoveType) String() string {
return "<unknown>"
}

type MoveFlag uint16
type MoveFlag uint8

const (
NoMoveFlag MoveFlag = 0x0000
QuietMoveFlag MoveFlag = 0x0001
CaputureMoveFlag MoveFlag = 0x0010
PawnPushMoveFlag MoveFlag = 0x0100
PromotionMoveFlag MoveFlag = 0x1000
NoMoveFlag MoveFlag = 0b0000
PawnPushMoveFlag MoveFlag = 0b0001
)

type Move struct {
Expand All @@ -49,15 +49,15 @@ type Move struct {
promotionPiece Piece
}

var NullMove = NewMove(A1, A1, Null, NoMoveFlag)
var NullMove = NewMove(A1, A1, Null)

// NewMove creates a new move with the given from and to.
func NewMove(from, to Square, moveType MoveType, flags MoveFlag) Move {
func NewMove(from, to Square, moveType MoveType) Move {
return Move{
from: from,
to: to,
moveType: moveType,
flags: flags,
flags: NoMoveFlag,
promotionPiece: EmptyPiece,
}
}
Expand All @@ -74,10 +74,13 @@ func (m Move) To() Square {

// WithPromotion sets that the move will result with the moving piece being promoted to the given piece.
func (m *Move) WithPromotion(piece Piece) {
m.flags |= PromotionMoveFlag
m.promotionPiece = piece
}

func (m *Move) WithFlags(flags MoveFlag) {
m.flags |= flags
}

// Type returns the type of the move.
func (m Move) Type() MoveType {
return m.moveType
Expand Down Expand Up @@ -111,7 +114,7 @@ func (m Move) IsPromotion() bool {

// IsCapture returns whether the move results in a capture.
func (m Move) IsCapture() bool {
return m.HasFlag(CaputureMoveFlag)
return m.Type() == CaptureMove || m.Type() == EnPassantMove
}

// HasFlag checks if the move has that flag set.
Expand All @@ -124,7 +127,7 @@ func (m Move) HasFlag(flag MoveFlag) bool {
// Moves such as pawn moves and captures can't be reversed once done meaning
// the position before the was made is no longer possible.
func (m Move) IsIrreversible() bool {
return m.HasFlag(PawnPushMoveFlag) || m.HasFlag(CaputureMoveFlag) || m.HasFlag(PromotionMoveFlag)
return m.HasFlag(PawnPushMoveFlag) || m.IsCapture() || m.IsPromotion()
}

func (m Move) String() string {
Expand Down
41 changes: 23 additions & 18 deletions internal/chess/movegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,24 @@ func generatePawnMoves(position Position, genType MoveGenerationType) []Move {

if toSquare.Rank() == pawnPromotionRank(position.Turn()) {
for _, pieceType := range promotablePieces {
move := NewMove(square, toSquare, NormalMove, QuietMoveFlag|PawnPushMoveFlag)
move := NewMove(square, toSquare, QuietMove)
move.WithFlags(PawnPushMoveFlag)
move.WithPromotion(NewPiece(pieceType, position.turn))

moves = append(moves, move)
}
} else {
moves = append(moves, NewMove(square, toSquare, NormalMove, QuietMoveFlag|PawnPushMoveFlag))
move := NewMove(square, toSquare, QuietMove)
move.WithFlags(PawnPushMoveFlag)
moves = append(moves, move)
}

if square.Rank() == pawnStartingRank(position.turn) {
toSquare := square + (dir * 2)
if !position.IsSquareOccupied(toSquare) {
moves = append(moves, NewMove(square, toSquare, NormalMove, QuietMoveFlag|PawnPushMoveFlag))
move := NewMove(square, toSquare, QuietMove)
move.WithFlags(PawnPushMoveFlag)
moves = append(moves, move)
}
}
}
Expand All @@ -54,12 +59,12 @@ func generatePawnMoves(position Position, genType MoveGenerationType) []Move {
if capturePiece != EmptyPiece && capturePiece.Color() != position.turn {
if captureSquare.Rank() == pawnPromotionRank(position.Turn()) {
for _, pieceType := range promotablePieces {
move := NewMove(square, captureSquare, NormalMove, CaputureMoveFlag)
move := NewMove(square, captureSquare, CaptureMove)
move.WithPromotion(NewPiece(pieceType, position.Turn()))
moves = append(moves, move)
}
} else {
move := NewMove(square, captureSquare, NormalMove, CaputureMoveFlag)
move := NewMove(square, captureSquare, CaptureMove)
moves = append(moves, move)
}
}
Expand All @@ -71,7 +76,7 @@ func generatePawnMoves(position Position, genType MoveGenerationType) []Move {

capturePiece, _ := position.GetPieceAt(captureSquare)
if capturePiece.Type() == Pawn && capturePiece.Color() == position.Turn().OpposingSide() {
move := NewMove(square, position.EnPassant(), EnPassantMove, CaputureMoveFlag)
move := NewMove(square, position.EnPassant(), EnPassantMove)
moves = append(moves, move)
}
}
Expand All @@ -97,15 +102,15 @@ func generateKnightMoves(position Position, genType MoveGenerationType) []Move {
moveBB := attackBB & ^occupied
for moveBB > 0 {
toSquare := Square(moveBB.PopLsb())
move := NewMove(fromSquare, toSquare, NormalMove, QuietMoveFlag)
move := NewMove(fromSquare, toSquare, QuietMove)
moves = append(moves, move)
}
}

capturesBB := attackBB & opponent
for capturesBB > 0 {
toSquare := Square(capturesBB.PopLsb())
move := NewMove(fromSquare, toSquare, NormalMove, CaputureMoveFlag)
move := NewMove(fromSquare, toSquare, CaptureMove)
moves = append(moves, move)
}
}
Expand All @@ -128,15 +133,15 @@ func generateBishopMoves(position Position, pieceBB BitBoard, genType MoveGenera
moveBB := attackBB & ^occupied
for moveBB > 0 {
toSquare := Square(moveBB.PopLsb())
move := NewMove(fromSquare, toSquare, NormalMove, QuietMoveFlag)
move := NewMove(fromSquare, toSquare, QuietMove)
moves = append(moves, move)
}
}

capturesBB := attackBB & opponent
for capturesBB > 0 {
toSquare := Square(capturesBB.PopLsb())
move := NewMove(fromSquare, toSquare, NormalMove, CaputureMoveFlag)
move := NewMove(fromSquare, toSquare, CaptureMove)
moves = append(moves, move)
}
}
Expand All @@ -159,15 +164,15 @@ func generateRookMoves(position Position, pieceBB BitBoard, genType MoveGenerati
moveBB := attacks & ^occupied
for moveBB > 0 {
toSquare := Square(moveBB.PopLsb())
move := NewMove(fromSquare, toSquare, NormalMove, QuietMoveFlag)
move := NewMove(fromSquare, toSquare, QuietMove)
moves = append(moves, move)
}
}

capturesBB := attacks & opponent
for capturesBB > 0 {
toSquare := Square(capturesBB.PopLsb())
move := NewMove(fromSquare, toSquare, NormalMove, CaputureMoveFlag)
move := NewMove(fromSquare, toSquare, CaptureMove)
moves = append(moves, move)
}
}
Expand Down Expand Up @@ -201,37 +206,37 @@ func generateKingMoves(position Position, genType MoveGenerationType, includeCas
moveBB := attacks & ^occupied
for moveBB > 0 {
toSquare := Square(moveBB.PopLsb())
move := NewMove(kingSquare, toSquare, NormalMove, QuietMoveFlag)
move := NewMove(kingSquare, toSquare, QuietMove)
moves = append(moves, move)
}
}

capturesBB := attacks & opponent
for capturesBB > 0 {
toSquare := Square(capturesBB.PopLsb())
move := NewMove(kingSquare, toSquare, NormalMove, CaputureMoveFlag)
move := NewMove(kingSquare, toSquare, CaptureMove)
moves = append(moves, move)
}

if includeCastling {
if position.turn == White {
if position.HasCastlingRights(WhiteCastleKingside) && position.squaresEmpty([]Square{F1, G1}) {
move := NewMove(kingSquare, kingSquare+Square(east*2), CastleMove, QuietMoveFlag)
move := NewMove(kingSquare, kingSquare+Square(east*2), CastleMove)
moves = append(moves, move)
}

if position.HasCastlingRights(WhiteCastleQueenside) && position.squaresEmpty([]Square{D1, C1, B1}) {
move := NewMove(kingSquare, kingSquare+Square(west*2), CastleMove, QuietMoveFlag)
move := NewMove(kingSquare, kingSquare+Square(west*2), CastleMove)
moves = append(moves, move)
}
} else {
if position.HasCastlingRights(BlackCastleKingside) && position.squaresEmpty([]Square{F8, G8}) {
move := NewMove(kingSquare, kingSquare+Square(east*2), CastleMove, QuietMoveFlag)
move := NewMove(kingSquare, kingSquare+Square(east*2), CastleMove)
moves = append(moves, move)
}

if position.HasCastlingRights(BlackCastleQueenside) && position.squaresEmpty([]Square{D8, C8, B8}) {
move := NewMove(kingSquare, kingSquare+Square(west*2), CastleMove, QuietMoveFlag)
move := NewMove(kingSquare, kingSquare+Square(west*2), CastleMove)
moves = append(moves, move)
}
}
Expand Down
Loading

0 comments on commit 147383d

Please sign in to comment.