added comments and integration test
parent
f6fa31196e
commit
5ebe14df32
|
@ -8,15 +8,16 @@ void main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Main application widget
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
theme: halloweenTheme,
|
theme: halloweenTheme, // Apply custom theme
|
||||||
home: const PlayerRegistry(),
|
home: const PlayerRegistry(), // Set initial screen to PlayerRegistry
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false, // Disable debug banner
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
import 'package:werwolf/models/role.dart';
|
import 'package:werwolf/models/role.dart';
|
||||||
|
|
||||||
import 'player.dart';
|
import 'player.dart';
|
||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
|
// List to store player objects
|
||||||
List<Player> players = [];
|
List<Player> players = [];
|
||||||
|
|
||||||
|
// List to store player names
|
||||||
List playernames = [];
|
List playernames = [];
|
||||||
|
|
||||||
|
// Initial number of werewolves
|
||||||
int numWolves = 1;
|
int numWolves = 1;
|
||||||
|
|
||||||
|
// Map to store special roles and their activation status
|
||||||
Map specialRoles = <Role, bool>{};
|
Map specialRoles = <Role, bool>{};
|
||||||
|
|
||||||
|
// Constructor to initialize the game with player names
|
||||||
Game({required this.playernames}) {
|
Game({required this.playernames}) {
|
||||||
|
// Initialize specialRoles map, setting all special roles to false
|
||||||
for (Role role in Role.values) {
|
for (Role role in Role.values) {
|
||||||
if (role != Role.dorfbewohner && role != Role.werwolf) {
|
if (role != Role.dorfbewohner && role != Role.werwolf) {
|
||||||
specialRoles[role] = false;
|
specialRoles[role] = false;
|
||||||
|
@ -16,43 +24,64 @@ class Game {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to increment the number of werewolves
|
||||||
void incrementWolves() {
|
void incrementWolves() {
|
||||||
|
// Increment only if conditions are met: enough players and balance maintained
|
||||||
if (numWolves < playernames.length - 1 &&
|
if (numWolves < playernames.length - 1 &&
|
||||||
(playernames.length) >= ((numWolves + 1) * 3)) {
|
(playernames.length) >= ((numWolves + 1) * 3)) {
|
||||||
numWolves++;
|
numWolves++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to decrement the number of werewolves
|
||||||
void decrementWolves() {
|
void decrementWolves() {
|
||||||
|
// Decrement only if there's more than one werewolf
|
||||||
if (numWolves > 1) {
|
if (numWolves > 1) {
|
||||||
numWolves--;
|
numWolves--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to get the current number of werewolves
|
||||||
int getWolves() {
|
int getWolves() {
|
||||||
return numWolves;
|
return numWolves;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to get all players with their assigned roles
|
||||||
List<Player> getAllPlayers() {
|
List<Player> getAllPlayers() {
|
||||||
|
// Clear the players list to start fresh
|
||||||
players.clear();
|
players.clear();
|
||||||
|
|
||||||
|
// List to hold roles randomly assigned to players
|
||||||
List<Role> randomRoles = [];
|
List<Role> randomRoles = [];
|
||||||
|
|
||||||
|
// Add werewolf roles to the list
|
||||||
for (var i = 0; i < numWolves; i++) {
|
for (var i = 0; i < numWolves; i++) {
|
||||||
randomRoles.add(Role.werwolf);
|
randomRoles.add(Role.werwolf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add active special roles to the list
|
||||||
for (var specialRole in specialRoles.keys) {
|
for (var specialRole in specialRoles.keys) {
|
||||||
if (specialRoles[specialRole]) {
|
if (specialRoles[specialRole]) {
|
||||||
randomRoles.add(specialRole);
|
randomRoles.add(specialRole);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fill the remaining roles with dorfbewohner
|
||||||
for (var i = randomRoles.length; i < playernames.length; i++) {
|
for (var i = randomRoles.length; i < playernames.length; i++) {
|
||||||
randomRoles.add(Role.dorfbewohner);
|
randomRoles.add(Role.dorfbewohner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shuffle the roles to ensure randomness
|
||||||
randomRoles.shuffle();
|
randomRoles.shuffle();
|
||||||
|
|
||||||
|
// Assign roles to players and create Player objects
|
||||||
for (var playerName in playernames) {
|
for (var playerName in playernames) {
|
||||||
players
|
players
|
||||||
.add(Player(name: playerName, role: randomRoles.last, isDead: false));
|
.add(Player(name: playerName, role: randomRoles.last, isDead: false));
|
||||||
randomRoles.removeLast();
|
randomRoles.removeLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the list of players with their roles
|
||||||
return players;
|
return players;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
import 'package:werwolf/models/role.dart';
|
import 'package:werwolf/models/role.dart';
|
||||||
|
|
||||||
|
// Define a class named Player
|
||||||
class Player {
|
class Player {
|
||||||
|
// Declare a string variable to store the player's name
|
||||||
String name;
|
String name;
|
||||||
|
// Declare a variable of type Role to store the player's role
|
||||||
Role role;
|
Role role;
|
||||||
|
// Declare a boolean variable to indicate whether the player is dead
|
||||||
bool isDead;
|
bool isDead;
|
||||||
|
|
||||||
|
// Constructor for the Player class with required parameters for name, role, and isDead status
|
||||||
Player({required this.name, required this.role, required this.isDead});
|
Player({required this.name, required this.role, required this.isDead});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
|
// Enum representing different roles in the game
|
||||||
enum Role { dorfbewohner, werwolf, joker, seher, doctor }
|
enum Role { dorfbewohner, werwolf, joker, seher, doctor }
|
||||||
|
|
||||||
|
// Extension on the Role enum to provide string representations
|
||||||
extension RoleExtension on Role {
|
extension RoleExtension on Role {
|
||||||
|
// Getter to convert enum value to its string representation
|
||||||
String get stringValue {
|
String get stringValue {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case Role.dorfbewohner:
|
case Role.dorfbewohner:
|
||||||
return 'Dorfbewohner';
|
return 'Dorfbewohner'; // Returns 'Dorfbewohner' for the dorfbewohner role
|
||||||
case Role.werwolf:
|
case Role.werwolf:
|
||||||
return 'Werwolf';
|
return 'Werwolf'; // Returns 'Werwolf' for the werwolf role
|
||||||
case Role.joker:
|
case Role.joker:
|
||||||
return 'Joker';
|
return 'Joker'; // Returns 'Joker' for the joker role
|
||||||
case Role.seher:
|
case Role.seher:
|
||||||
return 'Seher';
|
return 'Seher'; // Returns 'Seher' for the seher role
|
||||||
case Role.doctor:
|
case Role.doctor:
|
||||||
return 'Doctor';
|
return 'Doctor'; // Returns 'Doctor' for the doctor role
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:werwolf/screens/gameboard.dart';
|
||||||
import '../models/player.dart';
|
import '../models/player.dart';
|
||||||
import '../models/role.dart';
|
import '../models/role.dart';
|
||||||
|
|
||||||
|
// FlipingCard is a StatefulWidget that takes a list of players as input
|
||||||
class FlipingCard extends StatefulWidget {
|
class FlipingCard extends StatefulWidget {
|
||||||
final List<Player> players;
|
final List<Player> players;
|
||||||
const FlipingCard({required this.players, super.key});
|
const FlipingCard({required this.players, super.key});
|
||||||
|
@ -15,17 +16,19 @@ class FlipingCard extends StatefulWidget {
|
||||||
State<FlipingCard> createState() => _FlipingCardState();
|
State<FlipingCard> createState() => _FlipingCardState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State class for FlipingCard
|
||||||
class _FlipingCardState extends State<FlipingCard> {
|
class _FlipingCardState extends State<FlipingCard> {
|
||||||
int index = 0;
|
int index = 0; // Index to keep track of the current player
|
||||||
|
|
||||||
late FlipCardController _controller;
|
late FlipCardController _controller; // Controller for the flip card
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_controller = FlipCardController();
|
_controller = FlipCardController(); // Initialize the flip card controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to render the content of the flip card
|
||||||
_renderContent(context) {
|
_renderContent(context) {
|
||||||
return Card(
|
return Card(
|
||||||
elevation: 0.0,
|
elevation: 0.0,
|
||||||
|
@ -56,7 +59,7 @@ class _FlipingCardState extends State<FlipingCard> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Text(
|
const Text(
|
||||||
'Klick um deine Rolle zu sehen!',
|
'Click to see your role!',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -124,14 +127,14 @@ class _FlipingCardState extends State<FlipingCard> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (index > 0 && index <= widget.players.length) {
|
if (index > 0 && index <= widget.players.length) {
|
||||||
index--;
|
index--; // Go to the previous player
|
||||||
if (!_controller.state!.isFront) {
|
if (!_controller.state!.isFront) {
|
||||||
_controller.toggleCardWithoutAnimation();
|
_controller.toggleCardWithoutAnimation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: const Text("Zurück"),
|
child: const Text("Back"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
|
@ -139,11 +142,12 @@ class _FlipingCardState extends State<FlipingCard> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (index >= 0 && index < widget.players.length - 1) {
|
if (index >= 0 && index < widget.players.length - 1) {
|
||||||
index++;
|
index++; // Go to the next player
|
||||||
if (!_controller.state!.isFront) {
|
if (!_controller.state!.isFront) {
|
||||||
_controller.toggleCardWithoutAnimation();
|
_controller.toggleCardWithoutAnimation();
|
||||||
}
|
}
|
||||||
} else if (index == widget.players.length - 1) {
|
} else if (index == widget.players.length - 1) {
|
||||||
|
// Navigate to the game board if it's the last player
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
|
@ -155,8 +159,8 @@ class _FlipingCardState extends State<FlipingCard> {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Text(index != widget.players.length - 1
|
child: Text(index != widget.players.length - 1
|
||||||
? "Nächster Spieler"
|
? "Next Player"
|
||||||
: "Spiel anfangen!"),
|
: "Start Game!"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import '../models/player.dart';
|
import '../models/player.dart';
|
||||||
import '../models/role.dart';
|
import '../models/role.dart';
|
||||||
|
|
||||||
|
// Main widget for displaying the player grid
|
||||||
class PlayerGridView extends StatefulWidget {
|
class PlayerGridView extends StatefulWidget {
|
||||||
final List<Player> players;
|
final List<Player> players;
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ class PlayerGridView extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PlayerGridViewState extends State<PlayerGridView> {
|
class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
bool isNight = true;
|
bool isNight = true; // Variable to track whether it is night or day
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -35,7 +36,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
isNight ? 'Nacht' : 'Tag',
|
isNight ? 'Nacht' : 'Tag', // Display whether it is night or day
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -44,21 +45,21 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.info),
|
icon: const Icon(Icons.info),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_showRolesDialog();
|
_showRolesDialog(); // Show dialog with player roles
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(FontAwesomeIcons.xmark),
|
icon: const Icon(FontAwesomeIcons.xmark),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.popUntil(context, ModalRoute.withName('/'));
|
Navigator.popUntil(context, ModalRoute.withName('/')); // Return to main screen
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: Container(
|
body: Container(
|
||||||
color: isNight
|
color: isNight
|
||||||
? const Color(0xff2d2d2d)
|
? const Color(0xff2d2d2d)
|
||||||
: const Color.fromARGB(255, 194, 216, 225),
|
: const Color.fromARGB(255, 194, 216, 225), // Set background color based on night/day
|
||||||
padding: const EdgeInsets.only(left: 15, right: 15),
|
padding: const EdgeInsets.only(left: 15, right: 15),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -66,7 +67,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
child: GridView.builder(
|
child: GridView.builder(
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount:
|
crossAxisCount:
|
||||||
MediaQuery.of(context).size.shortestSide < 600 ? 2 : 4,
|
MediaQuery.of(context).size.shortestSide < 600 ? 2 : 4, // Adjust grid based on screen size
|
||||||
mainAxisSpacing: 10,
|
mainAxisSpacing: 10,
|
||||||
crossAxisSpacing: 10,
|
crossAxisSpacing: 10,
|
||||||
),
|
),
|
||||||
|
@ -78,14 +79,14 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (!widget.players[index].isDead) {
|
if (!widget.players[index].isDead) {
|
||||||
_killPlayer(widget.players[index]);
|
_killPlayer(widget.players[index]); // Mark player as dead
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Card(
|
child: Card(
|
||||||
color: widget.players[index].isDead
|
color: widget.players[index].isDead
|
||||||
? Colors.grey
|
? Colors.grey
|
||||||
: Theme.of(context).colorScheme.primary,
|
: Theme.of(context).colorScheme.primary, // Change card color based on player status
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
@ -98,7 +99,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
),
|
),
|
||||||
if (widget.players[index].isDead)
|
if (widget.players[index].isDead)
|
||||||
const Icon(Icons.close,
|
const Icon(Icons.close,
|
||||||
color: Colors.red, size: 48),
|
color: Colors.red, size: 48), // Show icon if player is dead
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -113,7 +114,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 60, top: 10),
|
padding: const EdgeInsets.only(bottom: 60, top: 10),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: _changePhase,
|
onPressed: _changePhase, // Change phase between night and day
|
||||||
child: Text(isNight ? 'Tag skippen' : 'Nacht skippen'),
|
child: Text(isNight ? 'Tag skippen' : 'Nacht skippen'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -127,14 +128,14 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
if (isNight) {
|
if (isNight) {
|
||||||
if (player.role != Role.werwolf) {
|
if (player.role != Role.werwolf) {
|
||||||
player.isDead = true;
|
player.isDead = true;
|
||||||
_checkWinCondition();
|
_checkWinCondition(); // Check win condition after killing player
|
||||||
isNight = false;
|
isNight = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
player.isDead = true;
|
player.isDead = true;
|
||||||
_checkWinCondition();
|
_checkWinCondition(); // Check win condition after killing player
|
||||||
if (player.role == Role.joker) {
|
if (player.role == Role.joker) {
|
||||||
_showWinDialog('Der Joker hat gewonnen!');
|
_showWinDialog('Der Joker hat gewonnen!'); // Show win dialog for Joker
|
||||||
}
|
}
|
||||||
isNight = true;
|
isNight = true;
|
||||||
}
|
}
|
||||||
|
@ -142,11 +143,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _changePhase() {
|
void _changePhase() {
|
||||||
if (isNight) {
|
isNight = !isNight; // Toggle between night and day
|
||||||
isNight = false;
|
|
||||||
} else {
|
|
||||||
isNight = true;
|
|
||||||
}
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,9 +156,9 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
.length;
|
.length;
|
||||||
|
|
||||||
if (countWolves == 0) {
|
if (countWolves == 0) {
|
||||||
_showWinDialog('Die Dorfbewohner haben gewonnen!');
|
_showWinDialog('Die Dorfbewohner haben gewonnen!'); // Show win dialog for villagers
|
||||||
} else if (countWolves >= countVillagers) {
|
} else if (countWolves >= countVillagers) {
|
||||||
_showWinDialog('Die Werwölfe haben gewonnen!');
|
_showWinDialog('Die Werwölfe haben gewonnen!'); // Show win dialog for werewolves
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +173,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
TextButton(
|
TextButton(
|
||||||
child: const Text('Spiel beenden'),
|
child: const Text('Spiel beenden'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.popUntil(context, ModalRoute.withName('/'));
|
Navigator.popUntil(context, ModalRoute.withName('/')); // Return to main screen
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -217,7 +214,7 @@ class _PlayerGridViewState extends State<PlayerGridView> {
|
||||||
TextButton(
|
TextButton(
|
||||||
child: const Text('OK'),
|
child: const Text('OK'),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop(); // Close dialog
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,25 +1,28 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:werwolf/screens/settings.dart';
|
import 'package:werwolf/screens/settings.dart';
|
||||||
|
|
||||||
|
// Define the PlayerRegistry StatefulWidget
|
||||||
class PlayerRegistry extends StatefulWidget {
|
class PlayerRegistry extends StatefulWidget {
|
||||||
const PlayerRegistry({super.key});
|
const PlayerRegistry({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
// Create the state for the PlayerRegistry widget
|
||||||
// ignore: library_private_types_in_public_api
|
// ignore: library_private_types_in_public_api
|
||||||
_PlayerRegistryState createState() => _PlayerRegistryState();
|
_PlayerRegistryState createState() => _PlayerRegistryState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define the state for the PlayerRegistry widget
|
||||||
class _PlayerRegistryState extends State<PlayerRegistry> {
|
class _PlayerRegistryState extends State<PlayerRegistry> {
|
||||||
final TextEditingController _playerController = TextEditingController();
|
final TextEditingController _playerController = TextEditingController(); // Controller for player name input
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>(); // Key for form validation
|
||||||
String _errorMessage = "";
|
String _errorMessage = ""; // Error message string
|
||||||
List<String> playernames = [];
|
List<String> playernames = []; // List to store player names
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text("Werwolf"),
|
title: const Text("Werwolf"), // App bar title
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
|
@ -32,8 +35,8 @@ class _PlayerRegistryState extends State<PlayerRegistry> {
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
controller: _playerController,
|
controller: _playerController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
errorText: _errorMessage == "" ? null : _errorMessage,
|
errorText: _errorMessage == "" ? null : _errorMessage, // Display error message if exists
|
||||||
labelText: 'Spielername',
|
labelText: 'Spielername', // Label for text field
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).colorScheme.primary),
|
color: Theme.of(context).colorScheme.primary),
|
||||||
|
@ -54,14 +57,14 @@ class _PlayerRegistryState extends State<PlayerRegistry> {
|
||||||
onSubmitted: (value) {
|
onSubmitted: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (_playerController.text.isEmpty) {
|
if (_playerController.text.isEmpty) {
|
||||||
_errorMessage = "Spielername ist leer!";
|
_errorMessage = "Spielername ist leer!"; // Error for empty name
|
||||||
} else if (playernames.contains(value)) {
|
} else if (playernames.contains(value)) {
|
||||||
_errorMessage = "Dieser Spieler existiert bereits";
|
_errorMessage = "Dieser Spieler existiert bereits"; // Error for duplicate name
|
||||||
_playerController.clear();
|
_playerController.clear();
|
||||||
} else {
|
} else {
|
||||||
_errorMessage = "";
|
_errorMessage = "";
|
||||||
_playerController.clear();
|
_playerController.clear();
|
||||||
playernames.add(value);
|
playernames.add(value); // Add valid player name to list
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -73,15 +76,15 @@ class _PlayerRegistryState extends State<PlayerRegistry> {
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
playernames[index],
|
playernames[index], // Display player name
|
||||||
),
|
),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
playernames.remove(playernames[index]);
|
playernames.remove(playernames[index]); // Remove player name from list
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.remove)),
|
icon: const Icon(Icons.remove)), // Remove icon button
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -93,16 +96,16 @@ class _PlayerRegistryState extends State<PlayerRegistry> {
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => GameSettings(
|
builder: (context) => GameSettings(
|
||||||
playernames: playernames,
|
playernames: playernames, // Pass player names to next screen
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
setState(() {
|
setState(() {
|
||||||
_errorMessage = "Es müssen mindestens 6 Spieler sein!";
|
_errorMessage = "Es müssen mindestens 6 Spieler sein!"; // Error for not enough players
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: const Text('Spiel einstellen'),
|
child: const Text('Spiel einstellen'), // Button to start game settings
|
||||||
),
|
),
|
||||||
const Padding(padding: EdgeInsets.all(30))
|
const Padding(padding: EdgeInsets.all(30))
|
||||||
],
|
],
|
||||||
|
|
|
@ -4,6 +4,7 @@ import 'package:werwolf/screens/flippingcards.dart';
|
||||||
import '../models/game.dart';
|
import '../models/game.dart';
|
||||||
import '../models/role.dart';
|
import '../models/role.dart';
|
||||||
|
|
||||||
|
// Main widget for game settings
|
||||||
class GameSettings extends StatefulWidget {
|
class GameSettings extends StatefulWidget {
|
||||||
final List<String> playernames;
|
final List<String> playernames;
|
||||||
const GameSettings({required this.playernames, super.key});
|
const GameSettings({required this.playernames, super.key});
|
||||||
|
@ -17,7 +18,7 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
game = Game(playernames: widget.playernames);
|
game = Game(playernames: widget.playernames); // Initialize the game with player names
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(
|
title: Text(
|
||||||
"Werwolf",
|
"Werwolf",
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
style: Theme.of(context).textTheme.titleLarge, // Use large title style from theme
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
),
|
),
|
||||||
|
@ -36,8 +37,8 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Anzahl der Spieler ${widget.playernames.length}",
|
"Anzahl der Spieler ${widget.playernames.length}", // Display number of players
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
style: Theme.of(context).textTheme.titleLarge, // Use large title style from theme
|
||||||
),
|
),
|
||||||
const Divider(
|
const Divider(
|
||||||
height: 60,
|
height: 60,
|
||||||
|
@ -47,14 +48,13 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Anzahl der Werwölfe ${game.getWolves()}",
|
"Anzahl der Werwölfe ${game.getWolves()}", // Display number of werewolves
|
||||||
style:
|
style: Theme.of(context).textTheme.bodyLarge, // Use large body style from theme
|
||||||
Theme.of(context).textTheme.bodyLarge,
|
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
game.decrementWolves();
|
game.decrementWolves(); // Decrease the number of werewolves
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.remove, color: Colors.white),
|
icon: const Icon(Icons.remove, color: Colors.white),
|
||||||
|
@ -62,7 +62,7 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
game.incrementWolves();
|
game.incrementWolves(); // Increase the number of werewolves
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.add, color: Colors.white),
|
icon: const Icon(Icons.add, color: Colors.white),
|
||||||
|
@ -75,9 +75,8 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 8.0, bottom: 20),
|
padding: const EdgeInsets.only(top: 8.0, bottom: 20),
|
||||||
child: Text(
|
child: Text(
|
||||||
"Spezielle Rollen",
|
"Spezielle Rollen", // Display special roles section
|
||||||
style:
|
style: Theme.of(context).textTheme.titleLarge, // Use large title style from theme
|
||||||
Theme.of(context).textTheme.titleLarge,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
@ -89,22 +88,20 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
Role role = Role.values[index];
|
Role role = Role.values[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
role.stringValue,
|
role.stringValue, // Display role name
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.bodyLarge, // Use large body style from theme
|
||||||
.textTheme
|
|
||||||
.bodyLarge,
|
|
||||||
),
|
),
|
||||||
trailing: Switch(
|
trailing: Switch(
|
||||||
value: game.specialRoles[role],
|
value: game.specialRoles[role],
|
||||||
onChanged: (bool value) {
|
onChanged: (bool value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
game.specialRoles[role] = value;
|
game.specialRoles[role] = value; // Toggle special role
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return Container();
|
return Container(); // Return empty container if not a special role
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -113,13 +110,12 @@ class _GameSettingsState extends State<GameSettings> {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) => FlipingCard(players: game.getAllPlayers()), // Start game
|
||||||
FlipingCard(players: game.getAllPlayers()),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: const Text(
|
child: const Text(
|
||||||
'Spiel starten!',
|
'Spiel starten!', // Start game button text
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Padding(padding: EdgeInsets.all(30)),
|
const Padding(padding: EdgeInsets.all(30)),
|
||||||
|
|
47
pubspec.lock
47
pubspec.lock
|
@ -118,6 +118,11 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_driver:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
|
@ -147,6 +152,11 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.0.0"
|
||||||
|
fuchsia_remote_debug_protocol:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -171,6 +181,11 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
integration_test:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -283,6 +298,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.0"
|
version: "1.9.0"
|
||||||
|
platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: platform
|
||||||
|
sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.4"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -291,6 +314,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "1.5.1"
|
||||||
|
process:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: process
|
||||||
|
sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.2"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -384,6 +415,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
sync_http:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sync_http
|
||||||
|
sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -464,6 +503,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.5"
|
version: "2.4.5"
|
||||||
|
webdriver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webdriver
|
||||||
|
sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
webkit_inspection_protocol:
|
webkit_inspection_protocol:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -17,6 +17,8 @@ dev_dependencies:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_lints: ^2.0.0
|
flutter_lints: ^2.0.0
|
||||||
test: ^1.25.2
|
test: ^1.25.2
|
||||||
|
integration_test:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
import 'package:werwolf/main.dart' as app;
|
||||||
|
import 'package:werwolf/screens/playerregistry.dart';
|
||||||
|
import 'package:werwolf/screens/settings.dart';
|
||||||
|
import 'package:werwolf/screens/flippingcards.dart';
|
||||||
|
import 'package:werwolf/screens/gameboard.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
group('Werwolf Game Integration Tests', () {
|
||||||
|
testWidgets('Complete game flow', (WidgetTester tester) async {
|
||||||
|
app.main();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Ensure we are on the PlayerRegistry screen
|
||||||
|
expect(find.byType(PlayerRegistry), findsOneWidget);
|
||||||
|
|
||||||
|
// Add players
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
await tester.enterText(find.byType(TextField), 'Player $i');
|
||||||
|
await tester.testTextInput.receiveAction(TextInputAction.done);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure all players are added
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
expect(find.text('Player $i'), findsOneWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigate to GameSettings screen
|
||||||
|
await tester.tap(find.text('Spiel einstellen'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.byType(GameSettings), findsOneWidget);
|
||||||
|
|
||||||
|
// Ensure the number of players and wolves are displayed correctly
|
||||||
|
expect(find.text('Anzahl der Spieler 6'), findsOneWidget);
|
||||||
|
expect(find.text('Anzahl der Werwölfe 1'), findsOneWidget);
|
||||||
|
|
||||||
|
// Toggle a special role
|
||||||
|
await tester.tap(find.byType(Switch).first);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect((tester.widget(find.byType(Switch).first) as Switch).value, true);
|
||||||
|
|
||||||
|
// Navigate to FlipingCard screen
|
||||||
|
await tester.tap(find.text('Spiel starten!'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.byType(FlipingCard), findsOneWidget);
|
||||||
|
|
||||||
|
// Flip through all players
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
await tester.tap(find.text('Klick um deine Rolle zu sehen!'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
await tester.tap(find.text('Nächster Spieler'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we navigate to the game board
|
||||||
|
await tester.tap(find.text('Spiel anfangen!'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.byType(PlayerGridView), findsOneWidget);
|
||||||
|
|
||||||
|
// Tap to kill a player
|
||||||
|
await tester.tap(find.text('Player 0'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.byIcon(Icons.close), findsOneWidget);
|
||||||
|
|
||||||
|
// Skip phase
|
||||||
|
await tester.tap(find.text('Tag skippen'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Nacht skippen'), findsOneWidget);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:werwolf/screens/settings.dart';
|
||||||
|
import 'package:werwolf/screens/flippingcards.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('GameSettings Tests', () {
|
||||||
|
List<String> playerNames = ['Alice', 'Bob', 'Charlie', 'Dave', 'Eve', 'Frank'];
|
||||||
|
|
||||||
|
testWidgets('Displays number of players', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(MaterialApp(home: GameSettings(playernames: playerNames)));
|
||||||
|
|
||||||
|
expect(find.text('Anzahl der Spieler 6'), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Displays number of wolves and increments/decrements correctly', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(MaterialApp(home: GameSettings(playernames: playerNames)));
|
||||||
|
|
||||||
|
expect(find.text('Anzahl der Werwölfe 1'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.byIcon(Icons.add));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Anzahl der Werwölfe 2'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.byIcon(Icons.remove));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('Anzahl der Werwölfe 1'), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Displays special roles and toggles switches', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(MaterialApp(home: GameSettings(playernames: playerNames)));
|
||||||
|
|
||||||
|
expect(find.text('Spezielle Rollen'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.tap(find.byType(Switch).first);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect((tester.widget(find.byType(Switch).first) as Switch).value, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Navigates to FlipingCard screen on start', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(MaterialApp(home: GameSettings(playernames: playerNames)));
|
||||||
|
|
||||||
|
await tester.tap(find.text('Spiel starten!'));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(find.byType(FlipingCard), findsOneWidget);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue