Complete forsyth notation tests and implementation

pull/1/merge
Thibault Duplessis 2012-03-06 22:38:07 +01:00
parent fdb7cd25fa
commit 1c9d39a2f1
2 changed files with 73 additions and 22 deletions

View File

@ -1,20 +1,43 @@
package lila.chess
package format
import Pos.posAt
import Pos.{ posAt, A8 }
/**
* Transform a game to standard Forsyth Edwards Notation
* http://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation
*/
object Forsyth extends Format[Game] {
object Forsyth {
def <<(source: String): Game = {
val useful = """\s*([\w\d/]+)\s.+""".r.replaceAllIn(
def <<(source: String): Option[Situation] = {
val boardChars = """\s*([\w\d/]+)\s.+""".r.replaceAllIn(
source.replace("/", ""),
m m group 1
)
Game()
).toList
val colorOption = for {
letter """^[\w\d/]+\s(\w).+$""".r.replaceAllIn(source, m m group 1).headOption
color Color(letter)
} yield color
def board(chars: List[Char], pos: Pos): Option[List[(Pos, Piece)]] = chars match {
case Nil Some(Nil)
case c :: rest c match {
case n if (n.toInt < 58)
tore(pos, n.toInt - 48) flatMap { board(rest, _) }
case n for {
role Role forsyth n.toLower
} yield (pos, Piece(Color(n.isUpper), role)) :: {
tore(pos, 1) flatMap { board(rest, _) } getOrElse Nil
}
}
}
for {
color colorOption
pieces board(boardChars, A8)
} yield Situation(Board(pieces), color)
}
def >>(game: Game): String = List(
@ -34,6 +57,11 @@ object Forsyth extends Format[Game] {
game.fullMoveNumber
) mkString " "
def tore(pos: Pos, n: Int): Option[Pos] = posAt(
((pos.x + n - 1) % 8 + 1),
(pos.y - (pos.x + n - 1) / 8)
)
private def exportBoard(board: Board) = {
{
for (y 8 to 1 by -1) yield {

View File

@ -42,34 +42,57 @@ class ForsythTest extends ChessTest {
}
}
"import" in {
"torus" in {
"A8 + 1" in { f.tore(A8, 1) must_== Some(B8) }
"A8 + 2" in { f.tore(A8, 2) must_== Some(C8) }
"A8 + 7" in { f.tore(A8, 7) must_== Some(H8) }
"A8 + 8" in { f.tore(A8, 8) must_== Some(A7) }
"C4 + 3" in { f.tore(C4, 3) must_== Some(F4) }
"C4 + 8" in { f.tore(C4, 8) must_== Some(C3) }
"F1 + 2" in { f.tore(F1, 2) must_== Some(H1) }
}
val moves = List(E2 -> E4, C7 -> C5, G1 -> F3, G8 -> H6, A2 -> A3)
def compare(ms: List[(Pos, Pos)], fen: String) =
Game().playMoveList(ms) must beSuccess.like {
case g (f << fen) must beSome.like {
case situation situation.board.visual must_== g.situation.board.visual
}
}
"new game" in {
f << "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" must_== Game()
compare(
Nil,
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
)
}
"one move" in {
Game().playMoveList(moves take 1) must beSuccess.like {
case g (f << "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1").situation must_== g.situation
}
compare(
moves take 1,
"rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1"
)
}
"2 moves" in {
Game().playMoveList(moves take 2) must beSuccess.like {
case g (f << "rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2") must_== g.situation
}
compare(
moves take 2,
"rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6 0 2"
)
}
"3 moves" in {
Game().playMoveList(moves take 3) must beSuccess.like {
case g (f << "rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2") must_== g.situation
}
compare(
moves take 3,
"rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2"
)
}
"4 moves" in {
Game().playMoveList(moves take 4) must beSuccess.like {
case g (f << "rnbqkb1r/pp1ppppp/7n/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3") must_== g.situation
}
compare(
moves take 4,
"rnbqkb1r/pp1ppppp/7n/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3"
)
}
"5 moves" in {
Game().playMoveList(moves take 5) must beSuccess.like {
case g (f << "rnbqkb1r/pp1ppppp/7n/2p5/4P3/P4N2/1PPP1PPP/RNBQKB1R b KQkq - 0 3") must_== g.situation
}
compare(
moves take 5,
"rnbqkb1r/pp1ppppp/7n/2p5/4P3/P4N2/1PPP1PPP/RNBQKB1R b KQkq - 0 3"
)
}
}
}