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.mvc._
|
||||
import play.api.libs.json._
|
||||
import com.codahale.jerkson.Json.{ generate => jsonify }
|
||||
|
||||
object Application extends Controller {
|
||||
|
||||
val env = new HttpEnv(Play.unsafeApplication.configuration.underlying)
|
||||
val json = "application/json"
|
||||
|
||||
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 ⇒
|
||||
|
|
|
@ -14,13 +14,13 @@ trait Dependencies {
|
|||
val scalaz = "org.scalaz" %% "scalaz-core" % "6.0.4"
|
||||
val specs2 = "org.specs2" %% "specs2" % "1.8.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 salat = "com.novus" %% "salat-core" % "0.0.8-SNAPSHOT"
|
||||
val slf4j = "org.slf4j" % "slf4j-nop" % "1.6.4"
|
||||
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 config = "com.typesafe.config" % "config" % "0.3.0"
|
||||
val json = "com.codahale" %% "jerkson" % "0.5.0"
|
||||
|
||||
// benchmark
|
||||
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) {
|
||||
|
||||
val reload = Map("reload" -> true)
|
||||
|
||||
def sync(
|
||||
id: String,
|
||||
colorString: String,
|
||||
|
@ -15,16 +17,16 @@ final class Syncer(repo: GameRepo) {
|
|||
color ← io { Color(colorString) err "Invalid color" }
|
||||
gameAndPlayer ← repo.player(id, color)
|
||||
(g, p) = gameAndPlayer
|
||||
//events ← io { eventsSince(p, version) }
|
||||
} yield Map(
|
||||
"v" -> p.eventStack.version,
|
||||
//"e" -> events map (_.toMap),
|
||||
"p" -> g.player,
|
||||
"t" -> g.turns
|
||||
)
|
||||
} except (e ⇒ io(Map("reload" -> true)))
|
||||
|
||||
def eventsSince(player: DbPlayer, version: Int): List[Event] =
|
||||
player.eventStack.eventsSince(version) | Nil
|
||||
} yield {
|
||||
p.eventStack eventsSince version map { events ⇒
|
||||
Map(
|
||||
"v" -> p.eventStack.lastVersion,
|
||||
"e" -> (events map (_.export)),
|
||||
"p" -> g.player.color.name,
|
||||
"t" -> g.turns
|
||||
)
|
||||
} getOrElse reload
|
||||
}
|
||||
} except (e ⇒ io(reload))
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@ trait SystemEnv {
|
|||
repo = gameRepo,
|
||||
ai = ai)
|
||||
|
||||
def syncer = new Syncer(
|
||||
repo = gameRepo)
|
||||
|
||||
lazy val ai: Ai = new StupidAi
|
||||
|
||||
def gameRepo = new GameRepo(
|
||||
|
|
|
@ -6,6 +6,7 @@ import Pos.{ piotr, allPiotrs }
|
|||
|
||||
sealed trait Event {
|
||||
def encode: String
|
||||
def export: Map[String, Any]
|
||||
}
|
||||
object Event {
|
||||
|
||||
|
@ -48,6 +49,8 @@ object EventDecoder {
|
|||
|
||||
case class StartEvent() extends Event {
|
||||
def encode = "s"
|
||||
def export = Map(
|
||||
"type" -> "start")
|
||||
}
|
||||
object StartEvent extends EventDecoder {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
case (orig, dests) ⇒ (orig :: dests) map (_.piotr) 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 {
|
||||
def decode(str: String) = Some(PossibleMovesEvent(
|
||||
|
@ -90,6 +103,9 @@ object PossibleMovesEvent extends EventDecoder {
|
|||
|
||||
case class EnpassantEvent(killed: Pos) extends Event {
|
||||
def encode = "E" + killed.piotr
|
||||
def export = Map(
|
||||
"type" -> "enpassant",
|
||||
"killed" -> killed.key)
|
||||
}
|
||||
object EnpassantEvent extends EventDecoder {
|
||||
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 {
|
||||
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 {
|
||||
def decode(str: String) = str.toList match {
|
||||
|
@ -119,6 +139,9 @@ object CastlingEvent extends EventDecoder {
|
|||
|
||||
case class RedirectEvent(url: String) extends Event {
|
||||
def encode = "r" + url
|
||||
def export = Map(
|
||||
"type" -> "redirect",
|
||||
"url" -> url)
|
||||
}
|
||||
object RedirectEvent extends EventDecoder {
|
||||
def decode(str: String) = Some(RedirectEvent(str))
|
||||
|
@ -126,6 +149,10 @@ object RedirectEvent extends EventDecoder {
|
|||
|
||||
case class PromotionEvent(role: PromotableRole, pos: Pos) extends Event {
|
||||
def encode = "P" + role.forsyth + pos.piotr
|
||||
def export = Map(
|
||||
"type" -> "promotion",
|
||||
"key" -> pos.key,
|
||||
"pieceClass" -> role.toString)
|
||||
}
|
||||
object PromotionEvent extends EventDecoder {
|
||||
def decode(str: String) = str.toList match {
|
||||
|
@ -139,6 +166,9 @@ object PromotionEvent extends EventDecoder {
|
|||
|
||||
case class CheckEvent(pos: Pos) extends Event {
|
||||
def encode = "C" + pos.piotr
|
||||
def export = Map(
|
||||
"type" -> "check",
|
||||
"key" -> pos.key)
|
||||
}
|
||||
object CheckEvent extends EventDecoder {
|
||||
def decode(str: String) = for {
|
||||
|
@ -149,6 +179,9 @@ object CheckEvent extends EventDecoder {
|
|||
|
||||
case class MessageEvent(author: String, message: String) extends Event {
|
||||
def encode = "M" + author + " " + message.replace("|", "(pipe)")
|
||||
def export = Map(
|
||||
"type" -> "message",
|
||||
"message" -> List(author, message))
|
||||
}
|
||||
object MessageEvent extends EventDecoder {
|
||||
def decode(str: String) = str.split(' ').toList match {
|
||||
|
@ -161,6 +194,8 @@ object MessageEvent extends EventDecoder {
|
|||
|
||||
case class EndEvent() extends Event {
|
||||
def encode = "e"
|
||||
def export = Map(
|
||||
"type" -> "end")
|
||||
}
|
||||
object EndEvent extends EventDecoder {
|
||||
def decode(str: String) = Some(EndEvent())
|
||||
|
@ -168,6 +203,8 @@ object EndEvent extends EventDecoder {
|
|||
|
||||
case class ThreefoldEvent() extends Event {
|
||||
def encode = "t"
|
||||
def export = Map(
|
||||
"type" -> "threefold_repetition")
|
||||
}
|
||||
object ThreefoldEvent extends EventDecoder {
|
||||
def decode(str: String) = Some(ThreefoldEvent())
|
||||
|
@ -175,6 +212,8 @@ object ThreefoldEvent extends EventDecoder {
|
|||
|
||||
case class ReloadTableEvent() extends Event {
|
||||
def encode = "R"
|
||||
def export = Map(
|
||||
"type" -> "reload_table")
|
||||
}
|
||||
object ReloadTableEvent extends EventDecoder {
|
||||
def decode(str: String) = Some(ReloadTableEvent())
|
||||
|
@ -182,6 +221,10 @@ object ReloadTableEvent extends EventDecoder {
|
|||
|
||||
case class MoretimeEvent(color: Color, seconds: Int) extends Event {
|
||||
def encode = "T" + color.letter + seconds
|
||||
def export = Map(
|
||||
"type" -> "moretime",
|
||||
"color" -> color.name,
|
||||
"seconds" -> seconds)
|
||||
}
|
||||
object MoretimeEvent extends EventDecoder {
|
||||
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 {
|
||||
first <- firstVersion
|
||||
first ← firstVersion
|
||||
if version >= first - 1
|
||||
last <- lastVersion
|
||||
last ← lastVersion
|
||||
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 = {
|
||||
|
||||
|
@ -45,7 +43,7 @@ case class EventStack(events: List[(Int, Event)]) {
|
|||
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 {
|
||||
found must beIO.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