Taboo.scala 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. package models
  2. import akka.actor._
  3. import scala.concurrent.duration._
  4. import play.api.libs.concurrent._
  5. import play.api.Play.current
  6. import play.api.libs.concurrent.Execution.Implicits._
  7. case class Card(word: String, taboo: Set[String]) {
  8. def isTaboo(text: String) = {
  9. val lower = text.toLowerCase
  10. def contains(word: String) = {
  11. lower.indexOf(word.toLowerCase) >= 0
  12. }
  13. // check if text contains word or anything in taboo
  14. (taboo + word).map(contains).foldLeft(false)(_ || _)
  15. }
  16. def isCorrect(text: String) = {
  17. text.toLowerCase.indexOf(word.toLowerCase) >= 0
  18. }
  19. }
  20. class Team {
  21. var members = List.empty[String]
  22. var player = ""
  23. var guessers = Set.empty[String]
  24. def hasPlayer(user: String) = members.indexOf(user) >= 0
  25. def nextPlayer() = {
  26. val index = (members.indexOf(player) + 1) % members.size
  27. player = members(index)
  28. guessers = members.filterNot(_ == player).toSet
  29. player
  30. }
  31. def join(user: String) = {
  32. if(!hasPlayer(user)) {
  33. members = members :+ user
  34. }
  35. }
  36. def leave(user: String) = {
  37. members = members.filterNot(_ == user)
  38. }
  39. def isEmpty = members.isEmpty
  40. def size = members.size
  41. }
  42. case class Round(team: Team, monitors: Set[String])
  43. case class Information(text: String)
  44. case class Guess(username: String, text: String)
  45. case object Pass
  46. case class Taboo(username: String)
  47. case class Correct(username: String, card: Card)
  48. case class Invalid(card: Card)
  49. case class Passed(card: Card)
  50. case class Tabooed(username: String, card: Card)
  51. case object NextCard
  52. case object PrepRound
  53. case object StartRound
  54. case object End
  55. case class Points(points: Int)
  56. class TabooGame(val chatActor: ActorRef) extends Actor {
  57. var ready = false
  58. var round: Option[Round] = None
  59. var roundActor: ActorRef = null
  60. val teamA: Team = new Team
  61. val teamB: Team = new Team
  62. var currentTeam: Team = teamB
  63. var opposingTeam: Team = teamA
  64. def receive = {
  65. case Join(username) =>
  66. if(teamA.size < 2 || teamA.size <= teamB.size) {
  67. teamA.join(username)
  68. }
  69. else {
  70. teamB.join(username)
  71. }
  72. if(round.isEmpty) {
  73. self ! PrepRound
  74. }
  75. case Quit(username) =>
  76. teamA.leave(username)
  77. teamB.leave(username)
  78. if(!round.isEmpty && (teamA.size < 2 || (currentTeam == teamB && teamB.size < 2))) {
  79. roundActor ! End
  80. }
  81. case Talk(username, text) => round match {
  82. case Some(round) =>
  83. if(username == round.team.player) {
  84. if(text == "/pass") {
  85. roundActor ! Pass
  86. }
  87. else {
  88. roundActor ! Information(text)
  89. }
  90. }
  91. else if(round.team.guessers(username)) {
  92. roundActor ! Guess(username, text)
  93. }
  94. else if(round.monitors(username) && text == "/taboo") {
  95. roundActor ! Taboo(username)
  96. }
  97. case None =>
  98. if(username == currentTeam.player && text == "/start") {
  99. self ! StartRound
  100. }
  101. }
  102. case Correct(username, card) =>
  103. nextCard(username+" got it right!", card)
  104. case Invalid(card) =>
  105. nextCard("Uh-uh! "+player+" said a taboo word. Sorry.", card)
  106. case Passed(card) =>
  107. nextCard(player+" has passed.", card)
  108. case Tabooed(username, card) =>
  109. nextCard("Oh no! "+player+" apparently said a taboo word. :(", card)
  110. case Points(points) =>
  111. chatActor ! Talk("*GM", "The round is over. The team got "+points)
  112. round = None
  113. ready = false
  114. self ! PrepRound
  115. case NextCard =>
  116. val card = randomCard()
  117. roundActor ! card
  118. (round.get.monitors + player).foreach { user =>
  119. chatActor ! Tell(
  120. "*GM",
  121. "The word is "+card.word+". The taboo words are: "+card.taboo.reduceLeft(_+" "+_),
  122. user)
  123. }
  124. case PrepRound =>
  125. if(!ready && teamA.size >= 2) {
  126. ready = true
  127. if(teamB.size < 2) {
  128. currentTeam = teamA
  129. opposingTeam = teamB
  130. }
  131. else {
  132. val temp = currentTeam
  133. currentTeam = opposingTeam
  134. opposingTeam = temp
  135. }
  136. currentTeam.nextPlayer()
  137. chatActor ! Talk("*GM", "Next round, the player will be "+currentTeam.player)
  138. chatActor ! Tell("*GM", "Type /start to start the round", currentTeam.player)
  139. }
  140. case StartRound =>
  141. round = Some(Round(currentTeam, opposingTeam.members.toSet))
  142. roundActor = context.actorOf(Props[TabooRound])
  143. Akka.system.scheduler.scheduleOnce(1 minute, roundActor, End)
  144. self ! NextCard
  145. }
  146. def player = round.get.team.player
  147. def randomCard() = Card("test", Set("a", "b", "c", "d", "e"))
  148. def nextCard(message: String, oldCard: Card) = {
  149. chatActor ! Talk("*GM", message+" The word was "+oldCard.word+".")
  150. self ! NextCard
  151. }
  152. self ! PrepRound
  153. }
  154. class TabooRound extends Actor {
  155. var card: Option[Card] = None
  156. var points = 0
  157. def receive = {
  158. case newCard: Card =>
  159. card = Some(newCard)
  160. case Guess(username, text) => card.map { card =>
  161. if(card.isCorrect(text)) {
  162. points += 1
  163. sender ! Correct(username, card)
  164. this.card = None
  165. }
  166. }
  167. case Information(text) => card.map { card =>
  168. if(card.isTaboo(text)) {
  169. points -= 1
  170. sender ! Invalid(card)
  171. this.card = None
  172. }
  173. }
  174. case Pass => card.map { card =>
  175. points -= 1
  176. sender ! Passed(card)
  177. this.card = None
  178. }
  179. case Taboo(username) => card.map { card =>
  180. points -= 1
  181. sender ! Tabooed(username, card)
  182. this.card = None
  183. }
  184. case End =>
  185. sender ! Points(points)
  186. context.stop(self)
  187. }
  188. }