Event export and basic sync: can play with the AI

This commit is contained in:
Thibault Duplessis 2012-03-17 10:14:12 +01:00
parent ef73f21eed
commit 8a3922cb50
7 changed files with 73 additions and 22 deletions

View file

@ -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

View file

@ -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"

View file

@ -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))
}

View file

@ -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(

View file

@ -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 {

View file

@ -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))
}
}

View file

@ -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)
}
}
}
}