Aktuelle Version mit richtigem Shuffle
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user