Skip to content
41 changes: 15 additions & 26 deletions cmd/silverfish/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,11 @@ func main() {
messageChannel := make(chan engine.UciClientMessage, 5)
// Used for reporting if an action is done.
actionAlertChannel := make(chan bool)
active := false

position := engine.StartingPosition()

go HandleMessages(messageChannel)

mainloop:
for {
message := engine.UciClientMessage{}
select {
Expand All @@ -99,30 +97,21 @@ mainloop:
continue
}

if active {
select {
case <-actionAlertChannel:
active = false
default:
// Do nothing :ye:
}
} else {
switch message.MessageType {
case engine.UciUciClientMessage:
engine.UciSetEngineName("Silverfish 0.0.0a")
engine.UciSetAuthor("李能和赵梁越")
engine.UciSetProtocol(2)

engine.UciOk()
case engine.UciIsReadyClientMessage:
engine.UciReadyOk()
case engine.UciPositionClientMessage:
position = *message.Position
case engine.UciQuitClientMessage:
break mainloop
case engine.UciGoClientMessage:
go executeGoCommand(actionAlertChannel, &position, message.GoMessage)
}
switch message.MessageType {
case engine.UciUciClientMessage:
engine.UciSetEngineName("Silverfish 0.0.0a")
engine.UciSetAuthor("李能和赵梁越")
engine.UciSetProtocol(2)

engine.UciOk()
case engine.UciIsReadyClientMessage:
engine.UciReadyOk()
case engine.UciPositionClientMessage:
position = *message.Position
case engine.UciQuitClientMessage:
return
case engine.UciGoClientMessage:
go executeGoCommand(actionAlertChannel, &position, message.GoMessage)
}
}
}
56 changes: 54 additions & 2 deletions engine/evaluation.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package engine

import "math/bits"
import (
"math"
"math/bits"
)

const Infinity int32 = 1000000

Expand Down Expand Up @@ -152,6 +155,52 @@ func (pos *Position) EndgameMaterial(color uint8) int32 {
return ans
}

func (pos *Position) KingSafety(color uint8) int32 {
safetyScore := int32(1000)

// Obviously, if the King is in check, it is not going to be safe.
checkers := pos.Checkers(color)
checkerCount := int32(bits.OnesCount64(uint64(checkers)))
safetyScore -= checkerCount * 100

kingSquare := pos.GetKingSquare(color)
kingRank := RankOf(kingSquare)
kingFile := FileOf(kingSquare)

// Enemy pieces being close to the King might be a bit of an issue.
// TODO: Have a more optimal way of doing this later. Probably by using the bitboards and stuff
for square := range NoSquare {
colorOfPiece, piece := pos.GetSquare(square)

pieceRank := RankOf(square)
pieceFile := FileOf(square)

rankDiff := Abs(int(pieceRank - kingRank))
fileDiff := Abs(int(pieceFile - kingFile))

distance := math.Sqrt(float64(rankDiff*rankDiff + fileDiff*fileDiff))
distanceWeight := 10.0 - distance // the closer it is the higher the weight

if colorOfPiece != color {
switch piece {
case Queen:
safetyScore -= int32(20 * distanceWeight)
case Rook:
safetyScore -= int32(10 * distanceWeight)
case Bishop:
safetyScore -= int32(5 * distanceWeight)
case Knight:
safetyScore -= int32(5 * distanceWeight)
case Pawn:
// Not as small as a pawn storm could be dangerous,
safetyScore -= int32(3 * distanceWeight)
}
}
}

return safetyScore
}

func Evaluate(pos *Position) int32 {
us := pos.Turn
them := pos.Turn ^ 1
Expand All @@ -161,9 +210,12 @@ func Evaluate(pos *Position) int32 {
ourEGMaterial := pos.EndgameMaterial(us)
theirEGMaterial := pos.EndgameMaterial(them)

ourKingSafety := pos.KingSafety(us)
theirKingSafety := pos.KingSafety(them)

isEndgame := (ourEGMaterial + theirEGMaterial) <= 1400

eval := ourMaterial - theirMaterial
eval := ourMaterial + ourKingSafety - theirMaterial - theirKingSafety

for piece := Pawn; piece <= King; piece++ {
bb := pos.Pieces[us][piece]
Expand Down
7 changes: 5 additions & 2 deletions engine/position.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ func (pos *Position) PutPiecesBB(pieces [2][6]Bitboard) {
}
}

func (pos *Position) GetKingSquare(color uint8) Square {
return Lsb(pos.Pieces[color][King])
}

func (pos *Position) RemovePiece(sq Square) {
piece := pos.Board[sq]
color := ColorOf(piece)
Expand All @@ -109,8 +113,7 @@ func (pos *Position) Equals(otherPos Position) bool {
pos.EnPassantSquare == otherPos.EnPassantSquare
}

// (color, piece)
func (pos *Position) GetSquare(sq Square) (uint8, uint8) {
func (pos *Position) GetSquare(sq Square) (color uint8, piece uint8) {
p := pos.Board[sq]
if p == NoPiece {
return NoColor, NoPiece
Expand Down
6 changes: 4 additions & 2 deletions engine/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@ const MaxQuiescenceDepth = 8
// return number in milliseconds
func TimeLimit(pos *Position, command *UciGoMessage) time.Duration {
var ourTime, ourInc int32 //, theirTime, theirInc int32
if pos.Turn == White {
switch pos.Turn {
case White:
ourTime = command.WTime
ourInc = command.WInc
// theirTime = command.BTime
// theirInc = command.BInc
} else if pos.Turn == Black {
case Black:
ourTime = command.BTime
ourInc = command.BInc
// theirTime = command.WTime
// theirInc = command.WInc
}

estimatedMovesLeft := max(10, 100-pos.FullMoves())
// multiplying time.Miillisecond twice?
return min(MaxMovetime, time.Duration(ourTime/int32(estimatedMovesLeft)+ourInc/4))
Expand Down
Loading