Taboo.scala 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. package models
  2. import akka.actor._
  3. import scala.concurrent.duration._
  4. import play.api.libs.concurrent._
  5. import play.api.libs.json._
  6. import play.api.Play.current
  7. import play.api.libs.concurrent.Execution.Implicits._
  8. object Card {
  9. implicit val writes = new Writes[Card] {
  10. def writes(o: Card) = Json.obj(
  11. "word" -> o.word,
  12. "taboo" -> o.taboo
  13. )
  14. }
  15. }
  16. case class Card(word: String, taboo: Set[String]) {
  17. def isTaboo(text: String) = {
  18. val lower = text.toLowerCase
  19. def contains(word: String) = {
  20. lower.indexOf(word.toLowerCase) >= 0
  21. }
  22. // check if text contains word or anything in taboo
  23. (taboo + word).map(contains).foldLeft(false)(_ || _)
  24. }
  25. def isCorrect(text: String) = {
  26. text.toLowerCase.indexOf(word.toLowerCase) >= 0
  27. }
  28. }
  29. object Team {
  30. implicit val writes = new Writes[Team] {
  31. def writes(o: Team) = Json.obj(
  32. "members" -> o.members,
  33. "player" -> o.player,
  34. "guessers" -> o.guessers
  35. )
  36. }
  37. }
  38. class Team {
  39. var members = List.empty[String]
  40. var player = ""
  41. var guessers = Set.empty[String]
  42. def hasPlayer(user: String) = members.indexOf(user) >= 0
  43. def nextPlayer() = {
  44. val index = (members.indexOf(player) + 1) % members.size
  45. player = members(index)
  46. guessers = members.filterNot(_ == player).toSet
  47. player
  48. }
  49. def join(user: String) = {
  50. if(!hasPlayer(user)) {
  51. members = members :+ user
  52. }
  53. }
  54. def leave(user: String) = {
  55. members = members.filterNot(_ == user)
  56. }
  57. def isEmpty = members.isEmpty
  58. def size = members.size
  59. }
  60. object Round {
  61. implicit val writes = new Writes[Round] {
  62. def writes(o: Round) = Json.obj(
  63. "team" -> o.team,
  64. "monitors" -> o.monitors
  65. )
  66. }
  67. }
  68. case class Round(team: Team, monitors: Set[String])
  69. case class Information(text: String)
  70. case class Guess(username: String, text: String)
  71. case object Pass
  72. case class Taboo(username: String)
  73. case object End
  74. case class Score(kind: String, points: Int, card: Card, username: String = "")
  75. case object NextCard
  76. case object PrepRound
  77. case object StartRound
  78. case class EndRound(points: Int, card: Option[Card])
  79. class TabooGame(val chatActor: ActorRef) extends Actor {
  80. var ready = false
  81. var round: Option[Round] = None
  82. var roundActor: ActorRef = null
  83. val teamA: Team = new Team
  84. val teamB: Team = new Team
  85. var currentTeam: Team = teamB
  86. var opposingTeam: Team = teamA
  87. def receive = {
  88. case Join(username) =>
  89. if(teamA.size < 2 || teamA.size <= teamB.size) {
  90. teamA.join(username)
  91. }
  92. else {
  93. teamB.join(username)
  94. }
  95. announceStatus("join", username)
  96. if(round.isEmpty) {
  97. self ! PrepRound
  98. }
  99. case Quit(username) =>
  100. teamA.leave(username)
  101. teamB.leave(username)
  102. announceStatus("quit", username)
  103. if(teamA.size < 2 || currentTeam == teamB && teamB.size < 2) {
  104. if(ready) {
  105. ready = false
  106. }
  107. if(!round.isEmpty) {
  108. roundActor ! End
  109. }
  110. }
  111. case Talk(username, "/status") => announceStatus()
  112. case Talk(username, text) => round match {
  113. case Some(round) =>
  114. if(username == round.team.player) {
  115. if(text == "/pass") {
  116. roundActor ! Pass
  117. }
  118. else {
  119. roundActor ! Information(text)
  120. }
  121. }
  122. else if(round.team.guessers(username)) {
  123. roundActor ! Guess(username, text)
  124. }
  125. else if(round.monitors(username) && text == "/taboo") {
  126. roundActor ! Taboo(username)
  127. }
  128. case None =>
  129. if(username == currentTeam.player && text == "/start") {
  130. self ! StartRound
  131. }
  132. }
  133. case Score(kind, points, card, user) =>
  134. chatActor ! Announce(Json.obj(
  135. "kind" -> "point",
  136. "action" -> kind,
  137. "card" -> card,
  138. "user" -> user
  139. ))
  140. self ! NextCard
  141. case NextCard =>
  142. val card = randomCard()
  143. roundActor ! card
  144. val message = Json.obj(
  145. "kind" -> "card",
  146. "card" -> card
  147. )
  148. (round.get.monitors + player).foreach { user =>
  149. chatActor ! Tell(user, message)
  150. }
  151. case PrepRound =>
  152. if(!ready && teamA.size >= 2) {
  153. ready = true
  154. if(teamB.size < 2) {
  155. currentTeam = teamA
  156. opposingTeam = teamB
  157. }
  158. else {
  159. val temp = currentTeam
  160. currentTeam = opposingTeam
  161. opposingTeam = temp
  162. }
  163. currentTeam.nextPlayer()
  164. chatActor ! Announce(Json.obj(
  165. "kind" -> "roundReady",
  166. "player" -> currentTeam.player
  167. ))
  168. }
  169. case StartRound =>
  170. round = Some(Round(currentTeam, opposingTeam.members.toSet))
  171. roundActor = context.actorOf(Props[TabooRound])
  172. Akka.system.scheduler.scheduleOnce(1 minute, roundActor, End)
  173. chatActor ! Announce(Json.obj(
  174. "kind" -> "roundStart"
  175. ))
  176. self ! NextCard
  177. case EndRound(points, card) =>
  178. chatActor ! Announce(Json.obj(
  179. "kind" -> "roundEnd",
  180. "points" -> points,
  181. "card" -> card
  182. ))
  183. round = None
  184. ready = false
  185. self ! PrepRound
  186. }
  187. def player = round.get.team.player
  188. def randomCard() = Card("test", Set("a", "b", "c", "d", "e"))
  189. def announceStatus(kind: String = "status", user: String = "*GM") {
  190. chatActor ! Announce(Json.obj(
  191. "kind" -> kind,
  192. "user" -> user,
  193. "teamA" -> teamA,
  194. "teamB" -> teamB
  195. ))
  196. }
  197. self ! PrepRound
  198. }
  199. class TabooRound extends Actor {
  200. var card: Option[Card] = None
  201. var points = 0
  202. def receive = {
  203. case newCard: Card =>
  204. card = Some(newCard)
  205. case Guess(username, text) => card.map { card =>
  206. if(card.isCorrect(text)) {
  207. points += 1
  208. sender ! Score("correct", points, card, username)
  209. this.card = None
  210. }
  211. }
  212. case Information(text) => card.map { card =>
  213. if(card.isTaboo(text)) {
  214. points -= 1
  215. sender ! Score("invalid", points, card)
  216. this.card = None
  217. }
  218. }
  219. case Pass => card.map { card =>
  220. points -= 1
  221. sender ! Score("pass", points, card)
  222. this.card = None
  223. }
  224. case Taboo(username) => card.map { card =>
  225. points -= 1
  226. sender ! Score("taboo", points, card)
  227. this.card = None
  228. }
  229. case End =>
  230. sender ! EndRound(points, card)
  231. context.stop(self)
  232. }
  233. }