From d946da73f0f503db4b2c96c1370a7e4b67a7b3e7 Mon Sep 17 00:00:00 2001 From: Vincent FROCHOT Date: Tue, 25 Feb 2025 11:29:14 +0100 Subject: [PATCH 01/10] feat: PLA-1183 playerInfo multiPt game score When loading results for a player during a swiss tournament, use the finalMultiPointScore for all finished games --- modules/game/src/main/Game.scala | 4 +- modules/swiss/src/main/SwissJson.scala | 53 +++++++++++++------------- ui/swiss/src/view/playerInfo.ts | 5 +-- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/modules/game/src/main/Game.scala b/modules/game/src/main/Game.scala index 55a19430f5..51a2bd833b 100644 --- a/modules/game/src/main/Game.scala +++ b/modules/game/src/main/Game.scala @@ -501,10 +501,10 @@ case class Game( // style "copy pasted" from a ts function def multiPointResult: String = if (metadata.multiPointState.isEmpty) "-" - else if (finished) finalMultiPointScore() + else if (finished) finalMultiPointScore else metadata.multiPointState.fold("-")(mps => f"${mps.target}%02d${mps.p1Points}%02d${mps.p2Points}%02d") - def finalMultiPointScore(): String = { + def finalMultiPointScore: String = { val points2Add: Array[Int] = if (pointValue.isDefined && winner.isDefined) if (winner.get.playerIndex == P1) Array(pointValue.get, 0) diff --git a/modules/swiss/src/main/SwissJson.scala b/modules/swiss/src/main/SwissJson.scala index 04b219f820..451a8eaa5d 100644 --- a/modules/swiss/src/main/SwissJson.scala +++ b/modules/swiss/src/main/SwissJson.scala @@ -282,40 +282,39 @@ object SwissJson { private def multiPointResultsJson(swissPairingGames: Seq[SwissPairingGames]) = JsArray( swissPairingGames.flatMap { - pairingGame => - Seq( - Json.obj( - "target" -> pairingGame.game.metadata.multiPointState.fold(0)(_.target), - "players" -> Json.obj( - "p1" -> Json.obj( - "userId" -> pairingGame.game.p1Player.userId, - ), - "p2" -> Json.obj( - "userId" -> pairingGame.game.p2Player.userId, - ) + pairingGame => Seq( + Json.obj( + "target" -> pairingGame.game.metadata.multiPointState.fold(0)(_.target), + "players" -> Json.obj( + "p1" -> Json.obj( + "userId" -> pairingGame.game.p1Player.userId, ), - "games" -> JsArray( - pairingGame.multiMatchGames.toList.flatten.reverse.map { game => - Json.obj( - "id" -> game.id, - "p1UserId" -> game.p1Player.userId, - "startingScore" -> Json.obj( - "p1" -> game.metadata.multiPointState.fold(0)(_.p1Points), - "p2" -> game.metadata.multiPointState.fold(0)(_.p2Points), - ) - ) - } :+ + "p2" -> Json.obj( + "userId" -> pairingGame.game.p2Player.userId, + ) + ), + "games" -> JsArray( + pairingGame.multiMatchGames.toList.flatten.reverse.map { game => Json.obj( - "id" -> pairingGame.game.id, - "p1UserId" -> pairingGame.game.p1Player.userId, + "id" -> game.id, + "p1UserId" -> game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> pairingGame.game.metadata.multiPointState.fold(0)(_.p1Points), - "p2" -> pairingGame.game.metadata.multiPointState.fold(0)(_.p2Points), + "p1" -> (if (game.finished) game.finalMultiPointScore.substring(2,4).toInt.toString else game.metadata.multiPointState.fold(0)(_.p1Points)), + "p2" -> (if (game.finished) game.finalMultiPointScore.substring(4,6).toInt.toString else game.metadata.multiPointState.fold(0)(_.p2Points)), ) ) - ) + } :+ + Json.obj( + "id" -> pairingGame.game.id, + "p1UserId" -> pairingGame.game.p1Player.userId, + "startingScore" -> Json.obj( + "p1" -> (if (pairingGame.game.finished) pairingGame.game.finalMultiPointScore.substring(2,4).toInt.toString else pairingGame.game.metadata.multiPointState.fold(0)(_.p1Points)), + "p2" -> (if (pairingGame.game.finished) pairingGame.game.finalMultiPointScore.substring(4,6).toInt.toString else pairingGame.game.metadata.multiPointState.fold(0)(_.p2Points)), + ) + ) ) ) + ) } ) diff --git a/ui/swiss/src/view/playerInfo.ts b/ui/swiss/src/view/playerInfo.ts index 1a10f50f0d..7cca5ca03b 100644 --- a/ui/swiss/src/view/playerInfo.ts +++ b/ui/swiss/src/view/playerInfo.ts @@ -221,11 +221,10 @@ function gameResult(p: MultiMatchPairing): string { } function multiPointResult(p: MultiMatchPairing, selectedUserId: string, multiPoints: MultiPoint[]): string { - // @TODO: need fix pla-1183-fix-multipoint-calculation-in-playerinfo : pass a ui/game/BaseGame and a ply up to here in order to invoke ui/stratutils/finalMultiPointState() and compute pts correctly (e.g : win multipoint match by timeout but opponent still gets pts by Rule of Gin) const edgeCasesDisplay = '(*)'; if (!multiPoints) return edgeCasesDisplay; const round = multiPoints.find(round => round.games?.find(game => game.id === p.g)); - if (p.mmGameNb === undefined || !round || round.games.length < 1 || !round.target) return edgeCasesDisplay; + if (p.mmGameNb === undefined || !round || round.games.length < 1 || !round.target || (p.w === undefined && p.mmGameNb == round.games.length)) return edgeCasesDisplay; if (p.isFinalGame && p.w !== undefined) { return p.w === true @@ -237,7 +236,7 @@ function multiPointResult(p: MultiMatchPairing, selectedUserId: string, multiPoi : round.games[0].startingScore.p2 + ' - ' + round.target; } - const multiPointMatchIndex = round.games.length - p.mmGameNb - 1; + const multiPointMatchIndex = round.games.length - p.mmGameNb; if (!round.games[multiPointMatchIndex]) return edgeCasesDisplay; const [selectedPlayerScore, opponentScore] = round.games[multiPointMatchIndex].p1UserId === selectedUserId From 48fa632eb752f20ea864b7e9af70a7481c08f7e9 Mon Sep 17 00:00:00 2001 From: Vincent FROCHOT Date: Tue, 25 Feb 2025 11:34:05 +0100 Subject: [PATCH 02/10] chore: pnpm format --- ui/swiss/src/view/playerInfo.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ui/swiss/src/view/playerInfo.ts b/ui/swiss/src/view/playerInfo.ts index 7cca5ca03b..ea6ef8a633 100644 --- a/ui/swiss/src/view/playerInfo.ts +++ b/ui/swiss/src/view/playerInfo.ts @@ -224,7 +224,14 @@ function multiPointResult(p: MultiMatchPairing, selectedUserId: string, multiPoi const edgeCasesDisplay = '(*)'; if (!multiPoints) return edgeCasesDisplay; const round = multiPoints.find(round => round.games?.find(game => game.id === p.g)); - if (p.mmGameNb === undefined || !round || round.games.length < 1 || !round.target || (p.w === undefined && p.mmGameNb == round.games.length)) return edgeCasesDisplay; + if ( + p.mmGameNb === undefined || + !round || + round.games.length < 1 || + !round.target || + (p.w === undefined && p.mmGameNb == round.games.length) + ) + return edgeCasesDisplay; if (p.isFinalGame && p.w !== undefined) { return p.w === true From 20a98f480331f8be7dd9a08b83deb65249032187 Mon Sep 17 00:00:00 2001 From: Vincent FROCHOT Date: Tue, 25 Feb 2025 11:42:49 +0100 Subject: [PATCH 03/10] fix: playerInfo in 1pt XGammon Swiss --- ui/swiss/src/view/playerInfo.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/ui/swiss/src/view/playerInfo.ts b/ui/swiss/src/view/playerInfo.ts index ea6ef8a633..cb8ebc1316 100644 --- a/ui/swiss/src/view/playerInfo.ts +++ b/ui/swiss/src/view/playerInfo.ts @@ -183,7 +183,7 @@ export default function (ctrl: SwissCtrl): VNode | undefined { h('td.is.playerIndex-icon.' + (p.c ? ctrl.data.p1Color : ctrl.data.p2Color)), h( 'td.gamescore' + (p.mmGameRes ? '.' + p.mmGameRes : ''), - ctrl.data.backgammonPoints + ctrl.data.backgammonPoints && ctrl.data.backgammonPoints > 1 ? multiPointResult(p, ctrl.playerInfoId, data.multiPoint ?? []) : p.ismm ? gameResult(p) @@ -224,14 +224,7 @@ function multiPointResult(p: MultiMatchPairing, selectedUserId: string, multiPoi const edgeCasesDisplay = '(*)'; if (!multiPoints) return edgeCasesDisplay; const round = multiPoints.find(round => round.games?.find(game => game.id === p.g)); - if ( - p.mmGameNb === undefined || - !round || - round.games.length < 1 || - !round.target || - (p.w === undefined && p.mmGameNb == round.games.length) - ) - return edgeCasesDisplay; + if (p.mmGameNb === undefined || !round || round.games.length < 1 || !round.target || (p.w === undefined && p.mmGameNb == round.games.length)) return edgeCasesDisplay; if (p.isFinalGame && p.w !== undefined) { return p.w === true From 2243e39eee14b024dc2403c7450dcd2207c8b8b4 Mon Sep 17 00:00:00 2001 From: Vincent FROCHOT Date: Tue, 25 Feb 2025 13:10:30 +0100 Subject: [PATCH 04/10] chore: refacto finalMultiPointScore --- modules/game/src/main/Game.scala | 10 +++++----- modules/swiss/src/main/SwissJson.scala | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/game/src/main/Game.scala b/modules/game/src/main/Game.scala index 51a2bd833b..094d0721d5 100644 --- a/modules/game/src/main/Game.scala +++ b/modules/game/src/main/Game.scala @@ -498,13 +498,13 @@ case class Game( p2Player = f(p2Player) ) - // style "copy pasted" from a ts function def multiPointResult: String = if (metadata.multiPointState.isEmpty) "-" - else if (finished) finalMultiPointScore + else if (finished) finalMultiPointScore.fold("-")(f => f) else metadata.multiPointState.fold("-")(mps => f"${mps.target}%02d${mps.p1Points}%02d${mps.p2Points}%02d") - def finalMultiPointScore: String = { + // style "copy pasted" from a ts function + def finalMultiPointScore: Option[String] = { val points2Add: Array[Int] = if (pointValue.isDefined && winner.isDefined) if (winner.get.playerIndex == P1) Array(pointValue.get, 0) @@ -526,8 +526,8 @@ case class Game( } return multiPointState match { - case Some(m) => f"${m.target}%02d${Math.min(m.target, m.p1Points + points2Add(0))}%02d${Math.min(m.target, m.p2Points + points2Add(1))}%02d" - case _ => "-" + case Some(m) => Some(f"${m.target}%02d${Math.min(m.target, m.p1Points + points2Add(0))}%02d${Math.min(m.target, m.p2Points + points2Add(1))}%02d") + case _ => None } } diff --git a/modules/swiss/src/main/SwissJson.scala b/modules/swiss/src/main/SwissJson.scala index 451a8eaa5d..8144a639ef 100644 --- a/modules/swiss/src/main/SwissJson.scala +++ b/modules/swiss/src/main/SwissJson.scala @@ -299,8 +299,8 @@ object SwissJson { "id" -> game.id, "p1UserId" -> game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> (if (game.finished) game.finalMultiPointScore.substring(2,4).toInt.toString else game.metadata.multiPointState.fold(0)(_.p1Points)), - "p2" -> (if (game.finished) game.finalMultiPointScore.substring(4,6).toInt.toString else game.metadata.multiPointState.fold(0)(_.p2Points)), + "p1" -> (if (game.finished) game.finalMultiPointScore.fold("-")(score => score).substring(2,4).toInt.toString else game.metadata.multiPointState.fold(0)(_.p1Points)), + "p2" -> (if (game.finished) game.finalMultiPointScore.fold("-")(score => score).substring(4,6).toInt.toString else game.metadata.multiPointState.fold(0)(_.p2Points)), ) ) } :+ @@ -308,8 +308,8 @@ object SwissJson { "id" -> pairingGame.game.id, "p1UserId" -> pairingGame.game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> (if (pairingGame.game.finished) pairingGame.game.finalMultiPointScore.substring(2,4).toInt.toString else pairingGame.game.metadata.multiPointState.fold(0)(_.p1Points)), - "p2" -> (if (pairingGame.game.finished) pairingGame.game.finalMultiPointScore.substring(4,6).toInt.toString else pairingGame.game.metadata.multiPointState.fold(0)(_.p2Points)), + "p1" -> (if (pairingGame.game.finished) pairingGame.game.finalMultiPointScore.fold("-")(score => score).substring(2,4).toInt.toString else pairingGame.game.metadata.multiPointState.fold(0)(_.p1Points)), + "p2" -> (if (pairingGame.game.finished) pairingGame.game.finalMultiPointScore.fold("-")(score => score).substring(4,6).toInt.toString else pairingGame.game.metadata.multiPointState.fold(0)(_.p2Points)), ) ) ) From 603c27400c40b9e2869e936eefd1998f211e56de Mon Sep 17 00:00:00 2001 From: Vincent FROCHOT Date: Tue, 25 Feb 2025 13:13:26 +0100 Subject: [PATCH 05/10] chore: pnpm format --- ui/swiss/src/view/playerInfo.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ui/swiss/src/view/playerInfo.ts b/ui/swiss/src/view/playerInfo.ts index cb8ebc1316..b32548b459 100644 --- a/ui/swiss/src/view/playerInfo.ts +++ b/ui/swiss/src/view/playerInfo.ts @@ -224,7 +224,14 @@ function multiPointResult(p: MultiMatchPairing, selectedUserId: string, multiPoi const edgeCasesDisplay = '(*)'; if (!multiPoints) return edgeCasesDisplay; const round = multiPoints.find(round => round.games?.find(game => game.id === p.g)); - if (p.mmGameNb === undefined || !round || round.games.length < 1 || !round.target || (p.w === undefined && p.mmGameNb == round.games.length)) return edgeCasesDisplay; + if ( + p.mmGameNb === undefined || + !round || + round.games.length < 1 || + !round.target || + (p.w === undefined && p.mmGameNb == round.games.length) + ) + return edgeCasesDisplay; if (p.isFinalGame && p.w !== undefined) { return p.w === true From 577e0796df1c77a28cb991a87d4527f2c7170056 Mon Sep 17 00:00:00 2001 From: Vincent FROCHOT Date: Tue, 25 Feb 2025 15:44:20 +0100 Subject: [PATCH 06/10] chore: refacto some Game multiPoint methods --- modules/game/src/main/Game.scala | 17 ++++++++++------- modules/swiss/src/main/SwissJson.scala | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/modules/game/src/main/Game.scala b/modules/game/src/main/Game.scala index 094d0721d5..74493cc6c1 100644 --- a/modules/game/src/main/Game.scala +++ b/modules/game/src/main/Game.scala @@ -498,13 +498,14 @@ case class Game( p2Player = f(p2Player) ) - def multiPointResult: String = - if (metadata.multiPointState.isEmpty) "-" - else if (finished) finalMultiPointScore.fold("-")(f => f) - else metadata.multiPointState.fold("-")(mps => f"${mps.target}%02d${mps.p1Points}%02d${mps.p2Points}%02d") + def multiPointResult: String = { + metadata.multiPointState.fold(MultiPointState.defaultChar) { mps => + if (finished) finalMultiPointScore else mps.toString + } + } // style "copy pasted" from a ts function - def finalMultiPointScore: Option[String] = { + def finalMultiPointScore: String = { val points2Add: Array[Int] = if (pointValue.isDefined && winner.isDefined) if (winner.get.playerIndex == P1) Array(pointValue.get, 0) @@ -526,8 +527,8 @@ case class Game( } return multiPointState match { - case Some(m) => Some(f"${m.target}%02d${Math.min(m.target, m.p1Points + points2Add(0))}%02d${Math.min(m.target, m.p2Points + points2Add(1))}%02d") - case _ => None + case Some(m) => MultiPointState(m.target, Math.min(m.target, m.p1Points + points2Add(0)), Math.min(m.target, m.p2Points + points2Add(1))).toString + case _ => MultiPointState.defaultChar } } @@ -1311,9 +1312,11 @@ case class MultiPointState(target: Int, p1Points: Int = 0, p2Points: Int = 0) { ) ) + override def toString: String = f"${target}%02d${p1Points}%02d${p2Points}%02d" } object MultiPointState { + var defaultChar = "-" def apply(points: Option[Int]): Option[MultiPointState] = points.filter(_ != 1).map(p => MultiPointState(p)) diff --git a/modules/swiss/src/main/SwissJson.scala b/modules/swiss/src/main/SwissJson.scala index 8144a639ef..b32521dd38 100644 --- a/modules/swiss/src/main/SwissJson.scala +++ b/modules/swiss/src/main/SwissJson.scala @@ -294,22 +294,22 @@ object SwissJson { ) ), "games" -> JsArray( - pairingGame.multiMatchGames.toList.flatten.reverse.map { game => - Json.obj( - "id" -> game.id, - "p1UserId" -> game.p1Player.userId, - "startingScore" -> Json.obj( - "p1" -> (if (game.finished) game.finalMultiPointScore.fold("-")(score => score).substring(2,4).toInt.toString else game.metadata.multiPointState.fold(0)(_.p1Points)), - "p2" -> (if (game.finished) game.finalMultiPointScore.fold("-")(score => score).substring(4,6).toInt.toString else game.metadata.multiPointState.fold(0)(_.p2Points)), + pairingGame.multiMatchGames.toList.flatten.reverse.map { game => + Json.obj( + "id" -> game.id, + "p1UserId" -> game.p1Player.userId, + "startingScore" -> Json.obj( + "p1" -> game.multiPointResult.substring(2,4).toInt.toString, + "p2" -> game.multiPointResult.substring(4,6).toInt.toString, + ) ) - ) } :+ Json.obj( "id" -> pairingGame.game.id, "p1UserId" -> pairingGame.game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> (if (pairingGame.game.finished) pairingGame.game.finalMultiPointScore.fold("-")(score => score).substring(2,4).toInt.toString else pairingGame.game.metadata.multiPointState.fold(0)(_.p1Points)), - "p2" -> (if (pairingGame.game.finished) pairingGame.game.finalMultiPointScore.fold("-")(score => score).substring(4,6).toInt.toString else pairingGame.game.metadata.multiPointState.fold(0)(_.p2Points)), + "p1" -> pairingGame.game.multiPointResult.substring(2,4).toInt.toString, + "p2" -> pairingGame.game.multiPointResult.substring(4,6).toInt.toString ) ) ) From 5ee9ee2586f9e1db9437f9f5291b3da9a0a6feb3 Mon Sep 17 00:00:00 2001 From: Vincent FROCHOT Date: Tue, 25 Feb 2025 16:03:20 +0100 Subject: [PATCH 07/10] chore: refactor MultiPointState util functions --- app/views/game/mini.scala | 4 ++-- modules/game/src/main/Game.scala | 3 +++ modules/swiss/src/main/SwissJson.scala | 10 +++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/app/views/game/mini.scala b/app/views/game/mini.scala index 7054f70410..e7d32c99d6 100644 --- a/app/views/game/mini.scala +++ b/app/views/game/mini.scala @@ -9,7 +9,7 @@ import play.api.i18n.Lang import lila.api.Context import lila.app.templating.Environment._ import lila.app.ui.ScalatagsTemplate._ -import lila.game.Pov +import lila.game.{ Pov, MultiPointState } import lila.i18n.defaultLang object mini { @@ -117,7 +117,7 @@ object mini { case Some(_) => { val score = pov.game.multiPointResult if (score == "-") score - else " (" + (if(pov.playerIndex.p1) score.substring(2, 4).toInt else score.substring(4, 6).toInt) + ")" + else " (" + (MultiPointState.extractPlayerScoreFromMultiPointString(score, pov.playerIndex.p1)) + ")" } case None => { val score = pov.game.calculateScore(pov.playerIndex) diff --git a/modules/game/src/main/Game.scala b/modules/game/src/main/Game.scala index 74493cc6c1..615282aada 100644 --- a/modules/game/src/main/Game.scala +++ b/modules/game/src/main/Game.scala @@ -1318,6 +1318,9 @@ case class MultiPointState(target: Int, p1Points: Int = 0, p2Points: Int = 0) { object MultiPointState { var defaultChar = "-" + def extractPlayerScoreFromMultiPointString(mps: String, p1: Boolean = true): String = + mps.substring(if (p1) 2 else 4, if (p1) 4 else 6).toInt.toString + def apply(points: Option[Int]): Option[MultiPointState] = points.filter(_ != 1).map(p => MultiPointState(p)) def nextGameIsCrawford(game: Game): Boolean = diff --git a/modules/swiss/src/main/SwissJson.scala b/modules/swiss/src/main/SwissJson.scala index b32521dd38..cef8ce7742 100644 --- a/modules/swiss/src/main/SwissJson.scala +++ b/modules/swiss/src/main/SwissJson.scala @@ -13,7 +13,7 @@ import scala.concurrent.ExecutionContext import lila.common.{ GreatPlayer, LightUser } import lila.db.dsl._ -import lila.game.Game +import lila.game.{ Game, MultiPointState } import lila.game.Handicaps.goRatingDisplay import lila.quote.Quote import lila.quote.Quote.quoteWriter @@ -299,8 +299,8 @@ object SwissJson { "id" -> game.id, "p1UserId" -> game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> game.multiPointResult.substring(2,4).toInt.toString, - "p2" -> game.multiPointResult.substring(4,6).toInt.toString, + "p1" -> MultiPointState.extractPlayerScoreFromMultiPointString(game.multiPointResult), + "p2" -> MultiPointState.extractPlayerScoreFromMultiPointString(game.multiPointResult, false), ) ) } :+ @@ -308,8 +308,8 @@ object SwissJson { "id" -> pairingGame.game.id, "p1UserId" -> pairingGame.game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> pairingGame.game.multiPointResult.substring(2,4).toInt.toString, - "p2" -> pairingGame.game.multiPointResult.substring(4,6).toInt.toString + "p1" -> MultiPointState.extractPlayerScoreFromMultiPointString(pairingGame.game.multiPointResult), + "p2" -> MultiPointState.extractPlayerScoreFromMultiPointString(pairingGame.game.multiPointResult, false), ) ) ) From a8473355ed9d34257a9d0b1b531dc2a1ffc352fd Mon Sep 17 00:00:00 2001 From: Vincent FROCHOT Date: Tue, 25 Feb 2025 18:34:34 +0100 Subject: [PATCH 08/10] chore: improve refacto --- app/views/board/bits.scala | 5 +++-- app/views/game/mini.scala | 6 +++--- modules/game/src/main/Game.scala | 18 +++++++----------- modules/swiss/src/main/SwissJson.scala | 8 ++++---- 4 files changed, 17 insertions(+), 20 deletions(-) diff --git a/app/views/board/bits.scala b/app/views/board/bits.scala index 5ae13a20f3..d95ae99c75 100644 --- a/app/views/board/bits.scala +++ b/app/views/board/bits.scala @@ -13,6 +13,7 @@ import lila.api.Context import lila.app.templating.Environment._ import lila.app.ui.ScalatagsTemplate._ import lila.game.Pov +import lila.game.MultiPointState object bits { @@ -80,7 +81,7 @@ object bits { lastMove: String = "", boardSizeOpt: Option[Board.BoardSize], variantKey: String = "standard", - multiPointResult: String = "-" + multiPointResult: Option[MultiPointState] = None )(tag: Tag): Tag = { // TODO: this is an excellent candidate for refactoring. val libName = fen match { @@ -98,7 +99,7 @@ object bits { val data = if (libName == "Draughts") { s"${fen.value}|${boardSize.width}x${boardSize.height}|${orient}|$lastMove" } else { - s"${fen.value}|${orient}|$lastMove|$multiPointResult" + s"${fen.value}|${orient}|$lastMove|${multiPointResult.fold(MultiPointState.noDataChar)(_.toString)}" } val extra = if (libName == "Draughts") s"is${boardSize.key} ${libName.toLowerCase()}" diff --git a/app/views/game/mini.scala b/app/views/game/mini.scala index e7d32c99d6..d0b6714a7c 100644 --- a/app/views/game/mini.scala +++ b/app/views/game/mini.scala @@ -115,9 +115,9 @@ object mini { private def calculateScore(pov: Pov): String = pov.game.metadata.multiPointState match { case Some(_) => { - val score = pov.game.multiPointResult - if (score == "-") score - else " (" + (MultiPointState.extractPlayerScoreFromMultiPointString(score, pov.playerIndex.p1)) + ")" + pov.game.multiPointResult.fold(MultiPointState.noDataChar) { mps => + s" (${if (pov.playerIndex.p1) mps.p1Points else mps.p2Points})" + } } case None => { val score = pov.game.calculateScore(pov.playerIndex) diff --git a/modules/game/src/main/Game.scala b/modules/game/src/main/Game.scala index 615282aada..306d93a511 100644 --- a/modules/game/src/main/Game.scala +++ b/modules/game/src/main/Game.scala @@ -498,14 +498,13 @@ case class Game( p2Player = f(p2Player) ) - def multiPointResult: String = { - metadata.multiPointState.fold(MultiPointState.defaultChar) { mps => - if (finished) finalMultiPointScore else mps.toString - } + def multiPointResult: Option[MultiPointState] = + metadata.multiPointState.flatMap { mps => + if (finished) finalScoreMultiPointState else Some(mps) } // style "copy pasted" from a ts function - def finalMultiPointScore: String = { + def finalScoreMultiPointState: Option[MultiPointState] = { val points2Add: Array[Int] = if (pointValue.isDefined && winner.isDefined) if (winner.get.playerIndex == P1) Array(pointValue.get, 0) @@ -527,8 +526,8 @@ case class Game( } return multiPointState match { - case Some(m) => MultiPointState(m.target, Math.min(m.target, m.p1Points + points2Add(0)), Math.min(m.target, m.p2Points + points2Add(1))).toString - case _ => MultiPointState.defaultChar + case Some(m) => Some(MultiPointState(m.target, Math.min(m.target, m.p1Points + points2Add(0)), Math.min(m.target, m.p2Points + points2Add(1)))) + case _ => None } } @@ -1316,10 +1315,7 @@ case class MultiPointState(target: Int, p1Points: Int = 0, p2Points: Int = 0) { } object MultiPointState { - var defaultChar = "-" - - def extractPlayerScoreFromMultiPointString(mps: String, p1: Boolean = true): String = - mps.substring(if (p1) 2 else 4, if (p1) 4 else 6).toInt.toString + var noDataChar = "-" def apply(points: Option[Int]): Option[MultiPointState] = points.filter(_ != 1).map(p => MultiPointState(p)) diff --git a/modules/swiss/src/main/SwissJson.scala b/modules/swiss/src/main/SwissJson.scala index cef8ce7742..5e1489605e 100644 --- a/modules/swiss/src/main/SwissJson.scala +++ b/modules/swiss/src/main/SwissJson.scala @@ -299,8 +299,8 @@ object SwissJson { "id" -> game.id, "p1UserId" -> game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> MultiPointState.extractPlayerScoreFromMultiPointString(game.multiPointResult), - "p2" -> MultiPointState.extractPlayerScoreFromMultiPointString(game.multiPointResult, false), + "p1" -> game.multiPointResult.get.p1Points.toString, + "p2" -> game.multiPointResult.get.p2Points.toString, ) ) } :+ @@ -308,8 +308,8 @@ object SwissJson { "id" -> pairingGame.game.id, "p1UserId" -> pairingGame.game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> MultiPointState.extractPlayerScoreFromMultiPointString(pairingGame.game.multiPointResult), - "p2" -> MultiPointState.extractPlayerScoreFromMultiPointString(pairingGame.game.multiPointResult, false), + "p1" -> pairingGame.game.multiPointResult.get.p1Points.toString, + "p2" -> pairingGame.game.multiPointResult.get.p2Points.toString, ) ) ) From b545d5ee9f8706a7a6793c3330d4e09ff3899a24 Mon Sep 17 00:00:00 2001 From: Vincent FROCHOT Date: Tue, 25 Feb 2025 18:38:25 +0100 Subject: [PATCH 09/10] chore: use fold as extra layer --- modules/swiss/src/main/SwissJson.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/swiss/src/main/SwissJson.scala b/modules/swiss/src/main/SwissJson.scala index 5e1489605e..376c42fb4c 100644 --- a/modules/swiss/src/main/SwissJson.scala +++ b/modules/swiss/src/main/SwissJson.scala @@ -299,8 +299,8 @@ object SwissJson { "id" -> game.id, "p1UserId" -> game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> game.multiPointResult.get.p1Points.toString, - "p2" -> game.multiPointResult.get.p2Points.toString, + "p1" -> game.multiPointResult.fold("0")(_.p1Points.toString), + "p2" -> game.multiPointResult.fold("0")(_.p2Points.toString), ) ) } :+ @@ -308,8 +308,8 @@ object SwissJson { "id" -> pairingGame.game.id, "p1UserId" -> pairingGame.game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> pairingGame.game.multiPointResult.get.p1Points.toString, - "p2" -> pairingGame.game.multiPointResult.get.p2Points.toString, + "p1" -> pairingGame.game.multiPointResult.fold("0")(_.p1Points.toString), + "p2" -> pairingGame.game.multiPointResult.fold("0")(_.p2Points.toString), ) ) ) From 7f4afdb8475aad55bee7971ff84676e4ef24f4a0 Mon Sep 17 00:00:00 2001 From: Vincent FROCHOT Date: Tue, 25 Feb 2025 18:59:01 +0100 Subject: [PATCH 10/10] fix: miniViews and padded numbers --- app/views/game/mini.scala | 4 ++-- modules/game/src/main/Game.scala | 1 + modules/swiss/src/main/SwissJson.scala | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/views/game/mini.scala b/app/views/game/mini.scala index d0b6714a7c..a265239515 100644 --- a/app/views/game/mini.scala +++ b/app/views/game/mini.scala @@ -85,7 +85,7 @@ object mini { def renderState(pov: Pov) = pov.game.variant match { case Variant.Backgammon(_) => - dataState := s"${Forsyth.>>(pov.game.variant.gameLogic, pov.game.stratGame)}|${orientation(pov)}|${~pov.game.lastActionKeys}|${pov.game.multiPointResult}" + dataState := s"${Forsyth.>>(pov.game.variant.gameLogic, pov.game.stratGame)}|${orientation(pov)}|${~pov.game.lastActionKeys}|${pov.game.multiPointResult.fold(MultiPointState.noDataChar)(_.toString)}" case Variant.Chess(_) | Variant.FairySF(_) | Variant.Samurai(_) | Variant.Togyzkumalak(_) | Variant.Go(_) | Variant.Abalone(_) => dataState := s"${Forsyth.>>(pov.game.variant.gameLogic, pov.game.stratGame)}|${orientation(pov)}|${~pov.game.lastActionKeys}" @@ -116,7 +116,7 @@ object mini { pov.game.metadata.multiPointState match { case Some(_) => { pov.game.multiPointResult.fold(MultiPointState.noDataChar) { mps => - s" (${if (pov.playerIndex.p1) mps.p1Points else mps.p2Points})" + s" (${mps.toString(pov.playerIndex.p1).toInt})" } } case None => { diff --git a/modules/game/src/main/Game.scala b/modules/game/src/main/Game.scala index 306d93a511..155797021d 100644 --- a/modules/game/src/main/Game.scala +++ b/modules/game/src/main/Game.scala @@ -1312,6 +1312,7 @@ case class MultiPointState(target: Int, p1Points: Int = 0, p2Points: Int = 0) { ) override def toString: String = f"${target}%02d${p1Points}%02d${p2Points}%02d" + def toString(p1: Boolean): String = f"${(if(p1) p1Points else p2Points)}%02d" } object MultiPointState { diff --git a/modules/swiss/src/main/SwissJson.scala b/modules/swiss/src/main/SwissJson.scala index 376c42fb4c..ecd81ed905 100644 --- a/modules/swiss/src/main/SwissJson.scala +++ b/modules/swiss/src/main/SwissJson.scala @@ -299,8 +299,8 @@ object SwissJson { "id" -> game.id, "p1UserId" -> game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> game.multiPointResult.fold("0")(_.p1Points.toString), - "p2" -> game.multiPointResult.fold("0")(_.p2Points.toString), + "p1" -> game.multiPointResult.fold(0)(_.p1Points), + "p2" -> game.multiPointResult.fold(0)(_.p2Points), ) ) } :+ @@ -308,8 +308,8 @@ object SwissJson { "id" -> pairingGame.game.id, "p1UserId" -> pairingGame.game.p1Player.userId, "startingScore" -> Json.obj( - "p1" -> pairingGame.game.multiPointResult.fold("0")(_.p1Points.toString), - "p2" -> pairingGame.game.multiPointResult.fold("0")(_.p2Points.toString), + "p1" -> pairingGame.game.multiPointResult.fold(0)(_.p1Points), + "p2" -> pairingGame.game.multiPointResult.fold(0)(_.p2Points), ) ) )