diff --git a/modules/simul/src/main/Env.scala b/modules/simul/src/main/Env.scala new file mode 100644 index 000000000000..6fb4b75cfe23 --- /dev/null +++ b/modules/simul/src/main/Env.scala @@ -0,0 +1,50 @@ +package lila.simul + +import akka.actor._ +import akka.pattern.ask +import com.typesafe.config.Config + +import lila.common.PimpedConfig._ +import lila.hub.actorApi.map.Ask +import lila.hub.{ ActorMap, Sequencer } +import lila.socket.actorApi.GetVersion +import lila.socket.History +import makeTimeout.short + +final class Env( + config: Config, + system: ActorSystem, + db: lila.db.Env, + mongoCache: lila.memo.MongoCache.Builder, + flood: lila.security.Flood, + hub: lila.hub.Env, + roundMap: ActorRef, + lightUser: String => Option[lila.common.LightUser], + isOnline: String => Boolean) { + + private val settings = new { + val CollectionSimul = config getString "collection.simul" + } + import settings._ + + lazy val api = new SimulApi( + simulColl = simulColl) + + private[simul] val simulColl = db(CollectionSimul) +} + +object Env { + + private def hub = lila.hub.Env.current + + lazy val current = "[boot] simul" describes new Env( + config = lila.common.PlayApp loadConfig "simul", + system = lila.common.PlayApp.system, + db = lila.db.Env.current, + mongoCache = lila.memo.Env.current.mongoCache, + flood = lila.security.Env.current.flood, + hub = lila.hub.Env.current, + roundMap = lila.round.Env.current.roundMap, + lightUser = lila.user.Env.current.lightUser, + isOnline = lila.user.Env.current.isOnline) +} diff --git a/modules/simul/src/main/Simul.scala b/modules/simul/src/main/Simul.scala new file mode 100644 index 000000000000..c728c4ca37c3 --- /dev/null +++ b/modules/simul/src/main/Simul.scala @@ -0,0 +1,40 @@ +package lila.simul + +import chess.variant.Variant +import org.joda.time.{ DateTime, Duration } +import ornicar.scalalib.Random + +case class Simul( + _id: Simul.ID, + name: String, + clock: SimulClock, + nbPlayers: Int, + players: List[SimulPlayer], + pairings: List[SimulPairing], + variant: Variant, + createdAt: DateTime, + createdBy: String) { + + def id = _id +} + +object Simul { + + type ID = String + + def make( + name: String, + createdBy: String, + clock: SimulClock, + nbPlayers: Int, + variant: chess.variant.Variant): Simul = Simul( + _id = Random nextStringUppercase 8, + name = name, + clock = clock, + createdBy = createdBy, + createdAt = DateTime.now, + variant = variant, + nbPlayers = nbPlayers, + players = Nil, + pairings = Nil) +} diff --git a/modules/simul/src/main/SimulApi.scala b/modules/simul/src/main/SimulApi.scala new file mode 100644 index 000000000000..462bda31e7ac --- /dev/null +++ b/modules/simul/src/main/SimulApi.scala @@ -0,0 +1,32 @@ +package lila.simul + +import org.joda.time.DateTime +import reactivemongo.bson._ +import reactivemongo.core.commands._ +import scala.concurrent.duration._ + +import chess.variant.Variant +import chess.Status +import lila.db.Types.Coll + +private[simul] final class SimulApi( + simulColl: Coll) { + + import lila.db.BSON.BSONJodaDateTimeHandler + import reactivemongo.bson.Macros + private implicit val StatusBSONHandler = new BSONHandler[BSONInteger, Status] { + def read(bsonInt: BSONInteger): Status = Status(bsonInt.value) err s"No such status: ${bsonInt.value}" + def write(x: Status) = BSONInteger(x.id) + } + private implicit val VariantBSONHandler = new BSONHandler[BSONInteger, Variant] { + def read(bsonInt: BSONInteger): Variant = Variant(bsonInt.value) err s"No such variant: ${bsonInt.value}" + def write(x: Variant) = BSONInteger(x.id) + } + private implicit val ClockBSONHandler = Macros.handler[SimulClock] + private implicit val PlayerBSONHandler = Macros.handler[SimulPlayer] + private implicit val PairingBSONHandler = Macros.handler[SimulPairing] + private implicit val SimulBSONHandler = Macros.handler[Simul] + + def find(id: Simul.ID): Fu[Option[Simul]] = + simulColl.find(BSONDocument("_id" -> id)).one[Simul] +} diff --git a/modules/simul/src/main/SimulClock.scala b/modules/simul/src/main/SimulClock.scala new file mode 100644 index 000000000000..ed4a6ff8af8a --- /dev/null +++ b/modules/simul/src/main/SimulClock.scala @@ -0,0 +1,11 @@ +package lila.simul + +// All durations are expressed in seconds +case class SimulClock(limit: Int, increment: Int) { + + def limitInMinutes = limit / 60 + + def show = s"${limitInMinutes}+${increment}" + + def chessClock = chess.Clock(limit, increment) +} diff --git a/modules/simul/src/main/SimulPairing.scala b/modules/simul/src/main/SimulPairing.scala new file mode 100644 index 000000000000..be5ac99c7017 --- /dev/null +++ b/modules/simul/src/main/SimulPairing.scala @@ -0,0 +1,29 @@ +package lila.simul + +import lila.game.{ PovRef, IdGenerator } + +case class SimulPairing( + gameId: String, + status: chess.Status, + user: String, + wins: Option[Boolean], + turns: Option[Int]) { + + def finished = status >= chess.Status.Mate + def playing = !finished + + def finish(s: chess.Status, w: Option[String], t: Int) = copy( + status = s, + wins = w map (user==), + turns = t.some) +} + +private[simul] object SimulPairing { + + def apply(user: String): SimulPairing = new SimulPairing( + gameId = IdGenerator.game, + status = chess.Status.Created, + user = user, + wins = none, + turns = none) +} diff --git a/modules/simul/src/main/SimulPlayer.scala b/modules/simul/src/main/SimulPlayer.scala new file mode 100644 index 000000000000..91ca29077848 --- /dev/null +++ b/modules/simul/src/main/SimulPlayer.scala @@ -0,0 +1,21 @@ +package lila.simul + +import lila.rating.Perf +import lila.user.{ User, Perfs} +import lila.game.PerfPicker + +private[simul] case class SimulPlayer( + id: String, + rating: Int) { + + def is(userId: String): Boolean = id == userId + def is(user: User): Boolean = is(user.id) + def is(other: SimulPlayer): Boolean = is(other.id) +} + +private[simul] object SimulPlayer { + + private[simul] def make(user: User, perfLens: Perfs => Perf): SimulPlayer = new SimulPlayer( + id = user.id, + rating = perfLens(user.perfs).intRating) +} diff --git a/modules/simul/src/main/package.scala b/modules/simul/src/main/package.scala new file mode 100644 index 000000000000..b75be22235fd --- /dev/null +++ b/modules/simul/src/main/package.scala @@ -0,0 +1,5 @@ +package lila + +import lila.socket.WithSocket + +package object simul extends PackageObject with WithPlay with WithSocket diff --git a/project/Build.scala b/project/Build.scala index b5fc09fd6c9d..cc4ed9aca957 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -39,7 +39,7 @@ object ApplicationBuild extends Build { message, notification, i18n, game, bookmark, search, gameSearch, timeline, forum, forumSearch, team, teamSearch, ai, analyse, mod, monitor, site, round, lobby, setup, - importer, tournament, relation, report, pref, // simulation, + importer, tournament, simul, relation, report, pref, // simulation, evaluation, chat, puzzle, tv, coordinate, blog, donation, qa, swisssystem, history, worldMap, opening, video) @@ -62,7 +62,7 @@ object ApplicationBuild extends Build { common, memo, hub, db, user)).settings( libraryDependencies ++= provided(play.api, RM, PRM) ) - + lazy val video = project("video", Seq( common, memo, hub, db, user)).settings( libraryDependencies ++= provided(play.api, RM, PRM) @@ -186,6 +186,11 @@ object ApplicationBuild extends Build { libraryDependencies ++= provided(play.api, RM, PRM) ) + lazy val simul = project("simul", Seq( + common, hub, socket, chess, game, round, chat, memo)).settings( + libraryDependencies ++= provided(play.api, RM, PRM) + ) + lazy val ai = project("ai", Seq(common, hub, chess, game, analyse, rating)).settings( libraryDependencies ++= provided(play.api, RM, PRM) )