Improve game repo, model and tests

pull/1/merge
Thibault Duplessis 2012-03-03 13:47:39 +01:00
parent a7b4ee2873
commit 74457ebf7f
8 changed files with 177 additions and 18 deletions

View File

@ -1,7 +1,7 @@
package lila.system
package repo
import model._
import DbGame._
import com.novus.salat._
import com.novus.salat.global._
@ -11,7 +11,23 @@ import com.mongodb.casbah.Imports._
class GameRepo(collection: MongoCollection) extends SalatDAO[DbGame, String](collection) {
def game(id: String): Option[DbGame] = findOneByID(id)
def game(gameId: String): Option[DbGame] =
if (gameId.size == gameIdSize) findOneByID(gameId)
else None
def player(fullId: String): Option[(DbGame, DbPlayer)] = for {
game game(fullId take gameIdSize)
player game playerById (fullId drop gameIdSize)
} yield (game, player)
def player(gameId: String, color: String): Option[(DbGame, DbPlayer)] = for {
game game(gameId take gameIdSize)
player game playerByColor color
} yield (game, player)
override def save(game: DbGame) {
update(DBObject("_id" -> game.id), _grater asDBObject game, false, false)
}
def anyGame = findOne(DBObject())
}

View File

@ -16,7 +16,17 @@ case class DbGame(
clock: Option[DbClock],
lastMove: Option[String]) {
def toChess = {
def playerById(id: String) = playersById get id
def playerByColor(color: String) = playersByColor get color
lazy val playersByColor: Map[String, DbPlayer] = players map { p (p.color, p) } toMap
lazy val playersById: Map[String, DbPlayer] = players map { p (p.id, p) } toMap
def fullIdOf(player: DbPlayer): Option[String] =
(players contains player) option id + player.id
def toChess: Game = {
def posPiece(posCode: Char, roleCode: Char, color: Color): Option[(Pos, Piece)] = for {
pos Piotr.decodePos get posCode
@ -29,10 +39,9 @@ case class DbGame(
board = Board(
(for {
player players
color = Color.allByName(player.color)
color = Color.allByName(player.color) // unsafe
piece player.ps.split(' ').toList
} yield piece.toList match {
case pos :: role :: Nil posPiece(pos, role, color)
case pos :: role :: rest posPiece(pos, role, color)
case _ None
}).flatten toMap,
@ -58,4 +67,25 @@ case class DbGame(
)
)
}
def update(game: Game): DbGame = {
copy(
pgn = game.pgnMoves,
players = for {
player players
color = Color.allByName(player.color) // unsafe
} yield player.copy(
ps = game.board actorsOf color map { actor
(Piotr encodePos actor.pos).toString + actor.piece.role.forsyth
} mkString " "
)
)
}
}
object DbGame {
val gameIdSize = 8
val playerIdSize = 4
val fullIdSize = 12
}

View File

@ -2,7 +2,10 @@ package lila
import ornicar.scalalib._
package object system extends OrnicarValidation with OrnicarCommon {
package object system
extends OrnicarValidation
with OrnicarCommon
with scalaz.Booleans {
implicit def addPP[A](a: A) = new {
def pp[A] = a~println

View File

@ -0,0 +1,50 @@
package lila.system
import model._
import lila.chess._
import format.Visual
import Pos._
class ChessToModelTest extends SystemTest {
"chess to model conversion" should {
"new game" in {
val game = newDbGame.toChess
"identity" in {
newDbGame update game must_== newDbGame
}
}
"played game" in {
val dbGame = dbGame4
val game = Game("""
r kb r
ppp pppp
np
P
P N
P B P
P P P P
R QK q
""", White, dbGame.pgn)
"identity" in {
dbGame update game must_== dbGame
}
"pieces" in {
val dbg2 = newDbGame update game
"white" in {
dbg2 playerByColor "white" map (_.ps) map sortPs must_== {
dbGame playerByColor "white" map (_.ps) map sortPs
}
}
"black" in {
dbg2 playerByColor "black" map (_.ps) map sortPs must_== {
dbGame playerByColor "black" map (_.ps) map sortPs
}
}
}
}
}
def sortPs(ps: String): String = ps.split(' ').toList.sorted mkString " "
}

View File

@ -1,9 +1,15 @@
package lila.system
import scala.util.Random
import model._
import DbGame._
trait Fixtures {
def randomString(len: Int) = List.fill(len)(randomChar) mkString
private def randomChar = (Random.nextInt(25) + 97).toChar
lazy val newDbGame = DbGame(
id = "arstdhne",
players = List(white, black),
@ -14,6 +20,11 @@ trait Fixtures {
clock = None
)
def newDbGameWithRandomIds() = newDbGame.copy(
id = randomString(gameIdSize),
players = newDbGame.players map (_.copy(id = randomString(playerIdSize)))
)
lazy val white = newDbPlayer("white", "ip ar jp bn kp cb lp dq mp ek np fb op gn pp hr")
lazy val black = newDbPlayer("black", "Wp 4r Xp 5n Yp 6b Zp 7q 0p 8k 1p 9b 2p !n 3p ?r")
@ -39,15 +50,6 @@ trait Fixtures {
lastMove = None
)
// "clock" : {
//"color" : "black",
//"increment" : 5,
//"limit" : 1200,
//"times" : {
//"white" : 196.25,
//"black" : 304.1
//}
//}
lazy val dbGame2 = DbGame(
id = "-176b4to",
players = List(
@ -81,4 +83,15 @@ trait Fixtures {
lastMove = Some("a3 a8")
)
lazy val dbGame4 = DbGame(
id = "huhuhiha",
players = List(
newDbPlayer("white", "ip ar sp sN kp ub Bp dq Kp ek np LB wp Fn pp hR"),
newDbPlayer("black", "Wp 4r Xp Qn Yp LB Rp hq 0p 8k 1p 9b 2p sN 3p ?r")),
pgn = "e4 Nc6 Nf3 Nf6 e5 Ne4 d3 Nc5 Be3 d6 d4 Ne4 Bd3 Bf5 Nc3 Nxc3 bxc3 Qd7 Bxf5 Qxf5 Nh4 Qe4 g3 Qxh1+",
status = 31,
turns = 24,
clock = None,
lastMove = None
)
}

View File

@ -19,5 +19,47 @@ class GameRepoTest extends SystemTest {
}
}
}
"find a player" in {
"by private ID" in {
"non existing" in {
repo player "huhu" must be none
}
"existing" in {
val player = anyGame.players.head
anyGame fullIdOf player flatMap repo.player must beSome.like {
case (g, p) p.id must_== player.id
}
}
}
"by ID and color" in {
"non existing" in {
repo.player(anyGame.id, "huhu") must be none
}
"existing" in {
val player = anyGame.players.head
repo.player(anyGame.id, player.color) must beSome.like {
case (g, p) p.id must_== player.id
}
}
}
}
"insert a new game" in {
sequential
val game = newDbGameWithRandomIds()
repo insert game
"find the saved game" in {
repo game game.id must_== Some(game)
}
}
"update a game" in {
sequential
val game = newDbGameWithRandomIds()
repo insert game
val updated = game.copy(turns = game.turns + 1)
repo save updated
"find the updated game" in {
repo game updated.id must_== Some(updated)
}
}
}
}

View File

@ -9,9 +9,9 @@ import Pos._
class ModelToChessTest extends SystemTest {
"model to chess conversion" should {
//"new game" in {
//newDbGame.toChess must_== Game()
//}
"new game" in {
newDbGame.toChess must_== Game()
}
"played game" in {
val game = dbGame1.toChess
"player" in {

View File

@ -3,8 +3,13 @@ package lila.system
import org.specs2.mutable.Specification
import ornicar.scalalib.test.OrnicarValidationMatchers
import lila.chess._
import format.Visual
trait SystemTest
extends Specification
with OrnicarValidationMatchers
with Fixtures {
implicit def stringToBoard(str: String): Board = Visual << str
}