Aktuelle Version mit richtigem Shuffle

This commit is contained in:
MarcWieland
2025-12-11 08:20:15 +01:00
parent 41a4b2481a
commit 404769af45
2 changed files with 186 additions and 48 deletions

View File

@@ -0,0 +1,146 @@
// lib/features/tournament/presentation/provider/shuffle_provider.dart
import 'dart:math';
import 'package:collection/collection.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../data/models/player_model.dart';
import 'active_players_provider.dart';
import 'shuffle_settings_provider.dart';
class ShuffleResult {
final List<List<PlayerModel>> fields; // 3 Felder à max 12
final List<PlayerModel> bench;
final String message;
ShuffleResult(this.fields, this.bench, {this.message = ''});
}
// Dies ist jetzt ein STATEFUL Provider → wird nur bei explizitem Aufruf neu berechnet
final shuffleResultProvider =
StateProvider<ShuffleResult>((ref) => ShuffleResult([], [], message: 'Noch nicht gemischt'));
final shuffleControllerProvider = Provider((ref) => ShuffleController(ref));
class ShuffleController {
final Ref _ref;
ShuffleController(this._ref);
/// Hauptfunktion wird nur vom Button aufgerufen
void shuffle() {
final activePlayers = _ref.read(activePlayersProvider);
final settings = _ref.read(shuffleSettingsProvider);
if (activePlayers.isEmpty) {
_ref.read(shuffleResultProvider.notifier).state =
ShuffleResult([], [], message: 'Keine aktiven Spieler');
return;
}
final result = ShuffleAlgorithm().run(activePlayers, settings);
// Jetzt erst speichern (einmalig!)
_commitAllChanges(result);
// UI aktualisieren
_ref.read(shuffleResultProvider.notifier).state = result;
}
void _commitAllChanges(ShuffleResult result) {
// Aussetzer markieren
for (final p in result.bench) {
p.hasSatOut = true;
p.save();
}
// Alle anderen zurücksetzen (falls nötig)
final allActive = _ref.read(activePlayersProvider);
for (final p in allActive) {
if (!result.bench.contains(p)) {
p.hasSatOut = false;
p.save();
}
}
}
}
class ShuffleAlgorithm {
final Random _random = Random();
ShuffleResult run(List<PlayerModel> players, ShuffleSettings settings) {
// 1. Aussetzer bestimmen
final bench = _determineBench(players);
final playing = players.where((p) => !bench.contains(p)).toList();
// 2. Mischen
List<PlayerModel> ordered;
switch (settings.mode) {
case ShuffleMode.random:
ordered = playing..shuffle(_random);
break;
default:
ordered = _balancedShuffle(playing, settings);
break;
}
// 3. Auf 3 Felder verteilen
final fields = <List<PlayerModel>>[];
for (int i = 0; i < 3; i++) {
final start = i * 12;
final end = (start + 12).clamp(0, ordered.length);
fields.add(start < ordered.length ? ordered.sublist(start, end) : []);
}
return ShuffleResult(
fields,
bench,
message: 'Gemischte Teams (${ordered.length} Spieler)',
);
}
List<PlayerModel> _determineBench(List<PlayerModel> players) {
if (players.length <= 36) return [];
final excess = players.length - 36;
final never = players.where((p) => !p.hasSatOut).toList();
final already = players.where((p) => p.hasSatOut).toList();
final bench = <PlayerModel>[];
bench.addAll(never.take(excess));
if (bench.length < excess) {
bench.addAll(already.take(excess - bench.length));
}
return bench;
}
List<PlayerModel> _balancedShuffle(List<PlayerModel> players, ShuffleSettings settings) {
players.sort((a, b) {
if (settings.prioritizeGenderBalance) {
final g = a.gender.index.compareTo(b.gender.index);
if (g != 0) return g;
}
if (settings.prioritizeLevelBalance) {
final l = b.skillLevel.index.compareTo(a.skillLevel.index);
if (l != 0) return l;
}
if (settings.usePositions) {
final az = a.positions.contains(Position.zuspieler) ? 1 : 0;
final bz = b.positions.contains(Position.zuspieler) ? 1 : 0;
if (az != bz) return bz.compareTo(az);
}
return 0;
});
final teams = List.generate(6, (_) => <PlayerModel>[]);
for (int i = 0; i < players.length; i++) {
teams[i % 6].add(players[i]);
}
for (final t in teams) t.shuffle(_random);
final result = <PlayerModel>[];
for (int i = 0; i < 3; i++) {
result.addAll(teams[i]);
result.addAll(teams[i + 3]);
}
return result;
}
}