schleifchenturnier_25/lib/features/tournament/presentation/provider/shuffle_provider.dart
2025-12-11 08:20:15 +01:00

146 lines
4.2 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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;
}
}