Event export and basic sync: can play with the AI
This commit is contained in:
parent
ef73f21eed
commit
8a3922cb50
|
@ -5,14 +5,17 @@ import DataForm._
|
||||||
|
|
||||||
import play.api._
|
import play.api._
|
||||||
import play.api.mvc._
|
import play.api.mvc._
|
||||||
import play.api.libs.json._
|
import com.codahale.jerkson.Json.{ generate => jsonify }
|
||||||
|
|
||||||
object Application extends Controller {
|
object Application extends Controller {
|
||||||
|
|
||||||
val env = new HttpEnv(Play.unsafeApplication.configuration.underlying)
|
val env = new HttpEnv(Play.unsafeApplication.configuration.underlying)
|
||||||
|
val json = "application/json"
|
||||||
|
|
||||||
def sync(id: String, color: String, version: Int, fullId: String) = Action {
|
def sync(id: String, color: String, version: Int, fullId: String) = Action {
|
||||||
Ok(toJson(env.syncer.sync(id, color, version, fullId)))
|
Ok(jsonify(
|
||||||
|
env.syncer.sync(id, color, version, fullId).unsafePerformIO
|
||||||
|
)) as json
|
||||||
}
|
}
|
||||||
|
|
||||||
def move(fullId: String) = Action { implicit request ⇒
|
def move(fullId: String) = Action { implicit request ⇒
|
||||||
|
|
|
@ -14,13 +14,13 @@ trait Dependencies {
|
||||||
val scalaz = "org.scalaz" %% "scalaz-core" % "6.0.4"
|
val scalaz = "org.scalaz" %% "scalaz-core" % "6.0.4"
|
||||||
val specs2 = "org.specs2" %% "specs2" % "1.8.2"
|
val specs2 = "org.specs2" %% "specs2" % "1.8.2"
|
||||||
val redis = "net.debasishg" %% "redisclient" % "2.4.2"
|
val redis = "net.debasishg" %% "redisclient" % "2.4.2"
|
||||||
val json = "net.liftweb" %% "lift-json" % "2.4"
|
|
||||||
val casbah = "com.mongodb.casbah" %% "casbah" % "2.1.5-1"
|
val casbah = "com.mongodb.casbah" %% "casbah" % "2.1.5-1"
|
||||||
val salat = "com.novus" %% "salat-core" % "0.0.8-SNAPSHOT"
|
val salat = "com.novus" %% "salat-core" % "0.0.8-SNAPSHOT"
|
||||||
val slf4j = "org.slf4j" % "slf4j-nop" % "1.6.4"
|
val slf4j = "org.slf4j" % "slf4j-nop" % "1.6.4"
|
||||||
val scalalib = "com.github.ornicar" %% "scalalib" % "1.23"
|
val scalalib = "com.github.ornicar" %% "scalalib" % "1.23"
|
||||||
val hasher = "com.roundeights" % "hasher" % "0.3" from "http://cloud.github.com/downloads/Nycto/Hasher/hasher_2.9.1-0.3.jar"
|
val hasher = "com.roundeights" % "hasher" % "0.3" from "http://cloud.github.com/downloads/Nycto/Hasher/hasher_2.9.1-0.3.jar"
|
||||||
val config = "com.typesafe.config" % "config" % "0.3.0"
|
val config = "com.typesafe.config" % "config" % "0.3.0"
|
||||||
|
val json = "com.codahale" %% "jerkson" % "0.5.0"
|
||||||
|
|
||||||
// benchmark
|
// benchmark
|
||||||
val instrumenter = "com.google.code.java-allocation-instrumenter" % "java-allocation-instrumenter" % "2.0"
|
val instrumenter = "com.google.code.java-allocation-instrumenter" % "java-allocation-instrumenter" % "2.0"
|
||||||
|
|
|
@ -6,6 +6,8 @@ import scalaz.effects._
|
||||||
|
|
||||||
final class Syncer(repo: GameRepo) {
|
final class Syncer(repo: GameRepo) {
|
||||||
|
|
||||||
|
val reload = Map("reload" -> true)
|
||||||
|
|
||||||
def sync(
|
def sync(
|
||||||
id: String,
|
id: String,
|
||||||
colorString: String,
|
colorString: String,
|
||||||
|
@ -15,16 +17,16 @@ final class Syncer(repo: GameRepo) {
|
||||||
color ← io { Color(colorString) err "Invalid color" }
|
color ← io { Color(colorString) err "Invalid color" }
|
||||||
gameAndPlayer ← repo.player(id, color)
|
gameAndPlayer ← repo.player(id, color)
|
||||||
(g, p) = gameAndPlayer
|
(g, p) = gameAndPlayer
|
||||||
//events ← io { eventsSince(p, version) }
|
} yield {
|
||||||
} yield Map(
|
p.eventStack eventsSince version map { events ⇒
|
||||||
"v" -> p.eventStack.version,
|
Map(
|
||||||
//"e" -> events map (_.toMap),
|
"v" -> p.eventStack.lastVersion,
|
||||||
"p" -> g.player,
|
"e" -> (events map (_.export)),
|
||||||
"t" -> g.turns
|
"p" -> g.player.color.name,
|
||||||
)
|
"t" -> g.turns
|
||||||
} except (e ⇒ io(Map("reload" -> true)))
|
)
|
||||||
|
} getOrElse reload
|
||||||
def eventsSince(player: DbPlayer, version: Int): List[Event] =
|
}
|
||||||
player.eventStack.eventsSince(version) | Nil
|
} except (e ⇒ io(reload))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@ trait SystemEnv {
|
||||||
repo = gameRepo,
|
repo = gameRepo,
|
||||||
ai = ai)
|
ai = ai)
|
||||||
|
|
||||||
|
def syncer = new Syncer(
|
||||||
|
repo = gameRepo)
|
||||||
|
|
||||||
lazy val ai: Ai = new StupidAi
|
lazy val ai: Ai = new StupidAi
|
||||||
|
|
||||||
def gameRepo = new GameRepo(
|
def gameRepo = new GameRepo(
|
||||||
|
|
|
@ -6,6 +6,7 @@ import Pos.{ piotr, allPiotrs }
|
||||||
|
|
||||||
sealed trait Event {
|
sealed trait Event {
|
||||||
def encode: String
|
def encode: String
|
||||||
|
def export: Map[String, Any]
|
||||||
}
|
}
|
||||||
object Event {
|
object Event {
|
||||||
|
|
||||||
|
@ -48,6 +49,8 @@ object EventDecoder {
|
||||||
|
|
||||||
case class StartEvent() extends Event {
|
case class StartEvent() extends Event {
|
||||||
def encode = "s"
|
def encode = "s"
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "start")
|
||||||
}
|
}
|
||||||
object StartEvent extends EventDecoder {
|
object StartEvent extends EventDecoder {
|
||||||
def decode(str: String) = Some(StartEvent())
|
def decode(str: String) = Some(StartEvent())
|
||||||
|
@ -55,6 +58,11 @@ object StartEvent extends EventDecoder {
|
||||||
|
|
||||||
case class MoveEvent(orig: Pos, dest: Pos, color: Color) extends Event {
|
case class MoveEvent(orig: Pos, dest: Pos, color: Color) extends Event {
|
||||||
def encode = "m" + orig.piotr + dest.piotr + color.letter
|
def encode = "m" + orig.piotr + dest.piotr + color.letter
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "move",
|
||||||
|
"from" -> orig.key,
|
||||||
|
"to" -> dest.key,
|
||||||
|
"color" -> color.name)
|
||||||
}
|
}
|
||||||
object MoveEvent extends EventDecoder {
|
object MoveEvent extends EventDecoder {
|
||||||
def apply(move: Move): MoveEvent = MoveEvent(move.orig, move.dest, move.piece.color)
|
def apply(move: Move): MoveEvent = MoveEvent(move.orig, move.dest, move.piece.color)
|
||||||
|
@ -72,6 +80,11 @@ case class PossibleMovesEvent(moves: Map[Pos, List[Pos]]) extends Event {
|
||||||
def encode = "p" + (moves map {
|
def encode = "p" + (moves map {
|
||||||
case (orig, dests) ⇒ (orig :: dests) map (_.piotr) mkString
|
case (orig, dests) ⇒ (orig :: dests) map (_.piotr) mkString
|
||||||
} mkString ",")
|
} mkString ",")
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "possible_moves",
|
||||||
|
"possible_moves" -> (moves map {
|
||||||
|
case (o, d) ⇒ o.key -> (d map (_.key) mkString)
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
object PossibleMovesEvent extends EventDecoder {
|
object PossibleMovesEvent extends EventDecoder {
|
||||||
def decode(str: String) = Some(PossibleMovesEvent(
|
def decode(str: String) = Some(PossibleMovesEvent(
|
||||||
|
@ -90,6 +103,9 @@ object PossibleMovesEvent extends EventDecoder {
|
||||||
|
|
||||||
case class EnpassantEvent(killed: Pos) extends Event {
|
case class EnpassantEvent(killed: Pos) extends Event {
|
||||||
def encode = "E" + killed.piotr
|
def encode = "E" + killed.piotr
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "enpassant",
|
||||||
|
"killed" -> killed.key)
|
||||||
}
|
}
|
||||||
object EnpassantEvent extends EventDecoder {
|
object EnpassantEvent extends EventDecoder {
|
||||||
def decode(str: String) = for {
|
def decode(str: String) = for {
|
||||||
|
@ -100,7 +116,11 @@ object EnpassantEvent extends EventDecoder {
|
||||||
|
|
||||||
case class CastlingEvent(king: (Pos, Pos), rook: (Pos, Pos), color: Color) extends Event {
|
case class CastlingEvent(king: (Pos, Pos), rook: (Pos, Pos), color: Color) extends Event {
|
||||||
def encode = "c" + king._1.piotr + king._2.piotr + rook._1.piotr + rook._2.piotr + color.letter
|
def encode = "c" + king._1.piotr + king._2.piotr + rook._1.piotr + rook._2.piotr + color.letter
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "castling",
|
||||||
|
"king" -> List(king._1.key, king._2.key),
|
||||||
|
"rook" -> List(rook._1.key, rook._2.key),
|
||||||
|
"color" -> color.name)
|
||||||
}
|
}
|
||||||
object CastlingEvent extends EventDecoder {
|
object CastlingEvent extends EventDecoder {
|
||||||
def decode(str: String) = str.toList match {
|
def decode(str: String) = str.toList match {
|
||||||
|
@ -119,6 +139,9 @@ object CastlingEvent extends EventDecoder {
|
||||||
|
|
||||||
case class RedirectEvent(url: String) extends Event {
|
case class RedirectEvent(url: String) extends Event {
|
||||||
def encode = "r" + url
|
def encode = "r" + url
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "redirect",
|
||||||
|
"url" -> url)
|
||||||
}
|
}
|
||||||
object RedirectEvent extends EventDecoder {
|
object RedirectEvent extends EventDecoder {
|
||||||
def decode(str: String) = Some(RedirectEvent(str))
|
def decode(str: String) = Some(RedirectEvent(str))
|
||||||
|
@ -126,6 +149,10 @@ object RedirectEvent extends EventDecoder {
|
||||||
|
|
||||||
case class PromotionEvent(role: PromotableRole, pos: Pos) extends Event {
|
case class PromotionEvent(role: PromotableRole, pos: Pos) extends Event {
|
||||||
def encode = "P" + role.forsyth + pos.piotr
|
def encode = "P" + role.forsyth + pos.piotr
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "promotion",
|
||||||
|
"key" -> pos.key,
|
||||||
|
"pieceClass" -> role.toString)
|
||||||
}
|
}
|
||||||
object PromotionEvent extends EventDecoder {
|
object PromotionEvent extends EventDecoder {
|
||||||
def decode(str: String) = str.toList match {
|
def decode(str: String) = str.toList match {
|
||||||
|
@ -139,6 +166,9 @@ object PromotionEvent extends EventDecoder {
|
||||||
|
|
||||||
case class CheckEvent(pos: Pos) extends Event {
|
case class CheckEvent(pos: Pos) extends Event {
|
||||||
def encode = "C" + pos.piotr
|
def encode = "C" + pos.piotr
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "check",
|
||||||
|
"key" -> pos.key)
|
||||||
}
|
}
|
||||||
object CheckEvent extends EventDecoder {
|
object CheckEvent extends EventDecoder {
|
||||||
def decode(str: String) = for {
|
def decode(str: String) = for {
|
||||||
|
@ -149,6 +179,9 @@ object CheckEvent extends EventDecoder {
|
||||||
|
|
||||||
case class MessageEvent(author: String, message: String) extends Event {
|
case class MessageEvent(author: String, message: String) extends Event {
|
||||||
def encode = "M" + author + " " + message.replace("|", "(pipe)")
|
def encode = "M" + author + " " + message.replace("|", "(pipe)")
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "message",
|
||||||
|
"message" -> List(author, message))
|
||||||
}
|
}
|
||||||
object MessageEvent extends EventDecoder {
|
object MessageEvent extends EventDecoder {
|
||||||
def decode(str: String) = str.split(' ').toList match {
|
def decode(str: String) = str.split(' ').toList match {
|
||||||
|
@ -161,6 +194,8 @@ object MessageEvent extends EventDecoder {
|
||||||
|
|
||||||
case class EndEvent() extends Event {
|
case class EndEvent() extends Event {
|
||||||
def encode = "e"
|
def encode = "e"
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "end")
|
||||||
}
|
}
|
||||||
object EndEvent extends EventDecoder {
|
object EndEvent extends EventDecoder {
|
||||||
def decode(str: String) = Some(EndEvent())
|
def decode(str: String) = Some(EndEvent())
|
||||||
|
@ -168,6 +203,8 @@ object EndEvent extends EventDecoder {
|
||||||
|
|
||||||
case class ThreefoldEvent() extends Event {
|
case class ThreefoldEvent() extends Event {
|
||||||
def encode = "t"
|
def encode = "t"
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "threefold_repetition")
|
||||||
}
|
}
|
||||||
object ThreefoldEvent extends EventDecoder {
|
object ThreefoldEvent extends EventDecoder {
|
||||||
def decode(str: String) = Some(ThreefoldEvent())
|
def decode(str: String) = Some(ThreefoldEvent())
|
||||||
|
@ -175,6 +212,8 @@ object ThreefoldEvent extends EventDecoder {
|
||||||
|
|
||||||
case class ReloadTableEvent() extends Event {
|
case class ReloadTableEvent() extends Event {
|
||||||
def encode = "R"
|
def encode = "R"
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "reload_table")
|
||||||
}
|
}
|
||||||
object ReloadTableEvent extends EventDecoder {
|
object ReloadTableEvent extends EventDecoder {
|
||||||
def decode(str: String) = Some(ReloadTableEvent())
|
def decode(str: String) = Some(ReloadTableEvent())
|
||||||
|
@ -182,6 +221,10 @@ object ReloadTableEvent extends EventDecoder {
|
||||||
|
|
||||||
case class MoretimeEvent(color: Color, seconds: Int) extends Event {
|
case class MoretimeEvent(color: Color, seconds: Int) extends Event {
|
||||||
def encode = "T" + color.letter + seconds
|
def encode = "T" + color.letter + seconds
|
||||||
|
def export = Map(
|
||||||
|
"type" -> "moretime",
|
||||||
|
"color" -> color.name,
|
||||||
|
"seconds" -> seconds)
|
||||||
}
|
}
|
||||||
object MoretimeEvent extends EventDecoder {
|
object MoretimeEvent extends EventDecoder {
|
||||||
def decode(str: String) = for {
|
def decode(str: String) = for {
|
||||||
|
|
|
@ -29,14 +29,12 @@ case class EventStack(events: List[(Int, Event)]) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def version: Int = events.lastOption map (_._1) getOrElse 0
|
|
||||||
|
|
||||||
def eventsSince(version: Int): Option[List[Event]] = for {
|
def eventsSince(version: Int): Option[List[Event]] = for {
|
||||||
first <- firstVersion
|
first ← firstVersion
|
||||||
if version >= first - 1
|
if version >= first - 1
|
||||||
last <- lastVersion
|
last ← lastVersion
|
||||||
if version <= last
|
if version <= last
|
||||||
} yield sortedEvents dropWhile { ve => ve._1 <= version } map (_._2)
|
} yield sortedEvents dropWhile { ve ⇒ ve._1 <= version } map (_._2)
|
||||||
|
|
||||||
def withEvents(newEvents: List[Event]): EventStack = {
|
def withEvents(newEvents: List[Event]): EventStack = {
|
||||||
|
|
||||||
|
@ -45,7 +43,7 @@ case class EventStack(events: List[(Int, Event)]) {
|
||||||
case event :: rest ⇒ (v + 1, event) :: versionEvents(v + 1, rest)
|
case event :: rest ⇒ (v + 1, event) :: versionEvents(v + 1, rest)
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(events = events ++ versionEvents(version, newEvents))
|
copy(events = events ++ versionEvents(lastVersion getOrElse 0, newEvents))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,9 @@ B p p
|
||||||
"high version number" in {
|
"high version number" in {
|
||||||
found must beIO.like {
|
found must beIO.like {
|
||||||
case vg ⇒ vg must beSuccess.like {
|
case vg ⇒ vg must beSuccess.like {
|
||||||
case g ⇒ g.player(White).eventStack.version must be_>(20)
|
case g ⇒ g.player(White).eventStack.lastVersion must beSome.like {
|
||||||
|
case v => v must be_>(20)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue