You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
14 KiB
303 lines
14 KiB
4 years ago
|
package chess
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
"testing"
|
||
|
)
|
||
|
|
||
|
type moveTest struct {
|
||
|
pos *Position
|
||
|
m *Move
|
||
|
postPos *Position
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
validMoves = []moveTest{
|
||
|
// pawn moves
|
||
|
{m: &Move{s1: E2, s2: E4}, pos: unsafeFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")},
|
||
|
{m: &Move{s1: A2, s2: A3}, pos: unsafeFEN("8/8/8/8/8/8/P7/8 w - - 0 1")},
|
||
|
{m: &Move{s1: A7, s2: A6}, pos: unsafeFEN("8/p7/8/8/8/8/8/8 b - - 0 1")},
|
||
|
{m: &Move{s1: A7, s2: A5}, pos: unsafeFEN("8/p7/8/8/8/8/8/8 b - - 0 1")},
|
||
|
{m: &Move{s1: C4, s2: B5}, pos: unsafeFEN("8/8/8/1p1p4/2P5/8/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: C4, s2: D5}, pos: unsafeFEN("8/8/8/1p1p4/2P5/8/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: C4, s2: C5}, pos: unsafeFEN("8/8/8/1p1p4/2P5/8/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: C5, s2: B4}, pos: unsafeFEN("8/8/8/2p5/1P1P4/8/8/8 b - - 0 1")},
|
||
|
{m: &Move{s1: C5, s2: D4}, pos: unsafeFEN("8/8/8/2p5/1P1P4/8/8/8 b - - 0 1")},
|
||
|
{m: &Move{s1: C5, s2: C4}, pos: unsafeFEN("8/8/8/2p5/1P1P4/8/8/8 b - - 0 1")},
|
||
|
{m: &Move{s1: A4, s2: B3}, pos: unsafeFEN("2r3k1/1q1nbppp/r3p3/3pP3/pPpP4/P1Q2N2/2RN1PPP/2R4K b - b3 0 23")},
|
||
|
{m: &Move{s1: A2, s2: A1, promo: Queen}, pos: unsafeFEN("8/8/8/8/8/8/p7/8 b - - 0 1")},
|
||
|
{m: &Move{s1: E7, s2: E6}, pos: unsafeFEN("r2qkbnr/pppnpppp/8/3p4/6b1/1P3NP1/PBPPPP1P/RN1QKB1R b KQkq - 2 4")},
|
||
|
// knight moves
|
||
|
{m: &Move{s1: E4, s2: F6}, pos: unsafeFEN("8/8/8/3pp3/4N3/8/5B2/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: D6}, pos: unsafeFEN("8/8/8/3pp3/4N3/8/5B2/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: G5}, pos: unsafeFEN("8/8/8/3pp3/4N3/8/5B2/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: G3}, pos: unsafeFEN("8/8/8/3pp3/4N3/8/5B2/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: D2}, pos: unsafeFEN("8/8/8/3pp3/4N3/8/5B2/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: C3}, pos: unsafeFEN("8/8/8/3pp3/4N3/8/5B2/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: C5}, pos: unsafeFEN("8/8/8/3pp3/4N3/8/5B2/8 w - - 0 1")},
|
||
|
{m: &Move{s1: B8, s2: D7}, pos: unsafeFEN("rn1qkb1r/pp3ppp/2p1pn2/3p4/2PP4/2NQPN2/PP3PPP/R1B1K2R b KQkq - 0 7")},
|
||
|
{m: &Move{s1: F6, s2: E4}, pos: unsafeFEN("r1b1k2r/ppp2ppp/2p2n2/4N3/4P3/2P5/PPP2PPP/R1BK3R b kq - 0 8")},
|
||
|
// bishop moves
|
||
|
{m: &Move{s1: E4, s2: H7}, pos: unsafeFEN("8/8/8/3pp3/4B3/5N2/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: D5}, pos: unsafeFEN("8/8/8/3pp3/4B3/5N2/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: B1}, pos: unsafeFEN("8/8/8/3pp3/4B3/5N2/8/8 w - - 0 1")},
|
||
|
// rook moves
|
||
|
{m: &Move{s1: B2, s2: B4}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1R6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: B7}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1R6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: A2}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1R6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: H2}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1R6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: E1, s2: E8}, pos: unsafeFEN("r3r1k1/p4p1p/3p4/1p4p1/2pP4/2P2P2/PP3P1P/R3RK2 w - g6 0 22")},
|
||
|
// queen moves
|
||
|
{m: &Move{s1: B2, s2: E5}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1Q6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: A1}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1Q6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: A2}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1Q6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: H2}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1Q6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: D8, s2: D1}, pos: unsafeFEN("r1bqk2r/ppp2ppp/2p2n2/4N3/4P3/2P5/PPP2PPP/R1BQK2R b KQkq - 0 7")},
|
||
|
// king moves
|
||
|
{m: &Move{s1: E4, s2: E5}, pos: unsafeFEN("5r2/8/8/8/4K3/8/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: E3}, pos: unsafeFEN("5r2/8/8/8/4K3/8/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: D3}, pos: unsafeFEN("5r2/8/8/8/4K3/8/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: D4}, pos: unsafeFEN("5r2/8/8/8/4K3/8/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: D5}, pos: unsafeFEN("5r2/8/8/8/4K3/8/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: E5}, pos: unsafeFEN("5r2/8/8/8/4K3/8/8/8 w - - 0 1")},
|
||
|
// castleing
|
||
|
{m: &Move{s1: E1, s2: G1}, pos: unsafeFEN("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1")},
|
||
|
{m: &Move{s1: E1, s2: C1}, pos: unsafeFEN("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1")},
|
||
|
{m: &Move{s1: E8, s2: G8}, pos: unsafeFEN("r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1")},
|
||
|
{m: &Move{s1: E8, s2: C8}, pos: unsafeFEN("r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1")},
|
||
|
// king moving in front of enemy pawn http://en.lichess.org/4HXJOtpN#75
|
||
|
{m: &Move{s1: F8, s2: G7}, pos: unsafeFEN("3rrk2/8/2p3P1/1p2nP1p/pP2p3/P1B1NbPB/2P2K2/5R2 b - - 1 38")},
|
||
|
}
|
||
|
|
||
|
invalidMoves = []moveTest{
|
||
|
// out of turn moves
|
||
|
{m: &Move{s1: E7, s2: E5}, pos: unsafeFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")},
|
||
|
{m: &Move{s1: E2, s2: E4}, pos: unsafeFEN("rnbqkbnr/1ppppppp/p7/8/8/8/PPPPPPPP/RNBQKBNR b KQkq - 0 1")},
|
||
|
// pawn moves
|
||
|
{m: &Move{s1: E2, s2: D3}, pos: unsafeFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")},
|
||
|
{m: &Move{s1: E2, s2: F3}, pos: unsafeFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")},
|
||
|
{m: &Move{s1: E2, s2: E5}, pos: unsafeFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")},
|
||
|
{m: &Move{s1: A2, s2: A1}, pos: unsafeFEN("8/8/8/8/8/8/p7/8 b - - 0 1")},
|
||
|
{m: &Move{s1: E6, s2: E5}, pos: unsafeFEN(`2b1r3/2k2p1B/p2np3/4B3/8/5N2/PP1K1PPP/3R4 b - - 2 1`)},
|
||
|
{m: &Move{s1: H7, s2: H5}, pos: unsafeFEN(`2bqkbnr/rpppp2p/2n2p2/p5pB/5P2/4P3/PPPP2PP/RNBQK1NR b KQk - 4 6`)},
|
||
|
// knight moves
|
||
|
{m: &Move{s1: E4, s2: F2}, pos: unsafeFEN("8/8/8/3pp3/4N3/8/5B2/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: F3}, pos: unsafeFEN("8/8/8/3pp3/4N3/8/5B2/8 w - - 0 1")},
|
||
|
// bishop moves
|
||
|
{m: &Move{s1: E4, s2: C6}, pos: unsafeFEN("8/8/8/3pp3/4B3/5N2/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: E5}, pos: unsafeFEN("8/8/8/3pp3/4B3/5N2/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: E4}, pos: unsafeFEN("8/8/8/3pp3/4B3/5N2/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: F3}, pos: unsafeFEN("8/8/8/3pp3/4B3/5N2/8/8 w - - 0 1")},
|
||
|
// rook moves
|
||
|
{m: &Move{s1: B2, s2: B1}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1R6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: C3}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1R6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: B8}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1R6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: G7}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1R6/1B6 w - - 0 1")},
|
||
|
// queen moves
|
||
|
{m: &Move{s1: B2, s2: B1}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1Q6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: C4}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1Q6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: B8}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1Q6/1B6 w - - 0 1")},
|
||
|
{m: &Move{s1: B2, s2: G7}, pos: unsafeFEN("8/1p5b/4N3/4p3/8/8/1Q6/1B6 w - - 0 1")},
|
||
|
// king moves
|
||
|
{m: &Move{s1: E4, s2: F3}, pos: unsafeFEN("5r2/8/8/8/4K3/8/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: F4}, pos: unsafeFEN("5r2/8/8/8/4K3/8/8/8 w - - 0 1")},
|
||
|
{m: &Move{s1: E4, s2: F5}, pos: unsafeFEN("5r2/8/8/8/4K3/8/8/8 w - - 0 1")},
|
||
|
// castleing
|
||
|
{m: &Move{s1: E1, s2: B1}, pos: unsafeFEN("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1")},
|
||
|
{m: &Move{s1: E8, s2: B8}, pos: unsafeFEN("r3k2r/8/8/8/8/8/8/R3K2R b KQkq - 0 1")},
|
||
|
{m: &Move{s1: E1, s2: C1}, pos: unsafeFEN("r3k2r/8/8/8/8/8/8/R2QK2R w KQkq - 0 1")},
|
||
|
{m: &Move{s1: E1, s2: C1}, pos: unsafeFEN("2r1k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1")},
|
||
|
{m: &Move{s1: E1, s2: C1}, pos: unsafeFEN("3rk2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1")},
|
||
|
{m: &Move{s1: E1, s2: G1}, pos: unsafeFEN("r3k2r/8/8/8/8/8/8/R3K2R w Qkq - 0 1")},
|
||
|
{m: &Move{s1: E1, s2: C1}, pos: unsafeFEN("r3k2r/8/8/8/8/8/8/R3K2R w Kkq - 0 1")},
|
||
|
// invalid promotion for non-pawn move
|
||
|
{m: &Move{s1: B8, s2: D7, promo: Pawn}, pos: unsafeFEN("rn1qkb1r/pp3ppp/2p1pn2/3p4/2PP4/2NQPN2/PP3PPP/R1B1K2R b KQkq - 0 7")},
|
||
|
// en passant on doubled pawn file http://en.lichess.org/TnRtrHxf#24
|
||
|
{m: &Move{s1: E3, s2: F6}, pos: unsafeFEN("r1b2rk1/pp2b1pp/1qn1p3/3pPp2/1P1P4/P2BPN2/6PP/RN1Q1RK1 w - f6 0 13")},
|
||
|
// can't move piece out of pin (even if checking enemy king) http://en.lichess.org/JCRBhXH7#62
|
||
|
{m: &Move{s1: E1, s2: E7}, pos: unsafeFEN("4R3/1r1k2pp/p1p5/1pP5/8/8/1PP3PP/2K1Rr2 w - - 5 32")},
|
||
|
// invalid one up pawn capture
|
||
|
{m: &Move{s1: E6, s2: E5}, pos: unsafeFEN(`2b1r3/2k2p1B/p2np3/4B3/8/5N2/PP1K1PPP/3R4 b - - 2 1`)},
|
||
|
// invalid two up pawn capture
|
||
|
{m: &Move{s1: H7, s2: H5}, pos: unsafeFEN(`2bqkbnr/rpppp2p/2n2p2/p5pB/5P2/4P3/PPPP2PP/RNBQK1NR b KQk - 4 6`)},
|
||
|
// invalid pawn move d5e4
|
||
|
{m: &Move{s1: D5, s2: E4}, pos: unsafeFEN(`rnbqkbnr/pp2pppp/8/2pp4/3P4/4PN2/PPP2PPP/RNBQKB1R b KQkq - 0 3`)},
|
||
|
}
|
||
|
|
||
|
positionUpdates = []moveTest{
|
||
|
{
|
||
|
m: &Move{s1: E2, s2: E4},
|
||
|
pos: unsafeFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"),
|
||
|
postPos: unsafeFEN("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"),
|
||
|
},
|
||
|
{
|
||
|
m: &Move{s1: E1, s2: G1, tags: KingSideCastle},
|
||
|
pos: unsafeFEN("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1"),
|
||
|
postPos: unsafeFEN("r3k2r/8/8/8/8/8/8/R4RK1 b kq - 0 1"),
|
||
|
},
|
||
|
{
|
||
|
m: &Move{s1: A4, s2: B3, tags: EnPassant},
|
||
|
pos: unsafeFEN("2r3k1/1q1nbppp/r3p3/3pP3/pPpP4/P1Q2N2/2RN1PPP/2R4K b - b3 0 23"),
|
||
|
postPos: unsafeFEN("2r3k1/1q1nbppp/r3p3/3pP3/11pP4/PpQ2N2/2RN1PPP/2R4K w - - 0 24"),
|
||
|
},
|
||
|
{
|
||
|
m: &Move{s1: E1, s2: G1, tags: KingSideCastle},
|
||
|
pos: unsafeFEN("r2qk2r/pp1n1ppp/2pbpn2/3p4/2PP4/1PNQPN2/P4PPP/R1B1K2R w KQkq - 1 9"),
|
||
|
postPos: unsafeFEN("r2qk2r/pp1n1ppp/2pbpn2/3p4/2PP4/1PNQPN2/P4PPP/R1B2RK1 b kq - 0 9"),
|
||
|
},
|
||
|
}
|
||
|
)
|
||
|
|
||
|
func unsafeFEN(s string) *Position {
|
||
|
pos, err := decodeFEN(s)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
return pos
|
||
|
}
|
||
|
|
||
|
func TestValidMoves(t *testing.T) {
|
||
|
for _, mt := range validMoves {
|
||
|
if !moveIsValid(mt.pos, mt.m, false) {
|
||
|
log.Println(mt.pos.String())
|
||
|
log.Println(mt.pos.board.Draw())
|
||
|
log.Println(mt.pos.ValidMoves())
|
||
|
log.Println("In Check:", squaresAreAttacked(mt.pos, mt.pos.board.whiteKingSq))
|
||
|
// log.Println("In Check:", mt.pos.inCheck())
|
||
|
mt.pos.turn = mt.pos.turn.Other()
|
||
|
t.Fatalf("expected move %s to be valid", mt.m)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestInvalidMoves(t *testing.T) {
|
||
|
for _, mt := range invalidMoves {
|
||
|
if moveIsValid(mt.pos, mt.m, false) {
|
||
|
log.Println(mt.pos.String())
|
||
|
log.Println(mt.pos.board.Draw())
|
||
|
t.Fatalf("expected move %s to be invalid", mt.m)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestPositionUpdates(t *testing.T) {
|
||
|
for _, mt := range positionUpdates {
|
||
|
if !moveIsValid(mt.pos, mt.m, true) {
|
||
|
log.Println(mt.pos.String())
|
||
|
log.Println(mt.pos.board.Draw())
|
||
|
log.Println(mt.pos.ValidMoves())
|
||
|
t.Fatalf("expected move %s %v to be valid", mt.m, mt.m.tags)
|
||
|
}
|
||
|
|
||
|
postPos := mt.pos.Update(mt.m)
|
||
|
if postPos.String() != mt.postPos.String() {
|
||
|
t.Fatalf("starting from board \n%s%s\n after move %s\n expected board to be %s\n%s\n but was %s\n%s\n",
|
||
|
mt.pos.String(),
|
||
|
mt.pos.board.Draw(),
|
||
|
mt.m.String(),
|
||
|
mt.postPos.String(),
|
||
|
mt.postPos.board.Draw(),
|
||
|
postPos.String(),
|
||
|
postPos.board.Draw(),
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type perfTest struct {
|
||
|
pos *Position
|
||
|
nodesPerDepth []int
|
||
|
}
|
||
|
|
||
|
/* https://www.chessprogramming.org/Perft_Results */
|
||
|
var perfResults = []perfTest{
|
||
|
{pos: unsafeFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"), nodesPerDepth: []int{
|
||
|
20, 400, 8902, 197281,
|
||
|
// 4865609, 119060324, 3195901860, 84998978956, 2439530234167, 69352859712417
|
||
|
}},
|
||
|
{pos: unsafeFEN("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1"), nodesPerDepth: []int{
|
||
|
48, 2039, 97862,
|
||
|
// 4085603, 193690690
|
||
|
}},
|
||
|
{pos: unsafeFEN("8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1"), nodesPerDepth: []int{
|
||
|
14, 191, 2812, 43238, 674624,
|
||
|
// 11030083, 178633661
|
||
|
}},
|
||
|
{pos: unsafeFEN("r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1"), nodesPerDepth: []int{
|
||
|
6, 264, 9467, 422333,
|
||
|
// 15833292, 706045033
|
||
|
}},
|
||
|
{pos: unsafeFEN("r2q1rk1/pP1p2pp/Q4n2/bbp1p3/Np6/1B3NBn/pPPP1PPP/R3K2R b KQ - 0 1"), nodesPerDepth: []int{
|
||
|
6, 264, 9467, 422333,
|
||
|
// 15833292, 706045033
|
||
|
}},
|
||
|
{pos: unsafeFEN("rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8"), nodesPerDepth: []int{
|
||
|
44, 1486, 62379,
|
||
|
// 2103487, 89941194
|
||
|
}},
|
||
|
{pos: unsafeFEN("r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10"), nodesPerDepth: []int{
|
||
|
46, 2079, 89890,
|
||
|
// 3894594, 164075551, 6923051137, 287188994746, 11923589843526, 490154852788714
|
||
|
}},
|
||
|
}
|
||
|
|
||
|
func TestPerfResults(t *testing.T) {
|
||
|
for _, perf := range perfResults {
|
||
|
countMoves(t, perf.pos, []*Position{perf.pos}, perf.nodesPerDepth, len(perf.nodesPerDepth))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func countMoves(t *testing.T, originalPosition *Position, positions []*Position, nodesPerDepth []int, maxDepth int) {
|
||
|
if len(nodesPerDepth) == 0 {
|
||
|
return
|
||
|
}
|
||
|
depth := maxDepth - len(nodesPerDepth) + 1
|
||
|
expNodes := nodesPerDepth[0]
|
||
|
newPositions := make([]*Position, 0)
|
||
|
for _, pos := range positions {
|
||
|
for _, move := range pos.ValidMoves() {
|
||
|
newPos := pos.Update(move)
|
||
|
newPositions = append(newPositions, newPos)
|
||
|
}
|
||
|
}
|
||
|
gotNodes := len(newPositions)
|
||
|
if expNodes != gotNodes {
|
||
|
t.Errorf("Depth: %d Expected: %d Got: %d", depth, expNodes, gotNodes)
|
||
|
t.Log("##############################")
|
||
|
t.Log("# Original position info")
|
||
|
t.Log("###")
|
||
|
t.Log(originalPosition.String())
|
||
|
t.Log(originalPosition.board.Draw())
|
||
|
t.Log("##############################")
|
||
|
t.Log("# Details in JSONL (http://jsonlines.org)")
|
||
|
t.Log("###")
|
||
|
for _, pos := range positions {
|
||
|
t.Logf(`{"position": "%s", "moves": %d}`, pos.String(), len(pos.ValidMoves()))
|
||
|
}
|
||
|
}
|
||
|
countMoves(t, originalPosition, newPositions, nodesPerDepth[1:], maxDepth)
|
||
|
}
|
||
|
|
||
|
func BenchmarkValidMoves(b *testing.B) {
|
||
|
pos := unsafeFEN("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
|
||
|
b.ResetTimer()
|
||
|
for n := 0; n < b.N; n++ {
|
||
|
pos.ValidMoves()
|
||
|
pos.validMoves = nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func moveIsValid(pos *Position, m *Move, useTags bool) bool {
|
||
|
for _, move := range pos.ValidMoves() {
|
||
|
if move.s1 == m.s1 && move.s2 == m.s2 && move.promo == m.promo {
|
||
|
if useTags {
|
||
|
if m.tags != move.tags {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|