From 7a0959c2635083157db0275bc3b39be4c75991b3 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 29 Apr 2025 18:56:44 +0200 Subject: [PATCH 1/9] Refactored variable & changing limit from 101 to 101 --- lib/data/game_session.dart | 12 ++++++------ lib/views/create_game_view.dart | 6 ++++-- lib/views/main_menu_view.dart | 18 +++++++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index a8a9513..0bddc69 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -1,7 +1,7 @@ /// This class represents a game session for the Cabo game. /// [gameTitle] is the title of the game. /// [players] is a string list of player names. -/// [pointLimit] is a boolean indicating if the game has the +/// [gameHasPointLimit] is a boolean indicating if the game has the /// default point limit of 101 points or not. /// [createdAt] is the timestamp of when the game session was created. /// [round] is the current round number. @@ -10,7 +10,7 @@ class GameSession { final DateTime createdAt = DateTime.now(); final String gameTitle; - final bool pointLimit; + final bool gameHasPointLimit; final List players; List> playerScores = List.generate(5, (_) => [0, 0]); int round = 1; @@ -20,14 +20,14 @@ class GameSession { GameSession({ required this.gameTitle, required this.players, - required this.pointLimit, + required this.gameHasPointLimit, }); @override String toString() { return ('GameSession: [gameTitle: $gameTitle, ' 'players: $players, ' - 'round: $round, pointLimit: $pointLimit, ' + 'round: $round, pointLimit: $gameHasPointLimit, ' 'playerScores: $playerScores]'); } @@ -106,9 +106,9 @@ class GameSession { for (int j = 1; j < playerScores[i].length; j++) { playerScores[i][0] += playerScores[i][j]; } - if (pointLimit && playerScores[i][0] > 101) { + if (gameHasPointLimit && playerScores[i][0] > 100) { finished = true; - print('${players[i]} hat die 101 Punkte ueberschritten, ' + print('${players[i]} hat die 100 Punkte ueberschritten, ' 'deswegen wurde das Spiel beendet'); _determineWinner(); } diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index dd48597..0592629 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -131,7 +131,8 @@ class _CreateGameState extends State { showCupertinoDialog( context: context, builder: (context) => CupertinoAlertDialog( - title: const Text('Maximale Spielerzahl erreicht'), + title: + const Text('Maximale Spielerzahl erreicht'), content: const Text( 'Es können maximal 5 Spieler hinzugefügt ' 'werden.'), @@ -276,7 +277,8 @@ class _CreateGameState extends State { GameSession gameSession = GameSession( gameTitle: _gameTitleTextController.text, players: players, - pointLimit: selectedMode == '101 Pkt.' ? true : false, + gameHasPointLimit: + selectedMode == '101 Pkt.' ? true : false, ); Navigator.push( context, diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index 0a5f479..102bf3c 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -18,36 +18,36 @@ class _MainMenuViewState extends State { GameSession( gameTitle: 'Spiel am 27.02.2025', players: ['Clara', 'Tobias', 'Yannik', 'Lena', 'Lekaia'], - pointLimit: true), + gameHasPointLimit: true), GameSession( gameTitle: 'Freundschaftsrunde', players: ['Felix', 'Jonas', 'Nils'], - pointLimit: false), + gameHasPointLimit: false), GameSession( gameTitle: 'Familienabend', players: ['Mama', 'Papa', 'Lisa'], - pointLimit: true, + gameHasPointLimit: true, ), GameSession( gameTitle: 'Turnier 1. Runde', players: ['Tim', 'Max', 'Sophie', 'Lena'], - pointLimit: false), + gameHasPointLimit: false), GameSession( gameTitle: '2 Namen max length', players: ['Heinrich', 'Johannes'], - pointLimit: true), + gameHasPointLimit: true), GameSession( gameTitle: '3 Namen max length', players: ['Benjamin', 'Stefanie', 'Wolfgang'], - pointLimit: false), + gameHasPointLimit: false), GameSession( gameTitle: '4 Namen max length', players: ['Leonhard', 'Mathilde', 'Bernhard', 'Gerlinde'], - pointLimit: true), + gameHasPointLimit: true), GameSession( gameTitle: '5 Namen max length', players: ['Hartmuth', 'Elisabet', 'Rosalind', 'Theresia', 'Karoline'], - pointLimit: false), + gameHasPointLimit: false), ]; @override @@ -97,7 +97,7 @@ class _MainMenuViewState extends State { style: const TextStyle(fontSize: 14), ) : Text( - 'Modus: ${_translateGameMode(session.pointLimit)}', + 'Modus: ${_translateGameMode(session.gameHasPointLimit)}', style: const TextStyle(fontSize: 14), ), trailing: Row( From 0e09f15c1436fad987cfe3a77219f12c69db9a60 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 29 Apr 2025 19:32:45 +0200 Subject: [PATCH 2/9] Refactoring --- lib/views/active_game_view.dart | 6 +++--- lib/views/main_menu_view.dart | 4 ++-- lib/views/round_view.dart | 11 ++++++----- pubspec.yaml | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index 14d4166..ba73ca9 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -66,7 +66,7 @@ class _ActiveGameViewState extends State { ), ListView.builder( shrinkWrap: true, - itemCount: widget.gameSession.round, + itemCount: widget.gameSession.roundNumber, itemBuilder: (BuildContext context, int index) { return Padding( padding: const EdgeInsets.all(1), @@ -74,8 +74,8 @@ class _ActiveGameViewState extends State { title: Text( 'Runde ${index + 1}', ), - trailing: index + 1 != widget.gameSession.round || - widget.gameSession.finished == true + trailing: index + 1 != widget.gameSession.roundNumber || + widget.gameSession.isGameFinished == true ? (const Text('\u{2705}', style: TextStyle(fontSize: 22))) : const Text('\u{23F3}', diff --git a/lib/views/main_menu_view.dart b/lib/views/main_menu_view.dart index 102bf3c..d89a91e 100644 --- a/lib/views/main_menu_view.dart +++ b/lib/views/main_menu_view.dart @@ -91,7 +91,7 @@ class _MainMenuViewState extends State { padding: const EdgeInsets.symmetric(vertical: 10.0), child: CupertinoListTile( title: Text(session.gameTitle), - subtitle: session.finished == true + subtitle: session.isGameFinished == true ? Text( '\u{1F947} ${session.winner}', style: const TextStyle(fontSize: 14), @@ -102,7 +102,7 @@ class _MainMenuViewState extends State { ), trailing: Row( children: [ - Text('${session.round}'), + Text('${session.roundNumber}'), const SizedBox(width: 3), const Icon( CupertinoIcons.arrow_2_circlepath_circle_fill), diff --git a/lib/views/round_view.dart b/lib/views/round_view.dart index 16dc226..c3f39b6 100644 --- a/lib/views/round_view.dart +++ b/lib/views/round_view.dart @@ -41,8 +41,8 @@ class _RoundViewState extends State { @override void initState() { print('=== Runde ${widget.roundNumber} geöffnet ==='); - if (widget.roundNumber < widget.gameSession.round || - widget.gameSession.finished == true) { + if (widget.roundNumber < widget.gameSession.roundNumber || + widget.gameSession.isGameFinished == true) { print('Die Runde ${widget.roundNumber} wurde bereits gespielt, deshalb ' 'werden die alten Punktestaende angezeigt'); @@ -282,7 +282,7 @@ class _RoundViewState extends State { onPressed: _areRoundInputsValid() ? () { _finishRound(); - if (widget.gameSession.finished == true) { + if (widget.gameSession.isGameFinished == true) { Navigator.pop(context, widget.gameSession); } else { Navigator.pushReplacement( @@ -351,7 +351,8 @@ class _RoundViewState extends State { print('===================================='); print('Runde ${widget.roundNumber} beendet'); // The shown round is smaller than the newest round - if (widget.gameSession.round < widget.gameSession.playerScores[0].length) { + if (widget.gameSession.roundNumber < + widget.gameSession.playerScores[0].length) { print('Da diese Runde bereits gespielt wurde, werden die alten ' 'Punktestaende ueberschrieben'); print('Alte Punktestaende:'); @@ -360,7 +361,7 @@ class _RoundViewState extends State { _calculateScoredPoints(); widget.gameSession.sumPoints(); - if (widget.gameSession.finished == true) { + if (widget.gameSession.isGameFinished == true) { print('Das Spiel ist beendet'); } else { if (widget.roundNumber >= widget.gameSession.playerScores[0].length - 1) { diff --git a/pubspec.yaml b/pubspec.yaml index 73d0ca2..e6b6584 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game CABO" publish_to: 'none' -version: 0.1.3+55 +version: 0.1.3+57 environment: sdk: ^3.5.4 From 22eca2f2d4012ef837e01b888049720fd5c8ca97 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 29 Apr 2025 19:33:07 +0200 Subject: [PATCH 3/9] Corrected sumPoints Method --- lib/data/game_session.dart | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index 0bddc69..66a00c4 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -4,8 +4,8 @@ /// [gameHasPointLimit] is a boolean indicating if the game has the /// default point limit of 101 points or not. /// [createdAt] is the timestamp of when the game session was created. -/// [round] is the current round number. -/// [finished] is a boolean indicating if the game session is finished. +/// [roundNumber] is the current round number. +/// [isGameFinished] is a boolean indicating if the game session is finished. /// [winner] is the name of the player who won the game. class GameSession { final DateTime createdAt = DateTime.now(); @@ -13,8 +13,8 @@ class GameSession { final bool gameHasPointLimit; final List players; List> playerScores = List.generate(5, (_) => [0, 0]); - int round = 1; - bool finished = false; + int roundNumber = 1; + bool isGameFinished = false; String winner = ''; GameSession({ @@ -25,10 +25,10 @@ class GameSession { @override String toString() { - return ('GameSession: [gameTitle: $gameTitle, ' - 'players: $players, ' - 'round: $round, pointLimit: $gameHasPointLimit, ' - 'playerScores: $playerScores]'); + return ('GameSession: [createdAt: $createdAt, gameTitle: $gameTitle, ' + 'gameHasPointLimit: $gameHasPointLimit, players: $players, ' + 'playerScores: $playerScores, roundNumber: $roundNumber, ' + 'isGameFinished: $isGameFinished, winner: $winner]'); } // FIXME Debug @@ -55,7 +55,7 @@ class GameSession { /// Increases the round number by 1. void increaseRound() { - round++; + roundNumber++; } /// Expands the player score lists by adding a new score of 0 for each player. @@ -106,12 +106,22 @@ class GameSession { for (int j = 1; j < playerScores[i].length; j++) { playerScores[i][0] += playerScores[i][j]; } - if (gameHasPointLimit && playerScores[i][0] > 100) { - finished = true; - print('${players[i]} hat die 100 Punkte ueberschritten, ' - 'deswegen wurde das Spiel beendet'); - _determineWinner(); + if (gameHasPointLimit) { + print('playerScores[i][0]: ${playerScores[i][0]}'); + if (playerScores[i][0] == 100) { + print('${players[i]} hat genau 100 Punkte erreicht, ' + 'seine Punkte werden auf 50 Punkte reduziert'); + playerScores[i][playerScores[i].length - 1] -= + 50; // Subtract 50 from this round + playerScores[i][0] -= 50; // Subtract 50 from the sum + } else if (playerScores[i][0] > 100) { + isGameFinished = true; + print('${players[i]} hat die 100 Punkte ueberschritten, ' + 'deswegen wurde das Spiel beendet'); + _determineWinner(); + } } } + print('GameSession: sumPoints: $playerScores'); } } From c6ce5e8167e6e3a3ee6cd93db010dd2a35204a19 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 29 Apr 2025 19:33:39 +0200 Subject: [PATCH 4/9] Changed mode description text and return type of widget --- lib/views/create_game_view.dart | 15 ++++++++++----- lib/views/mode_selection_view.dart | 9 ++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 0592629..3c5c727 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -18,8 +18,12 @@ class _CreateGameState extends State { ]; final TextEditingController _gameTitleTextController = TextEditingController(); + + /// Maximum number of players allowed in the game. final int maxPlayers = 5; - String? selectedMode; // Variable für den ausgewählten Spielmodus + + /// Variable to store the selected game mode. + bool? selectedMode; @override Widget build(BuildContext context) { @@ -45,7 +49,7 @@ class _CreateGameState extends State { padding: const EdgeInsets.fromLTRB(10, 10, 10, 0), child: CupertinoTextField( decoration: const BoxDecoration(), - maxLength: 8, + maxLength: 16, prefix: const Text('Name'), textAlign: TextAlign.right, placeholder: 'Titel des Spiels', @@ -62,7 +66,9 @@ class _CreateGameState extends State { suffix: Row( children: [ Text( - selectedMode ?? 'Wähle einen Modus', + selectedMode == null + ? 'Wähle einen Modus' + : (selectedMode! ? '101 Punkte' : 'Unbegrenzt'), ), const SizedBox(width: 3), const CupertinoListTileChevron(), @@ -277,8 +283,7 @@ class _CreateGameState extends State { GameSession gameSession = GameSession( gameTitle: _gameTitleTextController.text, players: players, - gameHasPointLimit: - selectedMode == '101 Pkt.' ? true : false, + gameHasPointLimit: selectedMode!, ); Navigator.push( context, diff --git a/lib/views/mode_selection_view.dart b/lib/views/mode_selection_view.dart index 70e78fb..13a4b99 100644 --- a/lib/views/mode_selection_view.dart +++ b/lib/views/mode_selection_view.dart @@ -18,13 +18,12 @@ class ModeSelectionMenu extends StatelessWidget { child: CupertinoListTile( title: Text('101 Punkte', style: Styles.modeTitle), subtitle: const Text( - 'Es wird solange gespielt, bis einer Spieler die 101 Punkte ' - 'genau erreicht oder überschreitet.', + 'Es wird solange gespielt, bis einer Spieler mehr als 100 Punkte erreicht', style: Styles.modeDescription, maxLines: 3, ), onTap: () { - Navigator.pop(context, '101 Punkte'); + Navigator.pop(context, true); }, ), ), @@ -34,12 +33,12 @@ class ModeSelectionMenu extends StatelessWidget { title: Text('Unbegrenzt', style: theme.modeTitle), subtitle: const Text( 'Dem Spiel sind keine Grenzen gesetzt. Es wird so lange ' - 'gespielt, bis die Spieler keine Lust mehr haben.', + 'gespielt, bis Ihr keine Lust mehr habt.', style: Styles.modeDescription, maxLines: 3, ), onTap: () { - Navigator.pop(context, 'Unbegrenzt'); + Navigator.pop(context, false); }, ), ), From 18606508dc9ceaedf11540fb60c9ab2a4f938e7d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Tue, 29 Apr 2025 23:57:27 +0200 Subject: [PATCH 5/9] Implemented new Round data class --- lib/data/round.dart | 19 +++++++++++++++++++ pubspec.yaml | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 lib/data/round.dart diff --git a/lib/data/round.dart b/lib/data/round.dart new file mode 100644 index 0000000..76b444b --- /dev/null +++ b/lib/data/round.dart @@ -0,0 +1,19 @@ +/// This class represents a single round in the game. +/// It is stored within the [GameSession] class. +/// [roundNum] is the number of the round its reppresenting. +/// [scores] is a list of the actual scores the players got. +/// [scoreUpdates] is a list of how the players scores updated this round. +/// [kamikaze] is the index of the player who got kamikaze. If no one got +/// kamikaze, this value is null. +class Round { + final int roundNum; + List scores; + List scoreUpdates; + int? kamikaze; + + Round( + {required this.roundNum, + required this.scores, + required this.scoreUpdates, + this.kamikaze}); +} diff --git a/pubspec.yaml b/pubspec.yaml index e6b6584..048a6bf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game CABO" publish_to: 'none' -version: 0.1.3+57 +version: 0.1.3+63 environment: sdk: ^3.5.4 From 9827a983e7cf3db46e92576c3a4068f077177647 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 30 Apr 2025 00:06:13 +0200 Subject: [PATCH 6/9] Implemented new class structure --- lib/data/game_session.dart | 248 +++++++++++++++++++++++++++---------- lib/views/round_view.dart | 152 +++-------------------- 2 files changed, 200 insertions(+), 200 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index 66a00c4..5cf54e3 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -1,3 +1,5 @@ +import 'package:cabo_counter/data/round.dart'; + /// This class represents a game session for the Cabo game. /// [gameTitle] is the title of the game. /// [players] is a string list of player names. @@ -12,36 +14,27 @@ class GameSession { final String gameTitle; final bool gameHasPointLimit; final List players; - List> playerScores = List.generate(5, (_) => [0, 0]); + late List playerScores; + List roundList = []; int roundNumber = 1; bool isGameFinished = false; String winner = ''; GameSession({ required this.gameTitle, - required this.players, required this.gameHasPointLimit, - }); + required this.players, + }) { + playerScores = List.filled(players.length, 0); + } @override String toString() { return ('GameSession: [createdAt: $createdAt, gameTitle: $gameTitle, ' 'gameHasPointLimit: $gameHasPointLimit, players: $players, ' - 'playerScores: $playerScores, roundNumber: $roundNumber, ' - 'isGameFinished: $isGameFinished, winner: $winner]'); - } - - // FIXME Debug - /// Returns a string representation of the scores for a specific round. - /// The method takes a round number as a parameter and returns a string - /// containing the name of each player and their corressponding score in - /// the given round. - String printRoundScores(int round) { - String result = ''; - for (int i = 0; i < players.length; i++) { - result += '${players[i]}: ${playerScores[i][round]}\n'; - } - return result; + 'playerScores: $playerScores, roundList: $roundList, ' + 'roundNumber: $roundNumber, isGameFinished: $isGameFinished, ' + 'winner: $winner]'); } /// Returns the length of all player names combined. @@ -53,75 +46,200 @@ class GameSession { return length; } - /// Increases the round number by 1. - void increaseRound() { - roundNumber++; + /// Assigns 50 points to all players except the kamikaze player. + /// [kamikazePlayerIndex] is the index of the kamikaze player. + void applyKamikaze(int roundNum, int kamikazePlayerIndex) { + List roundScores = List.generate(players.length, (_) => 0); + List scoreUpdates = List.generate(players.length, (_) => 0); + for (int i = 0; i < roundScores.length; i++) { + if (i != kamikazePlayerIndex) { + scoreUpdates[i] += 50; + } + } + addRoundScoresToList( + roundNum, roundScores, scoreUpdates, kamikazePlayerIndex); } - /// Expands the player score lists by adding a new score of 0 for each player. - /// This method is called when a new round starts so the lists in the - /// active game view expands - void expandPlayerScoreLists() { - for (int i = 0; i < playerScores.length; i++) { - playerScores[i].add(0); + /// Checks the scores of the current round and assigns points to the players. + /// There are three possible outcomes of a round: + /// + /// **Case 1**
+ /// The player who said CABO has the lowest score. They receive 0 points. + /// Every other player gets their round score. + /// + /// **Case 2**
+ /// The player who said CABO does not have the lowest score. + /// They receive 5 extra points added to their round score. + /// Every player with the lowest score gets 0 points. + /// Every other player gets their round score. + void calculateScoredPoints( + int roundNum, List roundScores, int caboPlayerIndex) { + print('Spieler: $players'); + print('Punkte: $roundScores'); + print('${players[caboPlayerIndex]} hat mit ${roundScores[caboPlayerIndex]} ' + 'Punkten CABO gesagt'); + + /// List of the index of the player(s) with the lowest score + List lowestScoreIndex = _getLowestScoreIndex(roundScores); + print('Folgende Spieler haben die niedrigsten Punte:'); + for (int i in lowestScoreIndex) { + print('${players[i]} (${roundScores[i]} Punkte)'); } + // The player who said CABO is one of the players which have the + // fewest points. + if (lowestScoreIndex.contains(caboPlayerIndex)) { + print('${players[caboPlayerIndex]} hat CABO gesagt ' + 'und bekommt 0 Punkte'); + print('Alle anderen Spieler bekommen ihre Punkte'); + _assignPoints(roundNum, roundScores, [caboPlayerIndex]); + } else { + // A player other than the one who said CABO has the fewest points. + print('${players[caboPlayerIndex]} hat CABO gesagt, ' + 'jedoch nicht die wenigsten Punkte.'); + print('Folgende:r Spieler haben die wenigsten Punkte:'); + for (int i in lowestScoreIndex) { + print('${players[i]}: ${roundScores[i]} Punkte'); + } + _assignPoints(roundNum, roundScores, lowestScoreIndex, caboPlayerIndex); + } + } + + /// Returns the index of the player with the lowest score. If there are + /// multiple players with the same lowest score, all of them are returned. + /// [roundScores] is a list of the scores of all players in the current round. + List _getLowestScoreIndex(List roundScores) { + int lowestScore = roundScores[0]; + List lowestScoreIndex = [0]; + + for (int i = 1; i < roundScores.length; i++) { + if (roundScores[i] < lowestScore) { + lowestScore = roundScores[i]; + lowestScoreIndex = [i]; + } else if (roundScores[i] == lowestScore) { + lowestScoreIndex.add(i); + } + } + return lowestScoreIndex; + } + + /// Assigns points to the players based on the scores of the current round. + /// [roundNum] is the number of the current round. + /// [roundScores] is the raw list of the scores of all players in the current round. + /// [winnerIndex] is the index of the player who receives 5 extra points + void _assignPoints(int roundNum, List roundScores, List winnerIndex, + [int loserIndex = -1]) { + /// List of the updates for every player score + List scoreUpdates = [...roundScores]; + print('Folgende Punkte wurden aus der Runde übernommen:'); + for (int i = 0; i < scoreUpdates.length; i++) { + print('${players[i]}: ${scoreUpdates[i]}'); + } + for (int i in winnerIndex) { + print('${players[i]} hat gewonnen und bekommt 0 Punkte'); + scoreUpdates[i] = 0; + } + if (loserIndex != -1) { + print('${players[loserIndex]} bekommt 5 Fehlerpunkte'); + scoreUpdates[loserIndex] += 5; + } + print('Aktualisierte Punkte:'); + for (int i = 0; i < scoreUpdates.length; i++) { + print('${players[i]}: ${scoreUpdates[i]}'); + } + print('scoreUpdates: $scoreUpdates, roundScores: $roundScores'); + addRoundScoresToList(roundNum, roundScores, scoreUpdates); } /// Sets the scores of the players for a specific round. /// This method takes a list of round scores and a round number as parameters. - /// It then replaces the values for the given [roundNumber] in the + /// It then replaces the values for the given [roundNum] in the /// playerScores. Its important that each index of the [roundScores] list /// corresponds to the index of the player in the [playerScores] list. - void addRoundScoresToScoreList(List roundScores, int roundNumber) { - print('addRoundScoresToScoreList: $roundScores'); - for (int i = 0; i < roundScores.length; i++) { - playerScores[i][roundNumber] = (roundScores[i]); + void addRoundScoresToList( + int roundNum, List roundScores, List scoreUpdates, + [int? kamikazePlayerIndex]) { + Round newRound = Round( + roundNum: roundNum, + scores: roundScores, + scoreUpdates: scoreUpdates, + kamikaze: kamikazePlayerIndex, + ); + if (roundNum > roundList.length) { + roundList.add(newRound); + } else { + roundList[roundNum - 1] = newRound; } } + /// This method updates the points of each player after a round. + /// It first uses the _sumPoints() method to calculate the total points of each player. + /// Then, it checks if any player has reached 100 points. If so, it marks + /// that player as having reached 100 points in that corresponding [Round] object. + /// If the game has the point limit activated, it first applies the + /// _subtractPointsForReachingHundred() method to subtract 50 points + /// for every time a player reached 100 points in the game. + /// It then checks if any player has exceeded 100 points. If so, it sets + /// isGameFinished to true and calls the _setWinner() method to determine + /// the winner. + void updatePoints() { + _sumPoints(); + if (gameHasPointLimit) { + _checkHundredPointsReached(); + + for (int i = 0; i < playerScores.length; i++) { + if (playerScores[i] > 100) { + isGameFinished = true; + print('${players[i]} hat die 100 Punkte ueberschritten, ' + 'deswegen wurde das Spiel beendet'); + _setWinner(); + } + } + } + } + + /// Sums up the points of all players and stores the result in the + /// playerScores list. + void _sumPoints() { + print('_sumPoints()'); + for (int i = 0; i < players.length; i++) { + playerScores[i] = 0; + for (int j = 0; j < roundList.length; j++) { + playerScores[i] += roundList[j].scoreUpdates[i]; + } + } + } + + /// Checks if a player has reached 100 points in the current round. + /// If so, it updates the [scoreUpdate] List by subtracting 50 points from + /// the corresponding round update. + void _checkHundredPointsReached() { + for (int i = 0; i < players.length; i++) { + if (playerScores[i] == 100) { + print('${players[i]} hat genau 100 Punkte erreicht und bekommt ' + 'deswegen 50 Punkte abgezogen'); + roundList[roundNumber - 1].scoreUpdates[i] -= 50; + } + } + _sumPoints(); + } + /// Determines the winner of the game session. /// It iterates through the player scores and finds the player /// with the lowest score. - void _determineWinner() { - int score = playerScores[0][0]; + void _setWinner() { + int score = playerScores[0]; String lowestPlayer = players[0]; for (int i = 0; i < players.length; i++) { - if (playerScores[i][0] < score) { - score = playerScores[i][0]; + if (playerScores[i] < score) { + score = playerScores[i]; lowestPlayer = players[i]; } } winner = lowestPlayer; } - /// Summarizes the points of all players in the first index of their - /// score list. The method clears the first index of each player score - /// list and then sums up the points from the second index to the last - /// index. It then stores the result in the first index. This method is - /// used to update the total points of each player after a round. - /// If a player reaches the 101 points, - void sumPoints() { - for (int i = 0; i < playerScores.length; i++) { - playerScores[i][0] = 0; - for (int j = 1; j < playerScores[i].length; j++) { - playerScores[i][0] += playerScores[i][j]; - } - if (gameHasPointLimit) { - print('playerScores[i][0]: ${playerScores[i][0]}'); - if (playerScores[i][0] == 100) { - print('${players[i]} hat genau 100 Punkte erreicht, ' - 'seine Punkte werden auf 50 Punkte reduziert'); - playerScores[i][playerScores[i].length - 1] -= - 50; // Subtract 50 from this round - playerScores[i][0] -= 50; // Subtract 50 from the sum - } else if (playerScores[i][0] > 100) { - isGameFinished = true; - print('${players[i]} hat die 100 Punkte ueberschritten, ' - 'deswegen wurde das Spiel beendet'); - _determineWinner(); - } - } - } - print('GameSession: sumPoints: $playerScores'); + /// Increases the round number by 1. + void increaseRound() { + roundNumber++; } } diff --git a/lib/views/round_view.dart b/lib/views/round_view.dart index c3f39b6..331cb81 100644 --- a/lib/views/round_view.dart +++ b/lib/views/round_view.dart @@ -43,15 +43,17 @@ class _RoundViewState extends State { print('=== Runde ${widget.roundNumber} geöffnet ==='); if (widget.roundNumber < widget.gameSession.roundNumber || widget.gameSession.isGameFinished == true) { - print('Die Runde ${widget.roundNumber} wurde bereits gespielt, deshalb ' - 'werden die alten Punktestaende angezeigt'); + print( + 'Diese wurde bereits gespielt, deshalb werden die alten Punktestaende angezeigt'); // If the current round has already been played, the text fields // are filled with the scores from this round for (int i = 0; i < _scoreControllerList.length; i++) { _scoreControllerList[i].text = - gameSession.playerScores[i][widget.roundNumber].toString(); + gameSession.roundList[widget.roundNumber - 1].scores[i].toString(); } + _kamikazePlayerIndex = + gameSession.roundList[widget.roundNumber - 1].kamikaze; } super.initState(); } @@ -179,7 +181,7 @@ class _RoundViewState extends State { backgroundColor: CupertinoColors.secondaryLabel, title: Row(children: [Text(name)]), subtitle: Text( - '${widget.gameSession.playerScores[index][0]}' + '${widget.gameSession.playerScores[index]}' ' Punkte'), trailing: Row( children: [ @@ -343,7 +345,7 @@ class _RoundViewState extends State { } /// Finishes the current round. - /// Calls the [_calculateScoredPoints()] method to calculate the points for + /// It first determines, ifCalls the [_calculateScoredPoints()] method to calculate the points for /// every player. If the round is the highest round played in this game, /// it expands the player score lists. At the end it updates the score /// array for the game. @@ -351,150 +353,30 @@ class _RoundViewState extends State { print('===================================='); print('Runde ${widget.roundNumber} beendet'); // The shown round is smaller than the newest round - if (widget.gameSession.roundNumber < - widget.gameSession.playerScores[0].length) { + if (widget.roundNumber < widget.gameSession.roundNumber) { print('Da diese Runde bereits gespielt wurde, werden die alten ' 'Punktestaende ueberschrieben'); - print('Alte Punktestaende:'); - print(gameSession.printRoundScores(widget.roundNumber)); } - - _calculateScoredPoints(); - widget.gameSession.sumPoints(); - if (widget.gameSession.isGameFinished == true) { - print('Das Spiel ist beendet'); - } else { - if (widget.roundNumber >= widget.gameSession.playerScores[0].length - 1) { - gameSession.expandPlayerScoreLists(); - print('Das Punkte-Array wurde erweitert'); - } - widget.gameSession.increaseRound(); - } - - print('Die Punktesummen wurden aktualisiert'); - } - - /// Checks the scores of the current round and assigns points to the players. - /// There are three possible outcomes of a round: - /// - /// **Case 1**
- /// One player has Kamikaze. This player receives 0 points. Every other player - /// receives 50 points. - /// - /// **Case 2**
- /// The player who said CABO has the lowest score. They receive 0 points. - /// Every other player gets their round score. - /// - /// **Case 3**
- /// The player who said CABO does not have the lowest score. - /// They receive 5 extra points added to their round score. - /// Every player with the lowest score gets 0 points. - /// Every other player gets their round score. - void _calculateScoredPoints() { - print('Spieler: ${gameSession.players}'); - - // A player has Kamikaze if (_kamikazePlayerIndex != null) { print('${widget.gameSession.players[_kamikazePlayerIndex!]} hat Kamikaze ' 'und bekommt 0 Punkte'); print('Alle anderen Spieler bekommen 50 Punkte'); - _applyKamikaze(_kamikazePlayerIndex!, - List.generate(widget.gameSession.players.length, (index) => 0)); + widget.gameSession + .applyKamikaze(widget.roundNumber, _kamikazePlayerIndex!); } else { - // List of the scores of the current round List roundScores = []; for (TextEditingController c in _scoreControllerList) { if (c.text.isNotEmpty) roundScores.add(int.parse(c.text)); } - - print('Punkte: $roundScores'); - print('${gameSession.players[_caboPlayerIndex]} hat CABO gesagt'); - print('${gameSession.players[_caboPlayerIndex]} hat ' - '${roundScores[_caboPlayerIndex]} Punkte'); - - /// List of the index of the player(s) with the lowest score - List lowestScoreIndex = _getLowestScoreIndex(roundScores); - print('Folgende Spieler haben die niedrigsten Punte:'); - for (int i in lowestScoreIndex) { - print('${widget.gameSession.players[i]} (${roundScores[i]} Punkte)'); - } - // The player who said CABO is one of the players which have the - // fewest points. - if (lowestScoreIndex.contains(_caboPlayerIndex)) { - print('${widget.gameSession.players[_caboPlayerIndex]} hat CABO gesagt ' - 'und bekommt 0 Punkte'); - print('Alle anderen Spieler bekommen ihre Punkte'); - _assignPoints([_caboPlayerIndex], -1, roundScores); - } else { - // A player other than the one who said CABO has the fewest points. - print( - '${widget.gameSession.players[_caboPlayerIndex]} hat CABO gesagt, ' - 'jedoch nicht die wenigsten Punkte.'); - print('Folgende:r Spieler haben die wenigsten Punkte:'); - for (int i in lowestScoreIndex) { - print('${widget.gameSession.players[i]}: ${roundScores[i]} Punkte'); - } - _assignPoints(lowestScoreIndex, _caboPlayerIndex, roundScores); - } + widget.gameSession.calculateScoredPoints( + widget.roundNumber, roundScores, _caboPlayerIndex); } - } - - /// Returns the index of the player with the lowest score. If there are - /// multiple players with the same lowest score, all of them are returned. - /// [roundScores] is a list of the scores of all players in the current round. - List _getLowestScoreIndex(List roundScores) { - int lowestScore = roundScores[0]; - List lowestScoreIndex = [0]; - - for (int i = 1; i < roundScores.length; i++) { - if (roundScores[i] < lowestScore) { - lowestScore = roundScores[i]; - lowestScoreIndex = [i]; - } else if (roundScores[i] == lowestScore) { - lowestScoreIndex.add(i); - } + widget.gameSession.updatePoints(); + if (widget.gameSession.isGameFinished == true) { + print('Das Spiel ist beendet'); + } else if (widget.roundNumber == widget.gameSession.roundNumber) { + widget.gameSession.increaseRound(); } - return lowestScoreIndex; - } - - /// Assigns 50 points to all players except the kamikaze player. - /// [kamikazePlayerIndex] is the index of the kamikaze player. - /// [roundScores] is the list of the scores of all players in the - /// current round. - void _applyKamikaze(int kamikazePlayerIndex, List roundScores) { - for (int i = 0; i < widget.gameSession.players.length; i++) { - if (i != kamikazePlayerIndex) { - roundScores[i] += 50; - } - } - gameSession.addRoundScoresToScoreList(roundScores, widget.roundNumber); - } - - /// Assigns points to the players based on the scores of the current round. - /// [winnerIndex] is the index of the player(s) who receive 0 points - /// [loserIndex] is the index of the player who receives 5 extra points - /// [roundScores] is the raw list of the scores of all players in the - /// current round. - void _assignPoints( - List winnnerIndex, int loserIndex, List roundScores) { - print('Folgende Punkte wurden aus der Runde übernommen:'); - for (int i = 0; i < roundScores.length; i++) { - print('${widget.gameSession.players[i]}: ${roundScores[i]}'); - } - for (int i in winnnerIndex) { - print( - '${widget.gameSession.players[i]} hat gewonnen und bekommt 0 Punkte'); - roundScores[i] = 0; - } - if (loserIndex != -1) { - print('${widget.gameSession.players[loserIndex]} bekommt 5 Fehlerpunkte'); - roundScores[loserIndex] += 5; - } - print('Aktualisierte Punkte:'); - for (int i = 0; i < roundScores.length; i++) { - print('${widget.gameSession.players[i]}: ${roundScores[i]}'); - } - gameSession.addRoundScoresToScoreList(roundScores, widget.roundNumber); } @override From a4f53acaf4863ee1bc9a63b2f78cbef0d16db329 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 30 Apr 2025 00:06:30 +0200 Subject: [PATCH 7/9] Small adjustments bc new data class --- lib/views/active_game_view.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/views/active_game_view.dart b/lib/views/active_game_view.dart index ba73ca9..59d3a1b 100644 --- a/lib/views/active_game_view.dart +++ b/lib/views/active_game_view.dart @@ -50,7 +50,7 @@ class _ActiveGameViewState extends State { trailing: Row( children: [ const SizedBox(width: 5), - Text('${widget.gameSession.playerScores[playerIndex][0]} ' + Text('${widget.gameSession.playerScores[playerIndex]} ' 'Punkte') ], ), @@ -109,8 +109,8 @@ class _ActiveGameViewState extends State { List.generate(widget.gameSession.players.length, (index) => index); // Sort the indices based on the summed points playerIndices.sort((a, b) { - int scoreA = widget.gameSession.playerScores[a][0]; - int scoreB = widget.gameSession.playerScores[b][0]; + int scoreA = widget.gameSession.playerScores[a]; + int scoreB = widget.gameSession.playerScores[b]; return scoreA.compareTo(scoreB); }); return playerIndices; From 8320e7191b2830a631c3b4fda5a1fd77b3dc5d3d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 30 Apr 2025 00:49:15 +0200 Subject: [PATCH 8/9] Small changes & documentation --- lib/data/game_session.dart | 15 ++++++++------- lib/data/round.dart | 10 +++++----- lib/views/round_view.dart | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index 5cf54e3..94cc87c 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -1,13 +1,14 @@ import 'package:cabo_counter/data/round.dart'; -/// This class represents a game session for the Cabo game. -/// [gameTitle] is the title of the game. -/// [players] is a string list of player names. -/// [gameHasPointLimit] is a boolean indicating if the game has the -/// default point limit of 101 points or not. +/// This class represents a game session for Cabo game. /// [createdAt] is the timestamp of when the game session was created. +/// [gameTitle] is the title of the game. +/// [gameHasPointLimit] is a boolean indicating if the game has the default +/// point limit of 101 points or not. +/// [players] is a string list of player names. +/// [playerScores] is a list of the summed scores of all players. /// [roundNumber] is the current round number. -/// [isGameFinished] is a boolean indicating if the game session is finished. +/// [isGameFinished] is a boolean indicating if the game has ended yet. /// [winner] is the name of the player who won the game. class GameSession { final DateTime createdAt = DateTime.now(); @@ -162,7 +163,7 @@ class GameSession { roundNum: roundNum, scores: roundScores, scoreUpdates: scoreUpdates, - kamikaze: kamikazePlayerIndex, + kamikazePlayerIndex: kamikazePlayerIndex, ); if (roundNum > roundList.length) { roundList.add(newRound); diff --git a/lib/data/round.dart b/lib/data/round.dart index 76b444b..1f03b33 100644 --- a/lib/data/round.dart +++ b/lib/data/round.dart @@ -3,17 +3,17 @@ /// [roundNum] is the number of the round its reppresenting. /// [scores] is a list of the actual scores the players got. /// [scoreUpdates] is a list of how the players scores updated this round. -/// [kamikaze] is the index of the player who got kamikaze. If no one got +/// [kamikazePlayerIndex] is the index of the player who got kamikaze. If no one got /// kamikaze, this value is null. class Round { final int roundNum; - List scores; - List scoreUpdates; - int? kamikaze; + final List scores; + final List scoreUpdates; + final int? kamikazePlayerIndex; Round( {required this.roundNum, required this.scores, required this.scoreUpdates, - this.kamikaze}); + this.kamikazePlayerIndex}); } diff --git a/lib/views/round_view.dart b/lib/views/round_view.dart index 331cb81..9520aa5 100644 --- a/lib/views/round_view.dart +++ b/lib/views/round_view.dart @@ -53,7 +53,7 @@ class _RoundViewState extends State { gameSession.roundList[widget.roundNumber - 1].scores[i].toString(); } _kamikazePlayerIndex = - gameSession.roundList[widget.roundNumber - 1].kamikaze; + gameSession.roundList[widget.roundNumber - 1].kamikazePlayerIndex; } super.initState(); } From 42f0dfe515ec3a5532d439f2160dbb3d9eefe452 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Wed, 30 Apr 2025 01:04:32 +0200 Subject: [PATCH 9/9] Removed prints & edited route --- lib/data/game_session.dart | 1 - lib/views/create_game_view.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/data/game_session.dart b/lib/data/game_session.dart index 94cc87c..0403822 100644 --- a/lib/data/game_session.dart +++ b/lib/data/game_session.dart @@ -201,7 +201,6 @@ class GameSession { /// Sums up the points of all players and stores the result in the /// playerScores list. void _sumPoints() { - print('_sumPoints()'); for (int i = 0; i < players.length; i++) { playerScores[i] = 0; for (int j = 0; j < roundList.length; j++) { diff --git a/lib/views/create_game_view.dart b/lib/views/create_game_view.dart index 3c5c727..2ffbe22 100644 --- a/lib/views/create_game_view.dart +++ b/lib/views/create_game_view.dart @@ -285,7 +285,7 @@ class _CreateGameState extends State { players: players, gameHasPointLimit: selectedMode!, ); - Navigator.push( + Navigator.pushReplacement( context, CupertinoPageRoute( builder: (context) => diff --git a/pubspec.yaml b/pubspec.yaml index e09b4e3..326e7ee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: cabo_counter description: "Mobile app for the card game Cabo" publish_to: 'none' -version: 0.1.3+63 +version: 0.1.3+65 environment: sdk: ^3.5.4