Feat: Money is now saved in the Higshcore list. #323
+11
-5
@@ -60,12 +60,9 @@ public class GetGameStateResponse extends SuccessResponse {
|
|||||||
builder.param("WINNER", winnerIndex);
|
builder.param("WINNER", winnerIndex);
|
||||||
|
|
||||||
List<String> winnerNames = computeWinnerNames(state, game);
|
List<String> winnerNames = computeWinnerNames(state, game);
|
||||||
int potPerWinner = computePotPerWinner(state, winnerNames.size());
|
|
||||||
|
|
||||||
for (String name : winnerNames) {
|
for (String name : winnerNames) {
|
||||||
builder.param("WINNER_NAME", name);
|
builder.param("WINNER_NAME", name);
|
||||||
}
|
}
|
||||||
builder.param("POT_PER_WINNER", potPerWinner);
|
|
||||||
|
|
||||||
appendWinnerToHighscoresIfFinished(state, winnerNames);
|
appendWinnerToHighscoresIfFinished(state, winnerNames);
|
||||||
appendHighscoreEntries(builder);
|
appendHighscoreEntries(builder);
|
||||||
@@ -92,13 +89,22 @@ public class GetGameStateResponse extends SuccessResponse {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep ordering stable, avoid duplicate writes for the same winner in one hand.
|
// Keep ordering stable and persist tied winners as a single shared highscore
|
||||||
|
// entry. Compute the per-winner share here (pot is split equally among
|
||||||
|
// winners)
|
||||||
|
int potPerWinner = computePotPerWinner(state, winnerNames.size());
|
||||||
Set<String> uniqueWinners = new LinkedHashSet<>(winnerNames);
|
Set<String> uniqueWinners = new LinkedHashSet<>(winnerNames);
|
||||||
|
List<String> formattedWinners = new ArrayList<>();
|
||||||
for (String name : uniqueWinners) {
|
for (String name : uniqueWinners) {
|
||||||
if (name != null && !name.isBlank()) {
|
if (name != null && !name.isBlank()) {
|
||||||
HighscoreService.getInstance().appendWinner(name);
|
formattedWinners.add(name + " (" + Math.max(0, potPerWinner) + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!formattedWinners.isEmpty()) {
|
||||||
|
HighscoreService.getInstance()
|
||||||
|
.appendFormattedEntry(String.join(", ", formattedWinners));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Player findPlayerByIndex(GameState state, int winnerIndex) {
|
private static Player findPlayerByIndex(GameState state, int winnerIndex) {
|
||||||
|
|||||||
+57
-3
@@ -18,6 +18,7 @@ public final class HighscoreService {
|
|||||||
private static final DateTimeFormatter DISPLAY_FORMATTER =
|
private static final DateTimeFormatter DISPLAY_FORMATTER =
|
||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
|
||||||
private static final int MAX_RETURNED_ENTRIES = 100;
|
private static final int MAX_RETURNED_ENTRIES = 100;
|
||||||
|
private static final int MIN_MONEY_COLUMN_COUNT = 3;
|
||||||
private static final String LINE_SEPARATOR = "\t";
|
private static final String LINE_SEPARATOR = "\t";
|
||||||
|
|
||||||
private final Path storagePath;
|
private final Path storagePath;
|
||||||
@@ -32,6 +33,11 @@ public final class HighscoreService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void appendWinner(String winnerName) {
|
public synchronized void appendWinner(String winnerName) {
|
||||||
|
appendWinner(winnerName, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Append a winner with an optional money value (money may be 0). */
|
||||||
|
public synchronized void appendWinner(String winnerName, int money) {
|
||||||
if (winnerName == null) {
|
if (winnerName == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -41,6 +47,44 @@ public final class HighscoreService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String line;
|
||||||
|
if (money > 0) {
|
||||||
|
line =
|
||||||
|
Instant.now()
|
||||||
|
+ LINE_SEPARATOR
|
||||||
|
+ sanitized
|
||||||
|
+ LINE_SEPARATOR
|
||||||
|
+ money
|
||||||
|
+ System.lineSeparator();
|
||||||
|
} else {
|
||||||
|
// Keep legacy two-column format for backward compatibility
|
||||||
|
line = Instant.now() + LINE_SEPARATOR + sanitized + System.lineSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.createDirectories(storagePath.getParent());
|
||||||
|
Files.writeString(
|
||||||
|
storagePath,
|
||||||
|
line,
|
||||||
|
StandardCharsets.UTF_8,
|
||||||
|
StandardOpenOption.CREATE,
|
||||||
|
StandardOpenOption.APPEND);
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
// Highscore persistence must never break the game state response path.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Append a preformatted highscore entry such as "Lars (1000), Jona (1000)". */
|
||||||
|
public synchronized void appendFormattedEntry(String entryText) {
|
||||||
|
if (entryText == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sanitized = sanitizeName(entryText);
|
||||||
|
if (sanitized.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
String line = Instant.now() + LINE_SEPARATOR + sanitized + System.lineSeparator();
|
String line = Instant.now() + LINE_SEPARATOR + sanitized + System.lineSeparator();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -74,15 +118,25 @@ public final class HighscoreService {
|
|||||||
if (raw == null || raw.isBlank()) {
|
if (raw == null || raw.isBlank()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Support both legacy format (TIMESTAMP \t NAME) and new format (TIMESTAMP \t
|
||||||
String[] parts = raw.split(LINE_SEPARATOR, 2);
|
// NAME \t MONEY)
|
||||||
|
String[] parts = raw.split(LINE_SEPARATOR);
|
||||||
if (parts.length < 2) {
|
if (parts.length < 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Instant ts = Instant.parse(parts[0].trim());
|
Instant ts = Instant.parse(parts[0].trim());
|
||||||
String display = DISPLAY_FORMATTER.format(ts) + " | " + parts[1].trim();
|
String name = parts[1].trim();
|
||||||
|
String display = DISPLAY_FORMATTER.format(ts) + " | " + name;
|
||||||
|
if (parts.length >= MIN_MONEY_COLUMN_COUNT) {
|
||||||
|
try {
|
||||||
|
int money = Integer.parseInt(parts[2].trim());
|
||||||
|
display = display + " | $" + money;
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
// ignore malformed money
|
||||||
|
}
|
||||||
|
}
|
||||||
formatted.add(display);
|
formatted.add(display);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
// Skip malformed lines and keep all valid entries.
|
// Skip malformed lines and keep all valid entries.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
|
|
||||||
<AnchorPane xmlns="http://javafx.com"
|
<AnchorPane fx:id="rootPane" xmlns="http://javafx.com"
|
||||||
xmlns:fx="http://javafx.com"
|
xmlns:fx="http://javafx.com"
|
||||||
fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.lobbyui.CasinomainuiController"
|
fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.lobbyui.CasinomainuiController"
|
||||||
styleClass="anchor-pane-bg"
|
styleClass="anchor-pane-bg"
|
||||||
|
|||||||
+5
-6
@@ -14,10 +14,10 @@ class TaskbarControllerInputValidationTest {
|
|||||||
void updateLogicRunsWithoutCrash() {
|
void updateLogicRunsWithoutCrash() {
|
||||||
GameState state = new GameState();
|
GameState state = new GameState();
|
||||||
|
|
||||||
state.players = List.of(
|
state.players =
|
||||||
new Player(PlayerId.of("me"), 20000),
|
List.of(
|
||||||
new Player(PlayerId.of("other"), 20000)
|
new Player(PlayerId.of("me"), 20000),
|
||||||
);
|
new Player(PlayerId.of("other"), 20000));
|
||||||
|
|
||||||
state.phase = "PREFLOP";
|
state.phase = "PREFLOP";
|
||||||
state.currentBet = 200;
|
state.currentBet = 200;
|
||||||
@@ -31,7 +31,6 @@ class TaskbarControllerInputValidationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class DummyController {
|
static class DummyController {
|
||||||
void update(GameState state, PlayerId id) {
|
void update(GameState state, PlayerId id) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user