Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions core/src/main/scala/Replay.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,20 @@ object Replay:
): (Game, List[(Game, Uci.WithSan)], Option[ErrorStr]) =
val init = makeGame(variant, initialFen.some)
val emptyGames = List.empty[(Game, Uci.WithSan)]
sans
sans.zipWithIndex
.foldM((init, emptyGames)):
case ((head, games), str) =>
case ((head, games), (str, index)) =>
Parser
.san(str)
.flatMap: san =>
san(head.situation)
.map: move =>
val newGame = move.applyGame(head)
(newGame, (newGame, Uci.WithSan(move.toUci, str)) :: games)
.bimap(
_ => Reader.makeError(init.ply + index, san),
{ move =>
val newGame = move.applyGame(head)
(newGame, (newGame, Uci.WithSan(move.toUci, str)) :: games)
}
)
.leftMap(err => (init, games, err.some))
.map(gs => (init, gs._2, none))
.merge
Expand Down Expand Up @@ -160,14 +164,13 @@ object Replay:
val after = moveOrDrop.finalizeAfter
val fen = Fen.write(Game(Situation(after, ply.turn), ply = ply))
if compareFen(fen) then ply.asRight
else recursivePlyAtFen(Situation(after, !sit.color), rest, ply + 1)
else recursivePlyAtFen(Situation(after, !sit.color), rest, ply.next)

val sit = initialFen.flatMap { Fen.read(variant, _) } | Situation(variant)
val sit = initialFen.flatMap(Fen.read(variant, _)) | Situation(variant)

Parser
.moves(sans)
.flatMap: moves =>
recursivePlyAtFen(sit, moves.value, Ply(1))
.flatMap(moves => recursivePlyAtFen(sit, moves.value, Ply.firstMove))

private def makeGame(variant: Variant, initialFen: Option[Fen.Full]): Game =
val g = Game(variant.some, initialFen)
Expand Down
9 changes: 4 additions & 5 deletions core/src/main/scala/format/pgn/Reader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,16 @@ object Reader:
private def makeReplay(game: Game, sans: Sans): Result =
sans.value.zipWithIndex
.foldM(Replay(game)) { case (replay, (san, index)) =>
san(replay.state.situation).bimap(_ => (replay, makeError(index, game.ply, san)), replay.addMove(_))
san(replay.state.situation).bimap(_ => (replay, makeError(game.ply + index, san)), replay.addMove(_))
}
.match
case Left(replay, err) => Result.Incomplete(replay, err)
case Right(replay) => Result.Complete(replay)

inline def makeError(index: Int, startedPly: Ply, san: San): ErrorStr =
val ply = startedPly + index
val moveAt = ply.fullMoveNumber.value
inline def makeError(currentPly: Ply, san: San): ErrorStr =
val moveAt = currentPly.fullMoveNumber.value
val move = san.rawString.getOrElse(san.toString)
ErrorStr(s"Cannot play $move at move $moveAt by ${ply.turn.name}")
ErrorStr(s"Cannot play $move at move $moveAt by ${currentPly.turn.name}")

private def makeGame(tags: Tags) =
val g = Game(variantOption = tags.variant, fen = tags.fen)
Expand Down
16 changes: 15 additions & 1 deletion test-kit/src/test/scala/ReplayTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package chess

import cats.syntax.option.*
import chess.format.pgn.{ Fixtures, SanStr }
import chess.variant.Chess960
import chess.variant.{ Chess960, Standard }

import format.{ FullFen, Fen, Uci }
import macros.uci
Expand Down Expand Up @@ -120,3 +120,17 @@ class ReplayTest extends ChessTest:
.foreach: moves =>
assertMatch(Replay.gameMoveWhileValid(moves, chess.format.Fen.initial, chess.variant.Standard)):
case (_, games, None) => assertEquals(games.size, moves.size)

/*============== Error Messages ==============*/

test("error message for white"):
val sans = List(SanStr("Nf7"))
Replay.gameMoveWhileValid(sans, Standard.initialFen, Standard) match
case (_, _, error) =>
assertEquals(error, ErrorStr("Cannot play Nf7 at move 1 by white").some)

test("error message for black"):
val sans = List("e4", "e4").map(SanStr(_))
Replay.gameMoveWhileValid(sans, Standard.initialFen, Standard) match
case (_, _, error) =>
assertEquals(error, ErrorStr("Cannot play e4 at move 1 by black").some)
12 changes: 10 additions & 2 deletions test-kit/src/test/scala/format/pgn/ReaderTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,23 @@ class ReaderTest extends ChessTest:

/*============== Error Messages ==============*/

test("simple error message"):
test("error message by white"):
val pgn = PgnStr("1.e6")
Reader
.full(pgn)
.assertRight:
case Incomplete(replay, error) =>
assertEquals(error, ErrorStr("Cannot play e6 at move 1 by white"))

test("more complicated error message"):
test("error message by black"):
val pgn = PgnStr("1.e4 e4")
Reader
.full(pgn)
.assertRight:
case Incomplete(replay, error) =>
assertEquals(error, ErrorStr("Cannot play e4 at move 1 by black"))

test("more error message"):
val pgn = PgnStr(
"e3 Nc6 d4 Nf6 c3 e5 dxe5 Nxe5 Bb5 a6 Ba4 b5 Bb3 d5 e4 dxe4 f4 Qxd1+ Kxd1 Nd3 Be3 Ng4 Bd4 Ngf2+ Bxf2 Nxf2+ Ke1 Nxh1 Bd5 Ra7 Bc6+ Kd8 Bxe4 Bd6 g3 Re8 Nd2 f5 Ne2 fxe4 Kf1 e3 Kg2 exd2 Rxh1 Bb7+ Kf2 Bg3+ Kf3 d1=Q#"
)
Expand Down