algorithmus improvements
This commit is contained in:
parent
36d7821629
commit
7d68026955
@ -1,6 +1,6 @@
|
||||
import React, { createContext, useContext, useState, ReactNode, useMemo } from 'react';
|
||||
import { Team, Round, TeamScore, Match, MatchResult } from '@/types/tournament';
|
||||
import { generateMatches } from '@/utils/tournamentUtils';
|
||||
import { generateMatches, createNextRoundMatches } from '@/utils/tournamentUtils';
|
||||
|
||||
interface TournamentContextType {
|
||||
teams: Team[];
|
||||
@ -53,7 +53,17 @@ export const TournamentProvider = ({ children }: { children: ReactNode }) => {
|
||||
const startNewRound = () => {
|
||||
if (currentRound && !currentRound.completed) return;
|
||||
|
||||
const state = generateMatches(teams, fieldCount);
|
||||
let state;
|
||||
|
||||
if (rounds.length === 0) {
|
||||
// First round: initial random generation
|
||||
state = generateMatches(teams, fieldCount);
|
||||
} else {
|
||||
// Subsequent rounds: rotation system
|
||||
const lastRound = rounds[rounds.length - 1];
|
||||
state = createNextRoundMatches(lastRound, fieldCount);
|
||||
}
|
||||
|
||||
const allMatches = [...state.bundesligaMatches, ...state.championsMatches];
|
||||
|
||||
const newRound: Round = {
|
||||
@ -69,12 +79,26 @@ export const TournamentProvider = ({ children }: { children: ReactNode }) => {
|
||||
};
|
||||
|
||||
const updateMatchResult = (matchId: string, scoreA: number, scoreB: number) => {
|
||||
const diff = scoreB - scoreA;
|
||||
const diff = Math.abs(scoreB - scoreA);
|
||||
|
||||
let pointsA: number;
|
||||
let pointsB: number;
|
||||
|
||||
if (scoreA > scoreB) {
|
||||
// Team A gewinnt
|
||||
pointsA = diff + 2;
|
||||
pointsB = -diff;
|
||||
} else {
|
||||
// Team B gewinnt
|
||||
pointsA = -diff;
|
||||
pointsB = diff + 2;
|
||||
}
|
||||
|
||||
const result: MatchResult = {
|
||||
scoreA,
|
||||
scoreB,
|
||||
pointsA: -diff,
|
||||
pointsB: diff,
|
||||
pointsA,
|
||||
pointsB,
|
||||
};
|
||||
|
||||
setRounds((prev) =>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Team, Match, TournamentState, League } from '@/types/tournament';
|
||||
import { Team, Match, TournamentState, League, Round } from '@/types/tournament';
|
||||
|
||||
export const generateMatches = (teams: Team[], fieldCount: number): TournamentState => {
|
||||
const bundesligaTeams = teams.filter((t) => t.league === 'bundesliga');
|
||||
@ -71,3 +71,139 @@ export const generateMatches = (teams: Team[], fieldCount: number): TournamentSt
|
||||
championsFields,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Rotation system for subsequent rounds
|
||||
* Implements 3 cases:
|
||||
* - Case 1: Even teams (no waiting) - all rotate using Circle Rotation algorithm
|
||||
* - Case 2: Odd teams (1 waiting) - waiting joins, last playing goes to waiting
|
||||
* - Case 3: Multiple waiting (3+) - all waiting play, last N playing go to waiting
|
||||
*/
|
||||
export const createNextRoundMatches = (
|
||||
previousRound: Round,
|
||||
fieldCount: number
|
||||
): TournamentState => {
|
||||
const createRotatedMatches = (
|
||||
currentMatches: Match[],
|
||||
waitingTeams: Team[],
|
||||
availableFields: number,
|
||||
league: League,
|
||||
fieldOffset: number
|
||||
): { matches: Match[]; waiting: Team[] } => {
|
||||
if (currentMatches.length === 0) {
|
||||
return { matches: [], waiting: waitingTeams };
|
||||
}
|
||||
|
||||
// Collect all teams from current matches and waiting
|
||||
const playingTeams = currentMatches.flatMap((m) => [m.teamA, m.teamB]);
|
||||
const allTeamsForLeague = [...playingTeams, ...waitingTeams];
|
||||
|
||||
if (allTeamsForLeague.length < 2) {
|
||||
return { matches: [], waiting: allTeamsForLeague };
|
||||
}
|
||||
|
||||
const numWaiting = waitingTeams.length;
|
||||
let rotatedTeams: Team[] = [];
|
||||
|
||||
if (numWaiting === 0) {
|
||||
// Case 1: No waiting teams - use Circle Rotation algorithm
|
||||
rotatedTeams = rotateTeamsInCircle(allTeamsForLeague);
|
||||
} else if (numWaiting === 1) {
|
||||
// Case 2: 1 waiting team - waiting joins, last playing goes to waiting
|
||||
rotatedTeams = [waitingTeams[0], ...playingTeams.slice(0, -1), playingTeams[playingTeams.length - 1]];
|
||||
} else {
|
||||
// Case 3: Multiple waiting - all waiting play, last N playing go to waiting
|
||||
rotatedTeams = [
|
||||
...waitingTeams,
|
||||
...playingTeams.slice(0, playingTeams.length - numWaiting),
|
||||
...playingTeams.slice(-numWaiting),
|
||||
];
|
||||
}
|
||||
|
||||
// Now create matches based on available fields
|
||||
const maxTeamsPlaying = availableFields * 2;
|
||||
const teamsToPlay = rotatedTeams.slice(0, maxTeamsPlaying);
|
||||
const newWaiting = rotatedTeams.slice(maxTeamsPlaying);
|
||||
|
||||
// Create matches from playing teams
|
||||
const matches: Match[] = [];
|
||||
let teamIndex = 0;
|
||||
let fieldNumber = fieldOffset + 1;
|
||||
|
||||
while (teamIndex < teamsToPlay.length - 1 && matches.length < availableFields) {
|
||||
matches.push({
|
||||
id: crypto.randomUUID(),
|
||||
teamA: teamsToPlay[teamIndex],
|
||||
teamB: teamsToPlay[teamIndex + 1],
|
||||
fieldNumber,
|
||||
league,
|
||||
});
|
||||
teamIndex += 2;
|
||||
fieldNumber++;
|
||||
}
|
||||
|
||||
return { matches, waiting: newWaiting };
|
||||
};
|
||||
|
||||
// Determine field allocation
|
||||
const bundesligaMatches = previousRound.matches.filter((m) => m.league === 'bundesliga');
|
||||
const championsMatches = previousRound.matches.filter((m) => m.league === 'champions');
|
||||
|
||||
const bundesligaHasTeams = bundesligaMatches.length > 0 || previousRound.bundesligaWaiting.length > 0;
|
||||
const championsHasTeams = championsMatches.length > 0 || previousRound.championsWaiting.length > 0;
|
||||
|
||||
let bundesligaFields = 0;
|
||||
let championsFields = 0;
|
||||
|
||||
if (bundesligaHasTeams && championsHasTeams) {
|
||||
bundesligaFields = Math.floor(fieldCount / 2);
|
||||
championsFields = fieldCount - bundesligaFields;
|
||||
} else if (bundesligaHasTeams) {
|
||||
bundesligaFields = fieldCount;
|
||||
} else if (championsHasTeams) {
|
||||
championsFields = fieldCount;
|
||||
}
|
||||
|
||||
// Apply rotation for each league
|
||||
const bundesliga = createRotatedMatches(
|
||||
bundesligaMatches,
|
||||
previousRound.bundesligaWaiting,
|
||||
bundesligaFields,
|
||||
'bundesliga',
|
||||
0
|
||||
);
|
||||
|
||||
const champions = createRotatedMatches(
|
||||
championsMatches,
|
||||
previousRound.championsWaiting,
|
||||
championsFields,
|
||||
'champions',
|
||||
bundesligaFields
|
||||
);
|
||||
|
||||
return {
|
||||
bundesligaMatches: bundesliga.matches,
|
||||
championsMatches: champions.matches,
|
||||
bundesligaWaiting: bundesliga.waiting,
|
||||
championsWaiting: champions.waiting,
|
||||
bundesligaFields,
|
||||
championsFields,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Circle Rotation Algorithm (Roundrobin)
|
||||
* Keeps first team fixed, rotates all others by 1 position
|
||||
* Example: [A, B, C, D] → [A, D, B, C] → [A, C, D, B] → [A, B, C, D]
|
||||
*/
|
||||
function rotateTeamsInCircle(teams: Team[]): Team[] {
|
||||
if (teams.length <= 2) return teams;
|
||||
|
||||
const fixed = teams[0];
|
||||
const rotating = teams.slice(1);
|
||||
|
||||
// Rotate: move last to first
|
||||
const rotated = [rotating[rotating.length - 1], ...rotating.slice(0, -1)];
|
||||
|
||||
return [fixed, ...rotated];
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user