Files
CoqDecks/server/app/models/massivedecks/Game.scala
T

90 lines
3.5 KiB
Scala

package models.massivedecks
import play.api.libs.json._
import models.massivedecks.Player.Formatters._
import models.massivedecks.Lobby.Formatters._
object Game {
sealed trait Card
case class Call(parts: List[String]) extends Card {
require(parts.length > 1, "A call must have at least one slot.")
def slots: Int = parts.length - 1
def withResponses(responses: List[Response]): String =
intersperse(parts, responses.map(response => response.text)).mkString("")
}
case class Response(text: String) extends Card
case class DeckInfo(id: String, name: String, calls: Int, responses: Int)
case class Config(decks: List[DeckInfo])
case class Round(czar: Player.Id, call: Call, responses: Responses) {
require(responses.revealed.isEmpty || responses.revealed.get.cards.forall(playerResponses => playerResponses.length == call.slots),
"Plays for a call must have a number of responses equal to the number of spots in the call.")
def inPickingState = responses.revealed.isEmpty
def inJudgingState = responses.revealed.isDefined && responses.revealed.get.playedByAndWinner.isEmpty
def inFinishedState = responses.revealed.isDefined && responses.revealed.get.playedByAndWinner.isDefined
def byState[T](picking: (Player.Id, Call, Int) => T,
judging: (Player.Id, Call, List[List[Response]]) => T,
finished: (Player.Id, Call, List[List[Response]], PlayedByAndWinner) => T): T = {
if (responses.revealed.isEmpty) {
picking(czar, call, responses.hidden.get)
} else {
if (responses.revealed.get.playedByAndWinner.isEmpty) {
judging(czar, call, responses.revealed.get.cards)
} else {
finished(czar, call, responses.revealed.get.cards, responses.revealed.get.playedByAndWinner.get)
}
}
}
}
case class Responses(hidden: Option[Int], revealed: Option[Revealed]) {
require(hidden.isDefined ^ revealed.isDefined, "Only one of the count or cards should be provided.")
}
object Responses {
def hidden(count: Int): Responses = Responses(Some(count), None)
def revealed(revealed: Revealed): Responses = Responses(None, Some(revealed))
}
case class Revealed(cards: List[List[Response]], playedByAndWinner: Option[PlayedByAndWinner])
case class PlayedByAndWinner(playedBy: List[Player.Id], winner: Player.Id)
case class Hand(hand: List[Response])
object Hand {
val size: Int = 7
}
object Formatters {
implicit val callFormat: Format[Call] = Format(
Reads(response => response.validate[List[String]].map(Call.apply)),
Writes(response => JsArray(response.parts.map(JsString)))
)
implicit val responseFormat: Format[Response] = Format(
Reads(response => response.validate[String].map(Response)),
Writes(response => JsString(response.text))
)
implicit val playedByAndWinnerFormat: Format[PlayedByAndWinner] = Json.format[PlayedByAndWinner]
implicit val revealedFormat: Format[Revealed] = Json.format[Revealed]
implicit val responsesFormat: Format[Responses] = Json.format[Responses]
implicit val roundFormat: Format[Round] = Json.format[Round]
implicit val deckInfoFormat: Format[DeckInfo] = Json.format[DeckInfo]
implicit val configFormat: Format[Config] = Json.format[Config]
implicit val handFormat: Format[Hand] = Json.format[Hand]
}
private def intersperse[A](a : List[A], b : List[A]): List[A] = a match {
case first :: rest => first :: intersperse(b, rest)
case _ => b
}
}