planning-poker-gwargh/common/src/main/scala/industries/sunshine/planningpoker/Models.scala

109 lines
3.2 KiB
Scala

package industries.sunshine.planningpoker.common
import java.util.UUID
import io.circe._
import scala.util.Random
object Models {
/** view of the single planning poker round
* @param players
* \- people who are currently playing
* @param allowedCards-
* the cards values that can be used by players
* @param round
* \- state of the selected cards of the players
* @param canCloseRound
* \- whether current player has access to button to finish the round
*/
final case class RoomStateView(
roomName: String,
players: List[Player],
me: PlayerID,
allowedCards: List[String],
round: RoundStateView,
canCloseRound: Boolean = false
) derives Codec.AsObject
object RoomStateView {
val empty = RoomStateView(
"",
List.empty,
PlayerID(0),
List.empty,
RoundStateView.Voting(None, List.empty),
false
)
}
enum RoundStateView derives Codec.AsObject:
/** view state for round before votes are open player can know their vote and who of the other
* players have voted
*/
case Voting(
myCard: Option[String],
alreadyVoted: List[PlayerID]
)
/** view state for round after opening the votes
*/
case Viewing(
votes: List[(PlayerID, String)]
)
final case class PlayerID(id: Long) derives Codec.AsObject
final case class Player(name: String, id: PlayerID) derives Codec.AsObject
object Player {
def create(name: String) = Player(name, PlayerID(Random.nextLong))
}
final case class RoomID(name: String) derives Codec.AsObject
final case class Room(
id: RoomID,
players: List[Player],
owner: String, // TODO switch to nickname
password: String,
allowedCards: List[String],
round: RoundState,
playersPasswords: Map[String, String] = Map.empty, // nickname into password
) {
def getViewFor(playerId: PlayerID): RoomStateView = {
players
.find(_.id == playerId)
.fold(ifEmpty = RoomStateView.empty)((me: Player) =>
RoomStateView(
id.name,
players,
me.id,
allowedCards,
round.toViewFor(playerId),
me.name == owner
)
)
}
}
// no need to send to the front end, no deed to derive codec, cool
sealed trait RoundState {
def toViewFor(player: PlayerID): RoundStateView
def removePlayer(id: PlayerID): RoundState
}
object RoundState {
final case class Voting(votes: Map[PlayerID, String]) extends RoundState {
override def toViewFor(playerId: PlayerID): RoundStateView.Voting = RoundStateView.Voting(
myCard = votes.get(playerId),
alreadyVoted = votes.filterKeys(id => id != playerId).keys.toList
)
override def removePlayer(id: PlayerID): RoundState.Voting =
RoundState.Voting(votes.filterKeys(_ != id).toMap)
}
final case class Viewing(votes: Map[PlayerID, String]) extends RoundState {
override def toViewFor(player: PlayerID): RoundStateView.Viewing =
RoundStateView.Viewing(votes.toList)
override def removePlayer(id: PlayerID): RoundState.Viewing =
RoundState.Viewing(votes.filterKeys(_ != id).toMap)
}
}
}