Improve game repo, model and tests
This commit is contained in:
parent
a7b4ee2873
commit
74457ebf7f
|
@ -1,7 +1,7 @@
|
||||||
package lila.system
|
package lila.system
|
||||||
package repo
|
|
||||||
|
|
||||||
import model._
|
import model._
|
||||||
|
import DbGame._
|
||||||
|
|
||||||
import com.novus.salat._
|
import com.novus.salat._
|
||||||
import com.novus.salat.global._
|
import com.novus.salat.global._
|
||||||
|
@ -11,7 +11,23 @@ import com.mongodb.casbah.Imports._
|
||||||
|
|
||||||
class GameRepo(collection: MongoCollection) extends SalatDAO[DbGame, String](collection) {
|
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())
|
def anyGame = findOne(DBObject())
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,17 @@ case class DbGame(
|
||||||
clock: Option[DbClock],
|
clock: Option[DbClock],
|
||||||
lastMove: Option[String]) {
|
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 {
|
def posPiece(posCode: Char, roleCode: Char, color: Color): Option[(Pos, Piece)] = for {
|
||||||
pos ← Piotr.decodePos get posCode
|
pos ← Piotr.decodePos get posCode
|
||||||
|
@ -29,10 +39,9 @@ case class DbGame(
|
||||||
board = Board(
|
board = Board(
|
||||||
(for {
|
(for {
|
||||||
player ← players
|
player ← players
|
||||||
color = Color.allByName(player.color)
|
color = Color.allByName(player.color) // unsafe
|
||||||
piece ← player.ps.split(' ').toList
|
piece ← player.ps.split(' ').toList
|
||||||
} yield piece.toList match {
|
} yield piece.toList match {
|
||||||
case pos :: role :: Nil ⇒ posPiece(pos, role, color)
|
|
||||||
case pos :: role :: rest ⇒ posPiece(pos, role, color)
|
case pos :: role :: rest ⇒ posPiece(pos, role, color)
|
||||||
case _ ⇒ None
|
case _ ⇒ None
|
||||||
}).flatten toMap,
|
}).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
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,10 @@ package lila
|
||||||
|
|
||||||
import ornicar.scalalib._
|
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 {
|
implicit def addPP[A](a: A) = new {
|
||||||
def pp[A] = a~println
|
def pp[A] = a~println
|
||||||
|
|
50
system/src/test/scala/ChessToModelTest.scala
Normal file
50
system/src/test/scala/ChessToModelTest.scala
Normal 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 " "
|
||||||
|
}
|
|
@ -1,9 +1,15 @@
|
||||||
package lila.system
|
package lila.system
|
||||||
|
|
||||||
|
import scala.util.Random
|
||||||
|
|
||||||
import model._
|
import model._
|
||||||
|
import DbGame._
|
||||||
|
|
||||||
trait Fixtures {
|
trait Fixtures {
|
||||||
|
|
||||||
|
def randomString(len: Int) = List.fill(len)(randomChar) mkString
|
||||||
|
private def randomChar = (Random.nextInt(25) + 97).toChar
|
||||||
|
|
||||||
lazy val newDbGame = DbGame(
|
lazy val newDbGame = DbGame(
|
||||||
id = "arstdhne",
|
id = "arstdhne",
|
||||||
players = List(white, black),
|
players = List(white, black),
|
||||||
|
@ -14,6 +20,11 @@ trait Fixtures {
|
||||||
clock = None
|
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 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")
|
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
|
lastMove = None
|
||||||
)
|
)
|
||||||
|
|
||||||
// "clock" : {
|
|
||||||
//"color" : "black",
|
|
||||||
//"increment" : 5,
|
|
||||||
//"limit" : 1200,
|
|
||||||
//"times" : {
|
|
||||||
//"white" : 196.25,
|
|
||||||
//"black" : 304.1
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
lazy val dbGame2 = DbGame(
|
lazy val dbGame2 = DbGame(
|
||||||
id = "-176b4to",
|
id = "-176b4to",
|
||||||
players = List(
|
players = List(
|
||||||
|
@ -81,4 +83,15 @@ trait Fixtures {
|
||||||
lastMove = Some("a3 a8")
|
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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ import Pos._
|
||||||
class ModelToChessTest extends SystemTest {
|
class ModelToChessTest extends SystemTest {
|
||||||
|
|
||||||
"model to chess conversion" should {
|
"model to chess conversion" should {
|
||||||
//"new game" in {
|
"new game" in {
|
||||||
//newDbGame.toChess must_== Game()
|
newDbGame.toChess must_== Game()
|
||||||
//}
|
}
|
||||||
"played game" in {
|
"played game" in {
|
||||||
val game = dbGame1.toChess
|
val game = dbGame1.toChess
|
||||||
"player" in {
|
"player" in {
|
||||||
|
|
|
@ -3,8 +3,13 @@ package lila.system
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
import ornicar.scalalib.test.OrnicarValidationMatchers
|
import ornicar.scalalib.test.OrnicarValidationMatchers
|
||||||
|
|
||||||
|
import lila.chess._
|
||||||
|
import format.Visual
|
||||||
|
|
||||||
trait SystemTest
|
trait SystemTest
|
||||||
extends Specification
|
extends Specification
|
||||||
with OrnicarValidationMatchers
|
with OrnicarValidationMatchers
|
||||||
with Fixtures {
|
with Fixtures {
|
||||||
|
|
||||||
|
implicit def stringToBoard(str: String): Board = Visual << str
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue