From 270f44cc1f3447ffcc33fb19a47c52391c69972b Mon Sep 17 00:00:00 2001
From: Janis
Date: Fri, 5 Dec 2025 19:24:10 +0100
Subject: [PATCH] fix: BAC-29 Implement Mappers for Common Classes (#101)
Reviewed-on: https://git.janis-eccarius.de/KnockOutWhist/KnockOutWhist-Web/pulls/101
Co-authored-by: Janis
Co-committed-by: Janis
---
knockoutwhist | 2 +-
knockoutwhistfrontend | 2 +-
knockoutwhistweb/app/dto/CardDTO.scala | 26 +++++++++++++++
knockoutwhistweb/app/dto/HandDTO.scala | 18 ++++++++++
knockoutwhistweb/app/dto/PlayerDTO.scala | 20 +++++++++++
knockoutwhistweb/app/dto/PlayerQueueDTO.scala | 22 +++++++++++++
knockoutwhistweb/app/dto/RoundDTO.scala | 22 +++++++++++++
knockoutwhistweb/app/dto/TieInfoDTO.scala | 20 +++++++++++
knockoutwhistweb/app/dto/TrickDTO.scala | 20 +++++++++++
knockoutwhistweb/app/dto/UserDTO.scala | 19 +++++++++++
knockoutwhistweb/app/util/WebUIUtils.scala | 33 +++++++++++++++++--
.../app/views/ingame/tie.scala.html | 4 +--
12 files changed, 202 insertions(+), 6 deletions(-)
create mode 100644 knockoutwhistweb/app/dto/CardDTO.scala
create mode 100644 knockoutwhistweb/app/dto/HandDTO.scala
create mode 100644 knockoutwhistweb/app/dto/PlayerDTO.scala
create mode 100644 knockoutwhistweb/app/dto/PlayerQueueDTO.scala
create mode 100644 knockoutwhistweb/app/dto/RoundDTO.scala
create mode 100644 knockoutwhistweb/app/dto/TieInfoDTO.scala
create mode 100644 knockoutwhistweb/app/dto/TrickDTO.scala
create mode 100644 knockoutwhistweb/app/dto/UserDTO.scala
diff --git a/knockoutwhist b/knockoutwhist
index ef7397f..e77aef9 160000
--- a/knockoutwhist
+++ b/knockoutwhist
@@ -1 +1 @@
-Subproject commit ef7397f7f1312e0d87ab7ccaab94159d7f7e9773
+Subproject commit e77aef9e313838ca799d4210a4affb31d3948211
diff --git a/knockoutwhistfrontend b/knockoutwhistfrontend
index 575d1b5..5d080bb 160000
--- a/knockoutwhistfrontend
+++ b/knockoutwhistfrontend
@@ -1 +1 @@
-Subproject commit 575d1b5e8eb785a53efa223e9d507412178e30e0
+Subproject commit 5d080bba47778d51c8dbbb99d4d7c2b156c5316c
diff --git a/knockoutwhistweb/app/dto/CardDTO.scala b/knockoutwhistweb/app/dto/CardDTO.scala
new file mode 100644
index 0000000..827930e
--- /dev/null
+++ b/knockoutwhistweb/app/dto/CardDTO.scala
@@ -0,0 +1,26 @@
+package dto
+
+import de.knockoutwhist.cards.Card
+import play.api.libs.json.{Json, OFormat}
+import util.WebUIUtils
+
+case class CardDTO(identifier: String, path: String, idx: Int) {
+
+ def toCard: Card = {
+ WebUIUtils.stringToCard(identifier)
+ }
+
+}
+
+object CardDTO {
+
+ implicit val cardFormat: OFormat[CardDTO] = Json.format[CardDTO]
+
+ def apply(card: Card, index: Int = 0): CardDTO = {
+ CardDTO(
+ identifier = WebUIUtils.cardtoString(card),
+ path = WebUIUtils.cardToPath(card),
+ idx = index
+ )
+ }
+}
diff --git a/knockoutwhistweb/app/dto/HandDTO.scala b/knockoutwhistweb/app/dto/HandDTO.scala
new file mode 100644
index 0000000..7353fef
--- /dev/null
+++ b/knockoutwhistweb/app/dto/HandDTO.scala
@@ -0,0 +1,18 @@
+package dto
+
+import de.knockoutwhist.cards.Hand
+import play.api.libs.json.{Json, OFormat}
+
+case class HandDTO(card: List[CardDTO])
+
+object HandDTO {
+
+ implicit val handFormat: OFormat[HandDTO] = Json.format[HandDTO]
+
+ def apply(hand: Hand): HandDTO = {
+ HandDTO(
+ card = hand.cards.zipWithIndex.map { case (card, idx) => CardDTO(card, idx) }
+ )
+ }
+
+}
diff --git a/knockoutwhistweb/app/dto/PlayerDTO.scala b/knockoutwhistweb/app/dto/PlayerDTO.scala
new file mode 100644
index 0000000..c3b9307
--- /dev/null
+++ b/knockoutwhistweb/app/dto/PlayerDTO.scala
@@ -0,0 +1,20 @@
+package dto
+
+import de.knockoutwhist.player.AbstractPlayer
+import play.api.libs.json.{Json, OFormat}
+
+case class PlayerDTO(id: String, name: String, dogLife: Boolean)
+
+object PlayerDTO {
+
+ implicit val playerFormat: OFormat[PlayerDTO] = Json.format[PlayerDTO]
+
+ def apply(player: AbstractPlayer): PlayerDTO = {
+ PlayerDTO(
+ id = player.id.toString,
+ name = player.name,
+ dogLife = player.isInDogLife
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/knockoutwhistweb/app/dto/PlayerQueueDTO.scala b/knockoutwhistweb/app/dto/PlayerQueueDTO.scala
new file mode 100644
index 0000000..43a815b
--- /dev/null
+++ b/knockoutwhistweb/app/dto/PlayerQueueDTO.scala
@@ -0,0 +1,22 @@
+package dto
+
+import de.knockoutwhist.control.GameLogic
+import play.api.libs.json.{Json, OFormat}
+
+case class PlayerQueueDTO(currentPlayer: Option[PlayerDTO], queue: Seq[PlayerDTO])
+
+object PlayerQueueDTO {
+
+ implicit val queueFormat: OFormat[PlayerQueueDTO] = Json.format[PlayerQueueDTO]
+
+ def apply(logic: GameLogic): PlayerQueueDTO = {
+ val currentPlayerDTO = logic.getCurrentPlayer.map(PlayerDTO(_))
+ val queueDTO = logic.getPlayerQueue.map(_.duplicate().flatMap(player => Some(PlayerDTO(player))).toSeq)
+ if (queueDTO.isEmpty) {
+ PlayerQueueDTO(currentPlayerDTO, Seq.empty)
+ } else {
+ PlayerQueueDTO(currentPlayerDTO, queueDTO.get)
+ }
+ }
+
+}
diff --git a/knockoutwhistweb/app/dto/RoundDTO.scala b/knockoutwhistweb/app/dto/RoundDTO.scala
new file mode 100644
index 0000000..ab5d91b
--- /dev/null
+++ b/knockoutwhistweb/app/dto/RoundDTO.scala
@@ -0,0 +1,22 @@
+package dto
+
+import de.knockoutwhist.cards.Card
+import de.knockoutwhist.cards.CardValue.Ace
+import play.api.libs.json.{Json, OFormat}
+
+case class RoundDTO(trumpSuit: CardDTO, firstRound: Boolean, tricklist: List[TrickDTO], winner: Option[PlayerDTO])
+
+object RoundDTO {
+
+ implicit val roundFormat: OFormat[RoundDTO] = Json.format[RoundDTO]
+
+ def apply(round: de.knockoutwhist.rounds.Round): RoundDTO = {
+ RoundDTO(
+ trumpSuit = CardDTO(Card(Ace, round.trumpSuit)),
+ firstRound = round.firstRound,
+ tricklist = round.tricklist.map(trick => TrickDTO(trick)),
+ winner = round.winner.map(player => PlayerDTO(player))
+ )
+ }
+
+}
diff --git a/knockoutwhistweb/app/dto/TieInfoDTO.scala b/knockoutwhistweb/app/dto/TieInfoDTO.scala
new file mode 100644
index 0000000..ce895fb
--- /dev/null
+++ b/knockoutwhistweb/app/dto/TieInfoDTO.scala
@@ -0,0 +1,20 @@
+package dto
+
+import de.knockoutwhist.control.sublogic.PlayerTieLogic
+import play.api.libs.json.{Json, OFormat}
+
+case class TieInfoDTO(currentPlayer: Option[PlayerDTO], tiedPlayers: Seq[PlayerDTO], highestAmount: Int)
+
+object TieInfoDTO {
+
+ implicit val tieInfoFormat: OFormat[TieInfoDTO] = Json.format[TieInfoDTO]
+
+ def apply(tieInput: PlayerTieLogic): Unit = {
+ TieInfoDTO(
+ currentPlayer = tieInput.currentTiePlayer().map(PlayerDTO.apply),
+ tiedPlayers = tieInput.getTiedPlayers.map(PlayerDTO.apply),
+ highestAmount = tieInput.highestAllowedNumber()
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/knockoutwhistweb/app/dto/TrickDTO.scala b/knockoutwhistweb/app/dto/TrickDTO.scala
new file mode 100644
index 0000000..f63ac64
--- /dev/null
+++ b/knockoutwhistweb/app/dto/TrickDTO.scala
@@ -0,0 +1,20 @@
+package dto
+
+import de.knockoutwhist.rounds.Trick
+import play.api.libs.json.{Json, OFormat}
+
+case class TrickDTO(cards: Map[PlayerDTO, CardDTO], firstCard: Option[CardDTO], winner: Option[PlayerDTO])
+
+object TrickDTO {
+
+ implicit val trickFormat: OFormat[TrickDTO] = Json.format[TrickDTO]
+
+ def apply(trick: Trick): TrickDTO = {
+ TrickDTO(
+ cards = trick.cards.map { case (card, player) => PlayerDTO(player) -> CardDTO(card) },
+ firstCard = trick.firstCard.map(card => CardDTO(card)),
+ winner = trick.winner.map(player => PlayerDTO(player))
+ )
+ }
+
+}
diff --git a/knockoutwhistweb/app/dto/UserDTO.scala b/knockoutwhistweb/app/dto/UserDTO.scala
new file mode 100644
index 0000000..5e18fd1
--- /dev/null
+++ b/knockoutwhistweb/app/dto/UserDTO.scala
@@ -0,0 +1,19 @@
+package dto
+
+import model.users.User
+import play.api.libs.json.{Json, OFormat}
+
+case class UserDTO(id: String, username: String)
+
+object UserDTO {
+
+ implicit val userFormat: OFormat[UserDTO] = Json.format[UserDTO]
+
+ def apply(user: User): UserDTO = {
+ UserDTO(
+ id = user.id.toString,
+ username = user.name
+ )
+ }
+
+}
\ No newline at end of file
diff --git a/knockoutwhistweb/app/util/WebUIUtils.scala b/knockoutwhistweb/app/util/WebUIUtils.scala
index 03f33b8..f33be6b 100644
--- a/knockoutwhistweb/app/util/WebUIUtils.scala
+++ b/knockoutwhistweb/app/util/WebUIUtils.scala
@@ -9,10 +9,14 @@ import scalafx.scene.image.Image
object WebUIUtils {
def cardtoImage(card: Card): Html = {
- views.html.render.card.apply(f"images/cards/${cardtoString(card)}.png")(card.toString)
+ views.html.render.card.apply(cardToPath(card))(card.toString)
+ }
+
+ def cardToPath(card: Card): String = {
+ f"images/cards/${cardtoString(card)}.png"
}
- def cardtoString(card: Card) = {
+ def cardtoString(card: Card): String = {
val s = card.suit match {
case Spades => "S"
case Hearts => "H"
@@ -36,6 +40,31 @@ object WebUIUtils {
}
f"$cv$s"
}
+
+ def stringToCard(cardStr: String): Card = {
+ val cv = cardStr.charAt(0) match {
+ case 'A' => Ace
+ case 'K' => King
+ case 'Q' => Queen
+ case 'J' => Jack
+ case 'T' => Ten
+ case '9' => Nine
+ case '8' => Eight
+ case '7' => Seven
+ case '6' => Six
+ case '5' => Five
+ case '4' => Four
+ case '3' => Three
+ case '2' => Two
+ }
+ val s = cardStr.charAt(1) match {
+ case 'S' => Spades
+ case 'H' => Hearts
+ case 'C' => Clubs
+ case 'D' => Diamonds
+ }
+ Card(cv, s)
+ }
/**
* Map a Hand to a JsArray of cards
diff --git a/knockoutwhistweb/app/views/ingame/tie.scala.html b/knockoutwhistweb/app/views/ingame/tie.scala.html
index 94e0978..b224e1d 100644
--- a/knockoutwhistweb/app/views/ingame/tie.scala.html
+++ b/knockoutwhistweb/app/views/ingame/tie.scala.html
@@ -20,7 +20,7 @@
- @if(player.equals(gamelobby.logic.playerTieLogic.currentTiePlayer())) {
+ @if(gamelobby.logic.playerTieLogic.currentTiePlayer().contains(player)) {
@defining(gamelobby.logic.playerTieLogic.highestAllowedNumber()) { maxNum =>
Pick a number between 1 and @{
@@ -71,7 +71,7 @@
}
} else {
- @gamelobby.logic.playerTieLogic.currentTiePlayer()
+ @gamelobby.logic.playerTieLogic.currentTiePlayer().get
is currently picking a number for the cut.