test(notation): add san and pgn tests
This commit is contained in:
1 parent
a38a065f6a
commit
5f2c484603
2 files changed
+134
No files matched your search
@@ -0,0 +1,61 @@
|
|||||||
|
package gambit
|
||||||
|
|
||||||
|
class PgnTest extends munit.FunSuite:
|
||||||
|
|
||||||
|
private def playUci(startFen: String, ucis: List[String]): List[Int] =
|
||||||
|
val pos = Fen.parse(startFen)
|
||||||
|
val moves = scala.collection.mutable.ListBuffer[Int]()
|
||||||
|
for u <- ucis do
|
||||||
|
val legal = new MoveList()
|
||||||
|
MoveGen.generateLegal(pos, legal)
|
||||||
|
var found = 0
|
||||||
|
var i = 0
|
||||||
|
while i < legal.size do
|
||||||
|
if Move.uci(legal(i)) == u then found = legal(i)
|
||||||
|
i += 1
|
||||||
|
moves += found
|
||||||
|
pos.make(found)
|
||||||
|
moves.toList
|
||||||
|
|
||||||
|
private val ruyLopez =
|
||||||
|
List("e2e4", "e7e5", "g1f3", "b8c6", "f1b5", "a7a6", "b5a4", "g8f6", "e1g1", "f8e7")
|
||||||
|
|
||||||
|
test("write produces numbered SAN movetext with a result") {
|
||||||
|
val moves = playUci(Fen.startPosition, ruyLopez)
|
||||||
|
val pgn = Pgn.write(Fen.startPosition, moves, "*")
|
||||||
|
assert(pgn.contains("1. e4 e5 2. Nf3 Nc6 3. Bb5 a6 4. Ba4 Nf6 5. O-O Be7"), pgn)
|
||||||
|
assert(pgn.contains("""[Result "*"]"""))
|
||||||
|
assert(pgn.trim.endsWith("*"))
|
||||||
|
}
|
||||||
|
|
||||||
|
test("write then read reconstructs the exact move list") {
|
||||||
|
val moves = playUci(Fen.startPosition, ruyLopez)
|
||||||
|
val game = Pgn.read(Pgn.write(Fen.startPosition, moves, "1-0"))
|
||||||
|
assertEquals(game.moves, moves)
|
||||||
|
assertEquals(game.result, "1-0")
|
||||||
|
assertEquals(game.startFen, Fen.startPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("read tolerates comments, NAGs, variations and move numbers") {
|
||||||
|
val text =
|
||||||
|
"""[Event "Test"]
|
||||||
|
|[Result "1-0"]
|
||||||
|
|
|
||||||
|
|1. e4 e5 2. Nf3 {developing} Nc6 3. Bb5 $1 a6 (3... Nf6 4. O-O) 4. Ba4 1-0
|
||||||
|
|""".stripMargin
|
||||||
|
val game = Pgn.read(text)
|
||||||
|
assertEquals(game.result, "1-0")
|
||||||
|
assertEquals(game.moves.map(m => Move.uci(m)), List("e2e4", "e7e5", "g1f3", "b8c6", "f1b5", "a7a6", "b5a4"))
|
||||||
|
assertEquals(game.tags.find(_._1 == "Event").map(_._2), Some("Test"))
|
||||||
|
}
|
||||||
|
|
||||||
|
test("a game set up from a FEN keeps SetUp/FEN tags and the black-to-move number") {
|
||||||
|
val startFen = "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3"
|
||||||
|
val moves = playUci(startFen, List("a7a6", "b5a4", "g8f6"))
|
||||||
|
val pgn = Pgn.write(startFen, moves, "*")
|
||||||
|
assert(pgn.contains("""[FEN "r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3"]"""), pgn)
|
||||||
|
assert(pgn.contains("3... a6 4. Ba4 Nf6"), pgn)
|
||||||
|
val game = Pgn.read(pgn)
|
||||||
|
assertEquals(game.startFen, startFen)
|
||||||
|
assertEquals(game.moves, moves)
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package gambit
|
||||||
|
|
||||||
|
class SanTest extends munit.FunSuite:
|
||||||
|
|
||||||
|
private def moveByUci(fen: String, uci: String): (Position, Int) =
|
||||||
|
val pos = Fen.parse(fen)
|
||||||
|
val legal = new MoveList()
|
||||||
|
MoveGen.generateLegal(pos, legal)
|
||||||
|
var found = 0
|
||||||
|
var i = 0
|
||||||
|
while i < legal.size do
|
||||||
|
if Move.uci(legal(i)) == uci then found = legal(i)
|
||||||
|
i += 1
|
||||||
|
(pos, found)
|
||||||
|
|
||||||
|
private def san(fen: String, uci: String): String =
|
||||||
|
val (pos, m) = moveByUci(fen, uci)
|
||||||
|
San.toSan(pos, m)
|
||||||
|
|
||||||
|
test("plain piece and pawn moves") {
|
||||||
|
assertEquals(san(Fen.startPosition, "g1f3"), "Nf3")
|
||||||
|
assertEquals(san(Fen.startPosition, "e2e4"), "e4")
|
||||||
|
}
|
||||||
|
|
||||||
|
test("captures, en passant and promotion") {
|
||||||
|
assertEquals(san("4k3/8/8/8/6n1/8/8/4K1R1 w - - 0 1", "g1g4"), "Rxg4")
|
||||||
|
assertEquals(san("rnbqkbnr/ppp1pppp/8/3pP3/8/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 3", "e5d6"), "exd6")
|
||||||
|
assertEquals(san("8/P7/8/8/6k1/8/8/7K w - - 0 1", "a7a8q"), "a8=Q")
|
||||||
|
assertEquals(san("8/P7/8/8/6k1/8/8/7K w - - 0 1", "a7a8n"), "a8=N")
|
||||||
|
}
|
||||||
|
|
||||||
|
test("castling both sides") {
|
||||||
|
assertEquals(san("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", "e1g1"), "O-O")
|
||||||
|
assertEquals(san("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1", "e1c1"), "O-O-O")
|
||||||
|
}
|
||||||
|
|
||||||
|
test("check and checkmate suffixes") {
|
||||||
|
assertEquals(san("6k1/5ppp/8/8/8/8/8/R6K w - - 0 1", "a1a8"), "Ra8#")
|
||||||
|
assertEquals(san("4k3/8/8/8/8/8/8/4K1R1 w - - 0 1", "g1g8"), "Rg8+")
|
||||||
|
}
|
||||||
|
|
||||||
|
test("file disambiguation between two knights") {
|
||||||
|
val fen = "4k3/8/8/8/8/5N2/8/1N2K3 w - - 0 1"
|
||||||
|
assertEquals(san(fen, "b1d2"), "Nbd2")
|
||||||
|
assertEquals(san(fen, "f3d2"), "Nfd2")
|
||||||
|
}
|
||||||
|
|
||||||
|
test("rank disambiguation between two rooks on a file") {
|
||||||
|
val fen = "4k3/8/8/8/8/R7/8/R3K3 w - - 0 1"
|
||||||
|
assertEquals(san(fen, "a1a2"), "R1a2")
|
||||||
|
assertEquals(san(fen, "a3a2"), "R3a2")
|
||||||
|
}
|
||||||
|
|
||||||
|
test("every legal move round-trips through SAN") {
|
||||||
|
val positions = List(
|
||||||
|
Fen.startPosition,
|
||||||
|
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1",
|
||||||
|
"rnbqkbnr/ppp1pppp/8/3pP3/8/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 3",
|
||||||
|
"8/P7/8/8/8/8/8/k6K w - - 0 1",
|
||||||
|
"r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1",
|
||||||
|
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 1"
|
||||||
|
)
|
||||||
|
for fen <- positions do
|
||||||
|
val pos = Fen.parse(fen)
|
||||||
|
val legal = new MoveList()
|
||||||
|
MoveGen.generateLegal(pos, legal)
|
||||||
|
var i = 0
|
||||||
|
while i < legal.size do
|
||||||
|
val m = legal(i)
|
||||||
|
val text = San.toSan(pos, m)
|
||||||
|
assertEquals(San.parse(pos, text), m, s"$fen : $text")
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
Reference in new issue
Block a user