Updated score and winner handling
This commit is contained in:
@@ -2,11 +2,12 @@ import 'package:drift/drift.dart';
|
||||
import 'package:tallee/core/enums.dart';
|
||||
import 'package:tallee/data/db/database.dart';
|
||||
import 'package:tallee/data/db/tables/game_table.dart';
|
||||
import 'package:tallee/data/db/tables/match_table.dart';
|
||||
import 'package:tallee/data/models/game.dart';
|
||||
|
||||
part 'game_dao.g.dart';
|
||||
|
||||
@DriftAccessor(tables: [GameTable])
|
||||
@DriftAccessor(tables: [MatchTable, GameTable])
|
||||
class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
||||
GameDao(super.db);
|
||||
|
||||
@@ -44,6 +45,25 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
||||
);
|
||||
}
|
||||
|
||||
Future<Game> getGameByMatchId({required String matchId}) async {
|
||||
final query = select(gameTable).join([
|
||||
innerJoin(matchTable, matchTable.gameId.equalsExp(gameTable.id)),
|
||||
])..where(matchTable.id.equals(matchId));
|
||||
|
||||
final result = await query.getSingle();
|
||||
final gameRow = result.readTable(gameTable);
|
||||
|
||||
return Game(
|
||||
id: gameRow.id,
|
||||
name: gameRow.name,
|
||||
ruleset: Ruleset.values.firstWhere((e) => e.name == gameRow.ruleset),
|
||||
description: gameRow.description,
|
||||
color: GameColor.values.firstWhere((e) => e.name == gameRow.color),
|
||||
icon: gameRow.icon,
|
||||
createdAt: gameRow.createdAt,
|
||||
);
|
||||
}
|
||||
|
||||
/// Adds a new [game] to the database.
|
||||
/// If a game with the same ID already exists, no action is taken.
|
||||
/// Returns `true` if the game was added, `false` otherwise.
|
||||
|
||||
@@ -5,6 +5,8 @@ part of 'game_dao.dart';
|
||||
// ignore_for_file: type=lint
|
||||
mixin _$GameDaoMixin on DatabaseAccessor<AppDatabase> {
|
||||
$GameTableTable get gameTable => attachedDatabase.gameTable;
|
||||
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
||||
$MatchTableTable get matchTable => attachedDatabase.matchTable;
|
||||
GameDaoManager get managers => GameDaoManager(this);
|
||||
}
|
||||
|
||||
@@ -13,4 +15,8 @@ class GameDaoManager {
|
||||
GameDaoManager(this._db);
|
||||
$$GameTableTableTableManager get gameTable =>
|
||||
$$GameTableTableTableManager(_db.attachedDatabase, _db.gameTable);
|
||||
$$GroupTableTableTableManager get groupTable =>
|
||||
$$GroupTableTableTableManager(_db.attachedDatabase, _db.groupTable);
|
||||
$$MatchTableTableTableManager get matchTable =>
|
||||
$$MatchTableTableTableManager(_db.attachedDatabase, _db.matchTable);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
||||
matchId: row.id,
|
||||
);
|
||||
|
||||
final winner = await db.scoreEntryDao.getWinner(matchId: row.id);
|
||||
return Match(
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
@@ -45,7 +44,6 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
||||
createdAt: row.createdAt,
|
||||
endedAt: row.endedAt,
|
||||
scores: scores,
|
||||
winner: winner,
|
||||
);
|
||||
}),
|
||||
);
|
||||
@@ -68,8 +66,6 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
||||
|
||||
final scores = await db.scoreEntryDao.getAllMatchScores(matchId: matchId);
|
||||
|
||||
final winner = await db.scoreEntryDao.getWinner(matchId: matchId);
|
||||
|
||||
return Match(
|
||||
id: result.id,
|
||||
name: result.name,
|
||||
@@ -80,7 +76,6 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
||||
createdAt: result.createdAt,
|
||||
endedAt: result.endedAt,
|
||||
scores: scores,
|
||||
winner: winner,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -110,19 +105,14 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
||||
}
|
||||
|
||||
for (final pid in match.scores.keys) {
|
||||
final playerScores = match.scores[pid]!;
|
||||
await db.scoreEntryDao.addScoresAsList(
|
||||
entrys: playerScores,
|
||||
playerId: pid,
|
||||
matchId: match.id,
|
||||
);
|
||||
}
|
||||
|
||||
if (match.winner != null) {
|
||||
await db.scoreEntryDao.setWinner(
|
||||
matchId: match.id,
|
||||
playerId: match.winner!.id,
|
||||
);
|
||||
final playerScores = match.scores[pid];
|
||||
if (playerScores != null) {
|
||||
await db.scoreEntryDao.addScore(
|
||||
entry: playerScores,
|
||||
playerId: pid,
|
||||
matchId: match.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -300,7 +290,6 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
||||
final group = await db.groupDao.getGroupById(groupId: groupId);
|
||||
final players =
|
||||
await db.playerMatchDao.getPlayersOfMatch(matchId: row.id) ?? [];
|
||||
final winner = await db.scoreEntryDao.getWinner(matchId: row.id);
|
||||
return Match(
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
@@ -310,7 +299,6 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
||||
notes: row.notes ?? '',
|
||||
createdAt: row.createdAt,
|
||||
endedAt: row.endedAt,
|
||||
winner: winner,
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:drift/drift.dart';
|
||||
import 'package:tallee/core/enums.dart';
|
||||
import 'package:tallee/data/db/database.dart';
|
||||
import 'package:tallee/data/db/tables/score_entry_table.dart';
|
||||
import 'package:tallee/data/models/player.dart';
|
||||
@@ -83,21 +84,21 @@ class ScoreEntryDao extends DatabaseAccessor<AppDatabase>
|
||||
}
|
||||
|
||||
/// Retrieves all scores for a specific match.
|
||||
Future<Map<String, List<ScoreEntry>>> getAllMatchScores({
|
||||
Future<Map<String, ScoreEntry?>> getAllMatchScores({
|
||||
required String matchId,
|
||||
}) async {
|
||||
final query = select(scoreEntryTable)
|
||||
..where((s) => s.matchId.equals(matchId));
|
||||
final result = await query.get();
|
||||
|
||||
final Map<String, List<ScoreEntry>> scoresByPlayer = {};
|
||||
final Map<String, ScoreEntry?> scoresByPlayer = {};
|
||||
for (final row in result) {
|
||||
final score = ScoreEntry(
|
||||
roundNumber: row.roundNumber,
|
||||
score: row.score,
|
||||
change: row.change,
|
||||
);
|
||||
scoresByPlayer.putIfAbsent(row.playerId, () => []).add(score);
|
||||
scoresByPlayer[row.playerId] = score;
|
||||
}
|
||||
|
||||
return scoresByPlayer;
|
||||
@@ -237,10 +238,25 @@ class ScoreEntryDao extends DatabaseAccessor<AppDatabase>
|
||||
|
||||
// Retrieves the winner of a match based on the highest score.
|
||||
Future<Player?> getWinner({required String matchId}) async {
|
||||
// Check the ruleset of the match
|
||||
final ruleset = await db.gameDao
|
||||
.getGameByMatchId(matchId: matchId)
|
||||
.then((game) => game.ruleset);
|
||||
|
||||
final query = select(scoreEntryTable)
|
||||
..where((s) => s.matchId.equals(matchId))
|
||||
..orderBy([(s) => OrderingTerm.desc(s.score)])
|
||||
..limit(1);
|
||||
..where((s) => s.matchId.equals(matchId));
|
||||
|
||||
// If the ruleset is lowestScore, the winner is the player with the lowest
|
||||
// score so we order by ascending score.
|
||||
if (ruleset == Ruleset.lowestScore) {
|
||||
query
|
||||
..orderBy([(s) => OrderingTerm.asc(s.score)])
|
||||
..limit(1);
|
||||
} else {
|
||||
query
|
||||
..orderBy([(s) => OrderingTerm.desc(s.score)])
|
||||
..limit(1);
|
||||
}
|
||||
final result = await query.getSingleOrNull();
|
||||
|
||||
if (result == null) return null;
|
||||
|
||||
@@ -15,27 +15,25 @@ class Match {
|
||||
final Group? group;
|
||||
final List<Player> players;
|
||||
final String notes;
|
||||
Map<String, List<ScoreEntry>> scores;
|
||||
Player? winner;
|
||||
Map<String, ScoreEntry?> scores;
|
||||
|
||||
Match({
|
||||
String? id,
|
||||
DateTime? createdAt,
|
||||
this.endedAt,
|
||||
required this.name,
|
||||
required this.game,
|
||||
required this.players,
|
||||
this.endedAt,
|
||||
this.group,
|
||||
this.players = const [],
|
||||
this.notes = '',
|
||||
Map<String, List<ScoreEntry>>? scores,
|
||||
this.winner,
|
||||
String? id,
|
||||
DateTime? createdAt,
|
||||
Map<String, ScoreEntry?>? scores,
|
||||
}) : id = id ?? const Uuid().v4(),
|
||||
createdAt = createdAt ?? clock.now(),
|
||||
scores = scores ?? {for (var player in players) player.id: []};
|
||||
scores = scores ?? {for (Player p in players) p.id: null};
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Match{id: $id, createdAt: $createdAt, endedAt: $endedAt, name: $name, game: $game, group: $group, players: $players, notes: $notes, scores: $scores, winner: $winner}';
|
||||
return 'Match{id: $id, createdAt: $createdAt, endedAt: $endedAt, name: $name, game: $game, group: $group, players: $players, notes: $notes, scores: $scores, mvp: $mvp}';
|
||||
}
|
||||
|
||||
/// Creates a Match instance from a JSON object where related objects are
|
||||
@@ -71,10 +69,60 @@ class Match {
|
||||
'gameId': game.id,
|
||||
'groupId': group?.id,
|
||||
'playerIds': players.map((player) => player.id).toList(),
|
||||
'scores': scores.map(
|
||||
(playerId, scoreList) =>
|
||||
MapEntry(playerId, scoreList.map((score) => score.toJson()).toList()),
|
||||
),
|
||||
'scores': scores,
|
||||
'notes': notes,
|
||||
};
|
||||
|
||||
List<Player> get mvp {
|
||||
if (players.isEmpty || scores.isEmpty) return [];
|
||||
|
||||
switch (game.ruleset) {
|
||||
case Ruleset.highestScore:
|
||||
return _getPlayersWithHighestScore();
|
||||
|
||||
case Ruleset.lowestScore:
|
||||
return _getPlayersWithLowestScore();
|
||||
|
||||
case Ruleset.singleWinner:
|
||||
return [_getPlayersWithHighestScore().first];
|
||||
|
||||
case Ruleset.singleLoser:
|
||||
return [_getPlayersWithLowestScore().first];
|
||||
|
||||
case Ruleset.multipleWinners:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
List<Player> _getPlayersWithHighestScore() {
|
||||
if (players.isEmpty || scores.isEmpty) return [];
|
||||
|
||||
final int highestScore = players
|
||||
.map((player) => scores[player.id]?.score)
|
||||
.whereType<int>()
|
||||
.reduce((max, score) => score > max ? score : max);
|
||||
|
||||
return players.where((player) {
|
||||
final playerScores = scores[player.id];
|
||||
if (playerScores == null) return false;
|
||||
return playerScores.score == highestScore;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
List<Player> _getPlayersWithLowestScore() {
|
||||
if (players.isEmpty || scores.values.every((score) => score == null)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final int lowestScore = players
|
||||
.map((player) => scores[player.id]?.score)
|
||||
.whereType<int>()
|
||||
.reduce((min, score) => score < min ? score : min);
|
||||
|
||||
return players.where((player) {
|
||||
final playerScore = scores[player.id];
|
||||
if (playerScore == null) return false;
|
||||
return playerScore.score == lowestScore;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user