diff --git a/README.md b/README.md index 6e76f0d99..36b7ab235 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![GitHub commit activity](https://img.shields.io/github/commit-activity/y/softwaremagico/KendoTournamentManager)](https://github.com/softwaremagico/KendoTournamentManager) [![GitHub last commit](https://img.shields.io/github/last-commit/softwaremagico/KendoTournamentManager)](https://github.com/softwaremagico/KendoTournamentManager) [![CircleCI](https://circleci.com/gh/softwaremagico/KendoTournamentManager.svg?style=shield)](https://circleci.com/gh/softwaremagico/KendoTournamentManager) -[![Time](https://img.shields.io/badge/development-639h-blueviolet.svg)]() +[![Time](https://img.shields.io/badge/development-642.5h-blueviolet.svg)]() [![Powered by](https://img.shields.io/badge/powered%20by%20java-orange.svg?logo=OpenJDK&logoColor=white)]() [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=kendo-tournament-backend&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=kendo-tournament-backend) diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/AchievementController.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/AchievementController.java index 09634fc1f..993244c2c 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/AchievementController.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/AchievementController.java @@ -1360,7 +1360,7 @@ && getScoresByParticipant().get(participant).contains(Score.HANSOKU) } /** - * When somebody loose a combat only by Hansokus. + * When somebody loses a combat only by Hansokus. * * @param tournament The tournament to check. * @return a list of new achievements. diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/FightController.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/FightController.java index 5b011536d..309f2a76d 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/FightController.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/FightController.java @@ -82,7 +82,7 @@ public FightController(FightProvider provider, FightConverter converter, Tournam TournamentProvider tournamentProvider, TournamentHandlerSelector tournamentHandlerSelector, TournamentExtraPropertyProvider tournamentExtraPropertyProvider, ParticipantProvider participantProvider, GroupProvider groupProvider, - TeamConverter teamConverter) { + TeamConverter teamConverter, FightProvider fightProvider) { super(provider, converter); this.tournamentConverter = tournamentConverter; this.tournamentProvider = tournamentProvider; @@ -197,6 +197,9 @@ public List createFights(Integer tournamentId, TeamsOrder teamsOrder, final Tournament tournament = (tournamentProvider.get(tournamentId) .orElseThrow(() -> new TournamentNotFoundException(getClass(), "No tournament found with id '" + tournamentId + "',", ExceptionType.INFO))); + //Delete any deeper level. If a group changes, the inner levels are invalid. + getProvider().delete(tournament, level + 1); + groupProvider.delete(tournament, level + 1); final ITournamentManager selectedManager = tournamentHandlerSelector.selectManager(tournament.getType()); if (selectedManager != null) { final List createdFights = getProvider().saveAll(selectedManager.createFights(tournament, teamsOrder, level, createdBy)); diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/RankingController.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/RankingController.java index abe535068..f733a1aef 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/RankingController.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/RankingController.java @@ -48,18 +48,22 @@ import com.softwaremagico.kt.core.converters.models.TeamConverterRequest; import com.softwaremagico.kt.core.exceptions.ClubNotFoundException; import com.softwaremagico.kt.core.exceptions.GroupNotFoundException; +import com.softwaremagico.kt.core.exceptions.TournamentNotFoundException; import com.softwaremagico.kt.core.providers.ClubProvider; import com.softwaremagico.kt.core.providers.GroupProvider; import com.softwaremagico.kt.core.providers.ParticipantProvider; import com.softwaremagico.kt.core.providers.RankingProvider; import com.softwaremagico.kt.core.providers.RoleProvider; +import com.softwaremagico.kt.core.providers.TournamentProvider; import com.softwaremagico.kt.core.score.CompetitorRanking; import com.softwaremagico.kt.core.score.ScoreOfCompetitor; +import com.softwaremagico.kt.core.tournaments.BubbleSortTournamentHandler; import com.softwaremagico.kt.persistence.entities.Club; import com.softwaremagico.kt.persistence.entities.Group; import com.softwaremagico.kt.persistence.entities.Participant; import com.softwaremagico.kt.persistence.entities.Role; import com.softwaremagico.kt.persistence.entities.Team; +import com.softwaremagico.kt.persistence.entities.Tournament; import com.softwaremagico.kt.persistence.values.RoleType; import com.softwaremagico.kt.persistence.values.ScoreType; import com.softwaremagico.kt.persistence.values.TournamentType; @@ -69,12 +73,14 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; @@ -112,6 +118,10 @@ public class RankingController { private final RoleProvider roleProvider; + private final TournamentProvider tournamentProvider; + + private final BubbleSortTournamentHandler bubbleSortTournamentHandler; + public RankingController(GroupProvider groupProvider, GroupConverter groupConverter, TournamentConverter tournamentConverter, FightConverter fightConverter, TeamConverter teamConverter, DuelConverter duelConverter, @@ -120,7 +130,8 @@ public RankingController(GroupProvider groupProvider, GroupConverter groupConver ScoreOfCompetitorConverter scoreOfCompetitorConverter, ScoreOfTeamConverter scoreOfTeamConverter, ClubProvider clubProvider, ParticipantProvider participantProvider, ClubConverter clubConverter, - RoleProvider roleProvider) { + RoleProvider roleProvider, TournamentProvider tournamentProvider, + BubbleSortTournamentHandler bubbleSortTournamentHandler) { this.groupProvider = groupProvider; this.groupConverter = groupConverter; this.tournamentConverter = tournamentConverter; @@ -136,6 +147,8 @@ public RankingController(GroupProvider groupProvider, GroupConverter groupConver this.participantProvider = participantProvider; this.clubConverter = clubConverter; this.roleProvider = roleProvider; + this.tournamentProvider = tournamentProvider; + this.bubbleSortTournamentHandler = bubbleSortTournamentHandler; } private static Set getParticipants(List teams) { @@ -164,8 +177,27 @@ public List getTeamsScoreRankingFromGroup(Integer groupId) { } public List getTeamsScoreRankingFromTournament(Integer tournamentId) { - return scoreOfTeamConverter.convertAll(rankingProvider.getTeamsScoreRankingFromTournament(tournamentId) + final Tournament tournament = tournamentProvider.get(tournamentId).orElseThrow( + () -> new TournamentNotFoundException(this.getClass(), "No tournamnet exists with id '" + tournamentId + "'.")); + final List ranking = scoreOfTeamConverter.convertAll(rankingProvider.getTeamsScoreRankingFromTournament(tournamentId) .stream().map(ScoreOfTeamConverterRequest::new).toList()); + //Bubble sort is different. The winner is only on the first group. + if (tournament.getType().equals(TournamentType.BUBBLE_SORT)) { + final List sortedTeams = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament); + Collections.reverse(sortedTeams); + final List scoreOfTeamDTOS = new ArrayList<>(); + final AtomicInteger counter = new AtomicInteger(0); + sortedTeams.forEach(team -> { + final ScoreOfTeamDTO score = ranking.stream().filter(rankingElement -> + Objects.equals(rankingElement.getTeam().getId(), team.getId())).findFirst().orElse(null); + if (score != null) { + score.setSortingIndex(counter.getAndIncrement()); + scoreOfTeamDTOS.add(score); + } + }); + return scoreOfTeamDTOS; + } + return ranking; } public List getTeamsScoreRanking(GroupDTO groupDTO) { diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/models/TournamentExtraPropertyDTO.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/models/TournamentExtraPropertyDTO.java index 2c189ad15..f3e260a73 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/models/TournamentExtraPropertyDTO.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/controller/models/TournamentExtraPropertyDTO.java @@ -23,8 +23,12 @@ import com.softwaremagico.kt.persistence.values.TournamentExtraPropertyKey; +import java.io.Serial; + public class TournamentExtraPropertyDTO extends ElementDTO { + @Serial + private static final long serialVersionUID = -4825047701201067422L; private TournamentDTO tournament; diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/exceptions/InvalidExtraPropertyException.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/exceptions/InvalidExtraPropertyException.java new file mode 100644 index 000000000..45e115cbb --- /dev/null +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/exceptions/InvalidExtraPropertyException.java @@ -0,0 +1,52 @@ +package com.softwaremagico.kt.core.exceptions; + +/*- + * #%L + * Kendo Tournament Manager (Core) + * %% + * Copyright (C) 2021 - 2024 Softwaremagico + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * #L% + */ + +import com.softwaremagico.kt.logger.ExceptionType; +import com.softwaremagico.kt.logger.LoggedException; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +import java.io.Serial; + +@ResponseStatus(HttpStatus.BAD_REQUEST) +public class InvalidExtraPropertyException extends LoggedException { + + @Serial + private static final long serialVersionUID = 2621573668990271417L; + + public InvalidExtraPropertyException(Class clazz, String message, ExceptionType type) { + super(clazz, message, type, HttpStatus.BAD_REQUEST); + } + + public InvalidExtraPropertyException(Class clazz, String message) { + super(clazz, message, ExceptionType.SEVERE, HttpStatus.BAD_REQUEST); + } + + public InvalidExtraPropertyException(Class clazz) { + this(clazz, "Invalid Group"); + } + + public InvalidExtraPropertyException(Class clazz, Throwable e) { + super(clazz, e); + } +} diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/managers/BubbleSortTournamentManager.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/managers/BubbleSortTournamentManager.java new file mode 100644 index 000000000..1286cfa34 --- /dev/null +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/managers/BubbleSortTournamentManager.java @@ -0,0 +1,30 @@ +package com.softwaremagico.kt.core.managers; + +/*- + * #%L + * Kendo Tournament Manager (Core) + * %% + * Copyright (C) 2021 - 2024 Softwaremagico + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * #L% + */ + +import org.springframework.stereotype.Service; + +@Service +public class BubbleSortTournamentManager extends KingOfTheMountainFightManager { + + +} diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/managers/KingOfTheMountainFightManager.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/managers/KingOfTheMountainFightManager.java index f17868ec6..91a38e5e0 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/managers/KingOfTheMountainFightManager.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/managers/KingOfTheMountainFightManager.java @@ -33,14 +33,17 @@ public class KingOfTheMountainFightManager { public List createFights(Tournament tournament, List teams, Integer level, String createdBy) { - return createOneFightsForEachTeam(tournament, teams, level, createdBy); + return createFirstFight(tournament, teams, level, createdBy); } private Fight createFight(Tournament tournament, Team team1, Team team2, Integer shiaijo, Integer level, String createdBy) { return new Fight(tournament, team1, team2, shiaijo, level, createdBy); } - private List createOneFightsForEachTeam(Tournament tournament, List teams, int level, String createdBy) { + /** + * Only the first two teams are used, as only first fight can be defined. + */ + private List createFirstFight(Tournament tournament, List teams, int level, String createdBy) { if (teams == null || tournament == null || teams.size() < 2) { return new ArrayList<>(); } @@ -48,16 +51,9 @@ private List createOneFightsForEachTeam(Tournament tournament, List // If only exists two teams, there are only one fight. If no, as many // fights as teams - for (int i = 0; i < (teams.size() > 2 ? teams.size() : 1); i++) { - final Team team1 = teams.get(i); - final Team team2 = teams.get((i + 1) % teams.size()); - - if (fights.size() % 2 == 0) { - fights.add(createFight(tournament, team1, team2, 0, level, createdBy)); - } else { - fights.add(createFight(tournament, team2, team1, 0, level, createdBy)); - } - } + final Team team1 = teams.get(0); + final Team team2 = teams.get(1); + fights.add(createFight(tournament, team1, team2, 0, level, createdBy)); return fights; } } diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/providers/FightProvider.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/providers/FightProvider.java index 9881e6254..f2599897f 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/providers/FightProvider.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/providers/FightProvider.java @@ -99,6 +99,14 @@ public void delete(Tournament tournament) { getRepository().deleteByTournament(tournament); } + public void delete(Tournament tournament, int level) { + groupRepository.findByTournamentAndLevelIsGreaterThanEqual(tournament, level).forEach(group -> { + group.setFights(new ArrayList<>()); + groupRepository.save(group); + }); + getRepository().deleteByTournamentAndLevelGreaterThanEqual(tournament, level); + } + public long count(Tournament tournament) { return getRepository().countByTournament(tournament); } diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/providers/TournamentExtraPropertyProvider.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/providers/TournamentExtraPropertyProvider.java index 03a914b75..7dc48a3fc 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/providers/TournamentExtraPropertyProvider.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/providers/TournamentExtraPropertyProvider.java @@ -21,6 +21,7 @@ * #L% */ +import com.softwaremagico.kt.core.exceptions.InvalidExtraPropertyException; import com.softwaremagico.kt.persistence.entities.Tournament; import com.softwaremagico.kt.persistence.entities.TournamentExtraProperty; import com.softwaremagico.kt.persistence.repositories.TournamentExtraPropertyRepository; @@ -77,6 +78,10 @@ public void deleteByTournamentAndProperty(Tournament tournament, TournamentExtra @Override public TournamentExtraProperty save(TournamentExtraProperty entity) { + if (!entity.getPropertyKey().getAllowedTournaments().contains(entity.getTournament().getType())) { + throw new InvalidExtraPropertyException(this.getClass(), "Tournament '" + entity.getTournament() + + "' cannot have property '" + entity.getPropertyKey() + "'"); + } deleteByTournamentAndProperty(entity.getTournament(), entity.getPropertyKey()); return getRepository().save(entity); } diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/BubbleSortTournamentHandler.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/BubbleSortTournamentHandler.java new file mode 100644 index 000000000..8f590839b --- /dev/null +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/BubbleSortTournamentHandler.java @@ -0,0 +1,328 @@ +package com.softwaremagico.kt.core.tournaments; + +/*- + * #%L + * Kendo Tournament Manager (Core) + * %% + * Copyright (C) 2021 - 2024 Softwaremagico + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * #L% + */ + +import com.softwaremagico.kt.core.exceptions.TournamentFinishedException; +import com.softwaremagico.kt.core.managers.BubbleSortTournamentManager; +import com.softwaremagico.kt.core.managers.TeamsOrder; +import com.softwaremagico.kt.core.providers.FightProvider; +import com.softwaremagico.kt.core.providers.GroupProvider; +import com.softwaremagico.kt.core.providers.RankingProvider; +import com.softwaremagico.kt.core.providers.TeamProvider; +import com.softwaremagico.kt.core.providers.TournamentExtraPropertyProvider; +import com.softwaremagico.kt.persistence.entities.Fight; +import com.softwaremagico.kt.persistence.entities.Group; +import com.softwaremagico.kt.persistence.entities.Team; +import com.softwaremagico.kt.persistence.entities.Tournament; +import com.softwaremagico.kt.persistence.entities.TournamentExtraProperty; +import com.softwaremagico.kt.persistence.repositories.TournamentRepository; +import com.softwaremagico.kt.persistence.values.TournamentExtraPropertyKey; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +@Service +public class BubbleSortTournamentHandler extends LeagueHandler { + private final BubbleSortTournamentManager bubbleSortTournamentManager; + private final GroupProvider groupProvider; + private final FightProvider fightProvider; + private final TeamProvider teamProvider; + private final RankingProvider rankingProvider; + private final TournamentExtraPropertyProvider tournamentExtraPropertyProvider; + private final TournamentRepository tournamentRepository; + + public BubbleSortTournamentHandler(BubbleSortTournamentManager bubbleSortTournamentManager, GroupProvider groupProvider, + FightProvider fightProvider, TeamProvider teamProvider, RankingProvider rankingProvider, + TournamentExtraPropertyProvider tournamentExtraPropertyProvider, TournamentRepository tournamentRepository) { + super(groupProvider, teamProvider, rankingProvider, tournamentExtraPropertyProvider); + this.bubbleSortTournamentManager = bubbleSortTournamentManager; + this.groupProvider = groupProvider; + this.fightProvider = fightProvider; + this.teamProvider = teamProvider; + this.rankingProvider = rankingProvider; + this.tournamentExtraPropertyProvider = tournamentExtraPropertyProvider; + this.tournamentRepository = tournamentRepository; + } + + @Override + public List createFights(Tournament tournament, TeamsOrder teamsOrder, Integer level, String createdBy) { + //Create the first fight only. + final List fights = fightProvider.saveAll(bubbleSortTournamentManager.createFights(tournament, + getFirstGroup(tournament).getTeams(), level, createdBy)); + final Group group = getFirstGroup(tournament); + group.setFights(fights); + groupProvider.save(group); + //Reset the counter. + tournamentExtraPropertyProvider.save(new TournamentExtraProperty(tournament, + TournamentExtraPropertyKey.KING_INDEX, "1")); + tournamentExtraPropertyProvider.save(new TournamentExtraProperty(tournament, + TournamentExtraPropertyKey.BUBBLE_SORT_ITERATION, "0")); + return fights; + } + + @Override + public List generateNextFights(Tournament tournament, String createdBy) { + List groups = groupProvider.getGroups(tournament); + Group group = groups.get(groups.size() - 1); + + //It is finished if there are as many levels as teams - 1; + if (groups.size() == teamProvider.getAll(tournament).size() - 1) { + return new ArrayList<>(); + } + + //Check if the group is over. The Number of fights must be the number of teams -1 and one less by level. + if (group.getFights().size() >= group.getTeams().size() - 1 - group.getLevel()) { + //Create a new level. And add a new group to this level. + createNextLevel(tournament); + groups = groupProvider.getGroups(tournament); + group = groups.get(groups.size() - 1); + + //Create the first fight from a group, + final List fights = fightProvider.saveAll(bubbleSortTournamentManager.createFights(tournament, + group.getTeams(), group.getLevel(), createdBy)); + group.setFights(fights); + groupProvider.save(group); + return fights; + } + + + final Fight lastFight = group.getFights().get(group.getFights().size() - 1); + + final Fight newFight = new Fight(); + newFight.setTournament(tournament); + //Previous winner with no draw + if (lastFight.getWinner() != null) { + newFight.setTeam1(lastFight.getWinner()); + newFight.setTeam2(getNextTeam(group.getTeams(), Collections.singletonList(lastFight.getWinner()), + Collections.singletonList(lastFight.getLoser()), tournament, null)); + } else { + final DrawResolution drawResolution = getDrawResolution(tournament); + switch (drawResolution) { + case BOTH_ELIMINATED -> { + newFight.setTeam1(getNextTeam(group.getTeams(), new ArrayList<>(), + Arrays.asList(lastFight.getTeam1(), lastFight.getTeam2()), tournament, drawResolution)); + newFight.setTeam2(getNextTeam(group.getTeams(), new ArrayList<>(), + Arrays.asList(lastFight.getTeam1(), lastFight.getTeam2(), newFight.getTeam1()), tournament, drawResolution)); + } + case OLDEST_ELIMINATED -> { + //Oldest is Team1 always. + newFight.setTeam1(lastFight.getTeam2()); + newFight.setTeam2(getNextTeam(group.getTeams(), Collections.singletonList(lastFight.getTeam2()), + Collections.singletonList(lastFight.getTeam1()), tournament, drawResolution)); + } + case NEWEST_ELIMINATED -> { + //Newest is Team2 always. + newFight.setTeam1(lastFight.getTeam1()); + newFight.setTeam2(getNextTeam(group.getTeams(), Collections.singletonList(lastFight.getTeam1()), + Collections.singletonList(lastFight.getTeam2()), tournament, drawResolution)); + } + default -> { + // Ignore. + } + } + } + newFight.generateDuels(createdBy); + //Fight is saved in a group by cascade. + group.getFights().add(newFight); + groupProvider.save(group); + return Collections.singletonList(newFight); + } + + private Team getNextTeam(List teams, List winners, List losers, Tournament tournament, DrawResolution drawResolution) { + final AtomicInteger kingIndex = new AtomicInteger(0); + final TournamentExtraProperty extraProperty = getKingIndex(tournament); + try { + kingIndex.addAndGet(Integer.parseInt(extraProperty.getPropertyValue())); + } catch (NumberFormatException | NullPointerException e) { + kingIndex.set(1); + } + kingIndex.getAndIncrement(); + // Avoid repeating a winner. + Integer forbiddenWinner = null; + for (final Team winner : winners) { + if (teams.indexOf(winner) == (kingIndex.get() % teams.size())) { + forbiddenWinner = kingIndex.getAndIncrement(); + } + } + // Avoid repeating a loser. + for (final Team loser : losers) { + if (teams.indexOf(loser) == (kingIndex.get() % teams.size())) { + kingIndex.getAndIncrement(); + //Avoid the new one is still the winner. + if (forbiddenWinner != null && (kingIndex.get() % teams.size()) == (forbiddenWinner % teams.size())) { + kingIndex.getAndIncrement(); + } + } + } + + // Get the next team and save index. + final Team nextTeam = teams.get(kingIndex.get() % teams.size()); + extraProperty.setPropertyValue(String.valueOf(kingIndex.get())); + tournamentExtraPropertyProvider.save(extraProperty); + return nextTeam; + } + + @Override + public List createInitialFights(Tournament tournament, TeamsOrder teamsOrder, String createdBy) { + return createFights(tournament, teamsOrder, getNextLevel(tournament), createdBy); + } + + private int getNextLevel(Tournament tournament) { + //Each group on a different level. + return (int) groupProvider.count(tournament); + } + + @Override + public List getGroups(Tournament tournament) { + return groupProvider.getGroups(tournament); + } + + @Override + public Group addGroup(Tournament tournament, Group group) { + return groupProvider.addGroup(tournament, group); + } + + @Override + public void createNextLevel(Tournament tournament) throws TournamentFinishedException { + final Group group = new Group(); + group.setTournament(tournament); + group.setLevel(getNextLevel(tournament)); + group.setIndex(0); + final DrawResolution drawResolution = getDrawResolution(tournament); + final List existingGroups = groupProvider.getGroups(tournament); + group.setTeams(getTeamsOrderedByRanks(tournament, + !existingGroups.isEmpty() ? existingGroups.get(existingGroups.size() - 1) : null, + drawResolution)); + addGroup(tournament, group); + + //Reset counter + tournamentExtraPropertyProvider.save(new TournamentExtraProperty(tournament, + TournamentExtraPropertyKey.KING_INDEX, "1")); + } + + public List getTeamsOrderedByRanks(Tournament tournament) { + final List groups = groupProvider.getGroups(tournament); + if (groups.isEmpty()) { + return new ArrayList<>(); + } + return getTeamsOrderedByRanks(tournament, groups.get(groups.size() - 1), getDrawResolution(tournament)); + } + + + public List getTeamsOrderedByRanks(Tournament tournament, Group group, DrawResolution drawResolution) { + final List teams = new ArrayList<>(); + if (group != null) { + //Add last teams that have no fights! + for (int i = group.getLevel(); i > 0; i--) { + teams.add(0, group.getTeams().get(group.getTeams().size() - (group.getLevel() - i) - 1)); + } + if (group.getFights() != null && !group.getFights().isEmpty()) { + //From the last fight we get both teams + if (group.getFights().get(group.getFights().size() - 1).getWinner() != null) { + //Winner only if is not added before. + teams.add(0, group.getFights().get(group.getFights().size() - 1).getWinner()); + teams.add(0, group.getFights().get(group.getFights().size() - 1).getLoser()); + } else { + switch (drawResolution) { + case NEWEST_ELIMINATED: + //Newest is Team2 always. + teams.add(0, group.getFights().get(group.getFights().size() - 1).getTeam1()); + teams.add(0, group.getFights().get(group.getFights().size() - 1).getTeam2()); + break; + case OLDEST_ELIMINATED: + case BOTH_ELIMINATED: + //Both cannot be on bubble sort! + default: + //Oldest is Team1 always. + teams.add(0, group.getFights().get(group.getFights().size() - 1).getTeam2()); + teams.add(0, group.getFights().get(group.getFights().size() - 1).getTeam1()); + break; + } + + } + //For any other fight, we get the disqualified one. + for (int i = group.getFights().size() - 2; i >= 0; i--) { + if (group.getFights().get(i).getWinner() != null) { + //Add the disqualified, as the winner has been already added on other fights. + teams.add(0, group.getFights().get(i).getLoser()); + } else { + switch (drawResolution) { + case NEWEST_ELIMINATED: + //Newest is Team2 always. + teams.add(0, group.getFights().get(i).getTeam2()); + break; + case OLDEST_ELIMINATED: + case BOTH_ELIMINATED: + //Both cannot be on bubble sort! + default: + //Oldest is Team1 always. + teams.add(0, group.getFights().get(i).getTeam1()); + break; + } + } + } + return teams; + } + } + if (group == null) { + return teamProvider.getAll(tournament); + } + return group.getTeams(); + } + + protected Group addGroup(Tournament tournament, List teams, Integer level, Integer index) { + final Group group = new Group(); + group.setTournament(tournament); + group.setLevel(level); + group.setIndex(index); + group.setTeams(teams); + return addGroup(tournament, group); + } + + public TournamentExtraProperty getKingIndex(Tournament tournament) { + TournamentExtraProperty extraProperty = tournamentExtraPropertyProvider.getByTournamentAndProperty(tournament, + TournamentExtraPropertyKey.KING_INDEX); + if (extraProperty == null) { + extraProperty = tournamentExtraPropertyProvider.save(new TournamentExtraProperty(tournament, + TournamentExtraPropertyKey.KING_INDEX, "1")); + } else { + //It is 'lazy' the tournament. + extraProperty.setTournament(tournamentRepository.findById(extraProperty.getTournament().getId()).orElse(null)); + } + return extraProperty; + } + + public DrawResolution getDrawResolution(Tournament tournament) { + TournamentExtraProperty extraProperty = tournamentExtraPropertyProvider.getByTournamentAndProperty(tournament, + TournamentExtraPropertyKey.KING_DRAW_RESOLUTION); + if (extraProperty == null) { + extraProperty = tournamentExtraPropertyProvider.save(new TournamentExtraProperty(tournament, + TournamentExtraPropertyKey.KING_DRAW_RESOLUTION, DrawResolution.OLDEST_ELIMINATED.name())); + } + + return DrawResolution.getFromTag(extraProperty.getPropertyValue()); + } +} diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/ITournamentManager.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/ITournamentManager.java index 2fce71b2d..94b41d39b 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/ITournamentManager.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/ITournamentManager.java @@ -33,7 +33,7 @@ public interface ITournamentManager { - List createFights(Tournament tournament, TeamsOrder teamsOrder, String createdBy); + List createInitialFights(Tournament tournament, TeamsOrder teamsOrder, String createdBy); List createFights(Tournament tournament, TeamsOrder teamsOrder, Integer level, String createdBy); @@ -81,7 +81,7 @@ public interface ITournamentManager { void removeFights(Tournament tournament); - void createNextLevel() throws TournamentFinishedException; + void createNextLevel(Tournament tournament) throws TournamentFinishedException; /** * Defines if a fight has a draw value or not. diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/KingOfTheMountainHandler.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/KingOfTheMountainHandler.java index 8b76d8dc6..f33a4dcfc 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/KingOfTheMountainHandler.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/KingOfTheMountainHandler.java @@ -65,8 +65,8 @@ public KingOfTheMountainHandler(KingOfTheMountainFightManager kingOfTheMountainF } @Override - public List createFights(Tournament tournament, TeamsOrder teamsOrder, String createdBy) { - return createFights(tournament, teamsOrder, getNextLevel(tournament), createdBy); + public List createInitialFights(Tournament tournament, TeamsOrder teamsOrder, String createdBy) { + return createFights(tournament, teamsOrder, 0, createdBy); } private int getNextLevel(Tournament tournament) { @@ -76,10 +76,10 @@ private int getNextLevel(Tournament tournament) { @Override public List createFights(Tournament tournament, TeamsOrder teamsOrder, Integer level, String createdBy) { - //Create first fight. + //Create the first fight. final List fights = fightProvider.saveAll(kingOfTheMountainFightManager.createFights(tournament, - getGroup(tournament).getTeams().subList(0, 2), level, createdBy)); - final Group group = getGroup(tournament); + getFirstGroup(tournament).getTeams(), level, createdBy)); + final Group group = getFirstGroup(tournament); group.setFights(fights); groupProvider.save(group); //Reset the counter. @@ -99,17 +99,9 @@ public List generateNextFights(Tournament tournament, String createdBy) { if (lastFight.getWinner() != null) { newFight.setTeam1(lastFight.getWinner()); newFight.setTeam2(getNextTeam(group.getTeams(), Collections.singletonList(lastFight.getWinner()), - Collections.singletonList(lastFight.getLooser()), tournament)); + Collections.singletonList(lastFight.getLoser()), tournament)); } else { - //Depending on the configuration. - TournamentExtraProperty extraProperty = tournamentExtraPropertyProvider.getByTournamentAndProperty(tournament, - TournamentExtraPropertyKey.KING_DRAW_RESOLUTION); - if (extraProperty == null) { - extraProperty = tournamentExtraPropertyProvider.save(new TournamentExtraProperty(tournament, - TournamentExtraPropertyKey.KING_DRAW_RESOLUTION, DrawResolution.BOTH_ELIMINATED.name())); - } - - final DrawResolution drawResolution = DrawResolution.getFromTag(extraProperty.getPropertyValue()); + final DrawResolution drawResolution = getDrawResolution(tournament); switch (drawResolution) { case BOTH_ELIMINATED -> { newFight.setTeam1(getNextTeam(group.getTeams(), new ArrayList<>(), @@ -135,24 +127,16 @@ public List generateNextFights(Tournament tournament, String createdBy) { } } newFight.generateDuels(createdBy); - //Fight is saved in group by cascade. + //Fight is saved in a group by cascade. group.getFights().add(newFight); groupProvider.save(group); return Collections.singletonList(newFight); } - private Team getNextTeam(List teams, List winners, List loosers, Tournament tournament) { + private Team getNextTeam(List teams, List winners, List losers, Tournament tournament) { final AtomicInteger kingIndex = new AtomicInteger(0); - TournamentExtraProperty extraProperty = tournamentExtraPropertyProvider.getByTournamentAndProperty(tournament, - TournamentExtraPropertyKey.KING_INDEX); - if (extraProperty == null) { - extraProperty = tournamentExtraPropertyProvider.save(new TournamentExtraProperty(tournament, - TournamentExtraPropertyKey.KING_INDEX, "1")); - } else { - //It is lazy the tournament. - extraProperty.setTournament(tournamentRepository.findById(extraProperty.getTournament().getId()).orElse(null)); - } + final TournamentExtraProperty extraProperty = getKingIndex(tournament); try { kingIndex.addAndGet(Integer.parseInt(extraProperty.getPropertyValue())); } catch (NumberFormatException | NullPointerException e) { @@ -166,9 +150,9 @@ private Team getNextTeam(List teams, List winners, List looser forbiddenWinner = kingIndex.getAndIncrement(); } } - // Avoid to repeat a looser. - for (final Team looser : loosers) { - if (teams.indexOf(looser) == (kingIndex.get() % teams.size())) { + // Avoid repeating a loser. + for (final Team loser : losers) { + if (teams.indexOf(loser) == (kingIndex.get() % teams.size())) { kingIndex.getAndIncrement(); //Avoid the new one is still the winner. if (forbiddenWinner != null && (kingIndex.get() % teams.size()) == (forbiddenWinner % teams.size())) { @@ -177,24 +161,13 @@ private Team getNextTeam(List teams, List winners, List looser } } - // Get next team and save index. + // Get the next team and save index. final Team nextTeam = teams.get(kingIndex.get() % teams.size()); extraProperty.setPropertyValue(String.valueOf(kingIndex.get())); tournamentExtraPropertyProvider.save(extraProperty); return nextTeam; } - private int getMaxIndex(List listWithIndex, List elements) { - int index = 0; - for (Team element : elements) { - final int indexOf = listWithIndex.indexOf(element); - if (indexOf > index) { - index = indexOf; - } - } - return index; - } - @Override public List getGroups(Tournament tournament) { return groupProvider.getGroups(tournament); @@ -204,4 +177,29 @@ public List getGroups(Tournament tournament) { public Group addGroup(Tournament tournament, Group group) { return groupProvider.addGroup(tournament, group); } + + public TournamentExtraProperty getKingIndex(Tournament tournament) { + TournamentExtraProperty extraProperty = tournamentExtraPropertyProvider.getByTournamentAndProperty(tournament, + TournamentExtraPropertyKey.KING_INDEX); + if (extraProperty == null) { + extraProperty = tournamentExtraPropertyProvider.save(new TournamentExtraProperty(tournament, + TournamentExtraPropertyKey.KING_INDEX, "1")); + } else { + //It is lazy the tournament. + extraProperty.setTournament(tournamentRepository.findById(extraProperty.getTournament().getId()).orElse(null)); + } + return extraProperty; + } + + + public DrawResolution getDrawResolution(Tournament tournament) { + TournamentExtraProperty extraProperty = tournamentExtraPropertyProvider.getByTournamentAndProperty(tournament, + TournamentExtraPropertyKey.KING_DRAW_RESOLUTION); + if (extraProperty == null) { + extraProperty = tournamentExtraPropertyProvider.save(new TournamentExtraProperty(tournament, + TournamentExtraPropertyKey.KING_DRAW_RESOLUTION, DrawResolution.BOTH_ELIMINATED.name())); + } + + return DrawResolution.getFromTag(extraProperty.getPropertyValue()); + } } diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/LeagueHandler.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/LeagueHandler.java index 5e7087a2d..b4295961d 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/LeagueHandler.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/LeagueHandler.java @@ -58,7 +58,7 @@ public LeagueHandler(GroupProvider groupProvider, TeamProvider teamProvider, Ran this.tournamentExtraPropertyProvider = tournamentExtraPropertyProvider; } - protected Group getGroup(Tournament tournament) { + protected Group getFirstGroup(Tournament tournament) { final List groups = groupProvider.getGroups(tournament); if (groups.isEmpty()) { final Group group = new Group(); @@ -110,7 +110,7 @@ public List getGroups(Tournament tournament, Integer level) { @Override public List getGroups(Tournament tournament) { final List groups = new ArrayList<>(); - groups.add(getGroup(tournament)); + groups.add(getFirstGroup(tournament)); return groups; } @@ -149,15 +149,15 @@ public void removeTeams(Tournament tournament, Integer level) { @Override public void setDefaultFightAreas(Tournament tournament) { - final Group group = getGroup(tournament); + final Group group = getFirstGroup(tournament); group.setShiaijo(0); groupProvider.save(group); } @Override public Group getGroup(Tournament tournament, Fight fight) { - if (getGroup(tournament).isFightOfGroup(fight)) { - return getGroup(tournament); + if (getFirstGroup(tournament).isFightOfGroup(fight)) { + return getFirstGroup(tournament); } return null; } @@ -174,20 +174,20 @@ public int getIndex(Integer level, Group group) { @Override public boolean isTheLastFight(Tournament tournament) { - final List fights = getGroup(tournament).getFights(); + final List fights = getFirstGroup(tournament).getFights(); return (fights.size() > 0) && (fights.size() == 1 || fights.get(fights.size() - 2).isOver()); } @Override public void removeFights(Tournament tournament) { - final Group group = getGroup(tournament); + final Group group = getFirstGroup(tournament); group.removeFights(); groupProvider.save(group); } @Override public void removeTeams(Tournament tournament) { - final Group group = getGroup(tournament); + final Group group = getFirstGroup(tournament); group.removeTeams(); groupProvider.save(group); } @@ -203,8 +203,8 @@ public List getGroupsByShiaijo(Tournament tournament, Integer shiaijo) { } @Override - public void createNextLevel() throws TournamentFinishedException { - // Only one level is needed. + public void createNextLevel(Tournament tournament) throws TournamentFinishedException { + // Only one level is necessary. } @Override @@ -214,7 +214,7 @@ public boolean hasDrawScore(Group group) { } @Override - public List createFights(Tournament tournament, TeamsOrder teamsOrder, String createdBy) { + public List createInitialFights(Tournament tournament, TeamsOrder teamsOrder, String createdBy) { return createFights(tournament, teamsOrder, 0, createdBy); } diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/LoopLeagueHandler.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/LoopLeagueHandler.java index a0cfa85ee..09734c356 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/LoopLeagueHandler.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/LoopLeagueHandler.java @@ -60,9 +60,9 @@ public List createFights(Tournament tournament, TeamsOrder teamsOrder, In return null; } //Automatically generates the group if needed in getGroup. - final List fights = fightProvider.saveAll(loopGroupFightManager.createFights(tournament, getGroup(tournament).getTeams(), + final Group group = getFirstGroup(tournament); + final List fights = fightProvider.saveAll(loopGroupFightManager.createFights(tournament, group.getTeams(), TeamsOrder.NONE, level, createdBy)); - final Group group = getGroup(tournament); group.setFights(fights); groupRepository.save(group); return fights; diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/SimpleLeagueHandler.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/SimpleLeagueHandler.java index cfc7f6600..6cb76a21b 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/SimpleLeagueHandler.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/SimpleLeagueHandler.java @@ -66,9 +66,9 @@ public List createFights(Tournament tournament, TeamsOrder teamsOrder, In } //Automatically generates the group if needed in getGroup. final TournamentExtraProperty extraProperty = getLeagueFightsOrder(tournament); - final List fights = fightRepository.saveAll(completeGroupFightManager.createFights(tournament, getGroup(tournament).getTeams(), + final List fights = fightRepository.saveAll(completeGroupFightManager.createFights(tournament, getFirstGroup(tournament).getTeams(), TeamsOrder.NONE, level, 0, LeagueFightsOrder.get(extraProperty.getPropertyValue()) == LeagueFightsOrder.FIFO, createdBy)); - final Group group = getGroup(tournament); + final Group group = getFirstGroup(tournament); group.setFights(fights); groupRepository.save(group); return fights; diff --git a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/TournamentHandlerSelector.java b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/TournamentHandlerSelector.java index 789d9136a..d0f57c21b 100644 --- a/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/TournamentHandlerSelector.java +++ b/backend/kendo-tournament-core/src/main/java/com/softwaremagico/kt/core/tournaments/TournamentHandlerSelector.java @@ -31,15 +31,17 @@ public class TournamentHandlerSelector { private final LoopLeagueHandler loopLeagueHandler; private final TreeTournamentHandler treeTournamentHandler; private final KingOfTheMountainHandler kingOfTheMountainHandler; + private final BubbleSortTournamentHandler bubbleSortTournamentHandler; public TournamentHandlerSelector(SimpleLeagueHandler simpleLeagueHandler, CustomLeagueHandler customTournamentHandler, LoopLeagueHandler loopLeagueHandler, TreeTournamentHandler treeTournamentHandler, - KingOfTheMountainHandler kingOfTheMountainHandler) { + KingOfTheMountainHandler kingOfTheMountainHandler, BubbleSortTournamentHandler bubbleSortTournamentHandler) { this.simpleLeagueHandler = simpleLeagueHandler; this.customTournamentHandler = customTournamentHandler; this.loopLeagueHandler = loopLeagueHandler; this.treeTournamentHandler = treeTournamentHandler; this.kingOfTheMountainHandler = kingOfTheMountainHandler; + this.bubbleSortTournamentHandler = bubbleSortTournamentHandler; } public ITournamentManager selectManager(TournamentType type) { @@ -59,6 +61,8 @@ public ITournamentManager selectManager(TournamentType type) { return kingOfTheMountainHandler; case LEAGUE: return simpleLeagueHandler; + case BUBBLE_SORT: + return bubbleSortTournamentHandler; default: break; } diff --git a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/TournamentTestUtils.java b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/TournamentTestUtils.java index cd474a70b..46fdaa4af 100644 --- a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/TournamentTestUtils.java +++ b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/TournamentTestUtils.java @@ -10,19 +10,18 @@ * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * #L% */ import com.softwaremagico.kt.core.controller.ClubController; -import com.softwaremagico.kt.core.controller.FightController; import com.softwaremagico.kt.core.controller.GroupController; import com.softwaremagico.kt.core.controller.ParticipantController; import com.softwaremagico.kt.core.controller.RoleController; @@ -36,7 +35,6 @@ import com.softwaremagico.kt.core.controller.models.TeamDTO; import com.softwaremagico.kt.core.controller.models.TournamentDTO; import com.softwaremagico.kt.core.controller.models.TournamentExtraPropertyDTO; -import com.softwaremagico.kt.core.providers.TournamentExtraPropertyProvider; import com.softwaremagico.kt.persistence.values.LeagueFightsOrder; import com.softwaremagico.kt.persistence.values.RoleType; import com.softwaremagico.kt.persistence.values.TournamentExtraPropertyKey; @@ -179,8 +177,10 @@ protected TournamentDTO addTournament(String tournamentName, int members, int te TournamentDTO tournamentDTO = tournamentController.create(new TournamentDTO(tournamentName, 1, members, type), null); tournamentDTO.setCreatedAt(LocalDateTime.now().minusMinutes(minutesPast)); tournamentController.update(tournamentDTO, null); - tournamentExtraPropertyController.create(new TournamentExtraPropertyDTO(tournamentDTO, - TournamentExtraPropertyKey.LEAGUE_FIGHTS_ORDER_GENERATION, LeagueFightsOrder.FIFO.name()), null); + if (TournamentExtraPropertyKey.LEAGUE_FIGHTS_ORDER_GENERATION.getAllowedTournaments().contains(type)) { + tournamentExtraPropertyController.create(new TournamentExtraPropertyDTO(tournamentDTO, + TournamentExtraPropertyKey.LEAGUE_FIGHTS_ORDER_GENERATION, LeagueFightsOrder.FIFO.name()), null); + } generateRoles(tournamentDTO, members, teams, referees, organizers, volunteers, press); addTeams(tournamentDTO, members); return tournamentDTO; diff --git a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/BubbleSortDrawTest.java b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/BubbleSortDrawTest.java new file mode 100644 index 000000000..b1689fd20 --- /dev/null +++ b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/BubbleSortDrawTest.java @@ -0,0 +1,322 @@ +package com.softwaremagico.kt.core.tests; + +/*- + * #%L + * Kendo Tournament Manager (Core) + * %% + * Copyright (C) 2021 - 2024 Softwaremagico + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * #L% + */ + +import com.softwaremagico.kt.core.managers.TeamsOrder; +import com.softwaremagico.kt.core.providers.ClubProvider; +import com.softwaremagico.kt.core.providers.DuelProvider; +import com.softwaremagico.kt.core.providers.FightProvider; +import com.softwaremagico.kt.core.providers.GroupProvider; +import com.softwaremagico.kt.core.providers.ParticipantProvider; +import com.softwaremagico.kt.core.providers.RankingProvider; +import com.softwaremagico.kt.core.providers.RoleProvider; +import com.softwaremagico.kt.core.providers.TeamProvider; +import com.softwaremagico.kt.core.providers.TournamentProvider; +import com.softwaremagico.kt.core.tournaments.BubbleSortTournamentHandler; +import com.softwaremagico.kt.persistence.entities.Club; +import com.softwaremagico.kt.persistence.entities.Fight; +import com.softwaremagico.kt.persistence.entities.Group; +import com.softwaremagico.kt.persistence.entities.Participant; +import com.softwaremagico.kt.persistence.entities.Role; +import com.softwaremagico.kt.persistence.entities.Team; +import com.softwaremagico.kt.persistence.entities.Tournament; +import com.softwaremagico.kt.persistence.values.RoleType; +import com.softwaremagico.kt.persistence.values.Score; +import com.softwaremagico.kt.persistence.values.TournamentType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +import java.util.Collections; +import java.util.List; + +@SpringBootTest +@Test(groups = {"bubleSortTest"}) +public class BubbleSortDrawTest extends AbstractTestNGSpringContextTests { + + private static final String CLUB_NAME = "ClubName"; + private static final String CLUB_COUNTRY = "ClubCountry"; + private static final String CLUB_CITY = "ClubCity"; + private static final int MEMBERS = 3; + private static final int TEAMS = 4; + private static final String TOURNAMENT_NAME = "scoreChampionshipTest"; + private Tournament tournament = null; + + + @Autowired + private TournamentProvider tournamentProvider; + + @Autowired + private ParticipantProvider participantProvider; + + @Autowired + private RoleProvider roleProvider; + + @Autowired + private TeamProvider teamProvider; + + @Autowired + private FightProvider fightProvider; + + @Autowired + private GroupProvider groupProvider; + + @Autowired + private ClubProvider clubProvider; + + @Autowired + private DuelProvider duelProvider; + + @Autowired + private RankingProvider rankingProvider; + + @Autowired + private BubbleSortTournamentHandler bubbleSortTournamentHandler; + + private Club club; + + @Test + public void addClub() { + club = clubProvider.save(new Club(CLUB_NAME, CLUB_COUNTRY, CLUB_CITY)); + } + + @Test(dependsOnMethods = "addClub") + public void addParticipants() { + for (int i = 0; i < MEMBERS * TEAMS; i++) { + participantProvider.save(new Participant(String.format("0000%s", i), String.format("name%s", i), String.format("lastname%s", i), club)); + } + } + + @Test(dependsOnMethods = "addParticipants") + public void addTournament() { + Assert.assertEquals(tournamentProvider.count(), 0); + Tournament newTournament = new Tournament(TOURNAMENT_NAME, 1, MEMBERS, TournamentType.BUBBLE_SORT, null); + tournament = tournamentProvider.save(newTournament); + Assert.assertEquals(tournamentProvider.count(), 1); + } + + @Test(dependsOnMethods = "addTournament") + public void addGroup() { + final Group group = new Group(); + group.setTournament(tournament); + group.setIndex(0); + group.setShiaijo(0); + groupProvider.addGroup(tournament, group); + Assert.assertEquals(groupProvider.count(), 1); + } + + @Test(dependsOnMethods = {"addTournament"}) + public void addRoles() { + for (Participant competitor : participantProvider.getAll()) { + roleProvider.save(new Role(tournament, competitor, RoleType.COMPETITOR)); + } + Assert.assertEquals(roleProvider.count(tournament), participantProvider.count()); + } + + @Test(dependsOnMethods = {"addGroup"}) + public void addTeams() { + int teamIndex = TEAMS; + Team team = null; + int teamMember = 0; + + final Group group = groupProvider.getGroups(tournament).get(0); + + for (Participant competitor : participantProvider.getAll()) { + // Create a new team. + if (team == null) { + team = new Team("Team" + String.format("%02d", teamIndex), tournament); + teamIndex--; + teamMember = 0; + } + + // Add member. + team.addMember(competitor); + team = teamProvider.save(team); + + if (teamMember == 0) { + groupProvider.addTeams(group.getId(), Collections.singletonList(team), null); + } + + teamMember++; + + // Team filled up, create a new team. + if (teamMember >= MEMBERS) { + team = null; + } + } + + Assert.assertEquals(TEAMS, teamProvider.count(tournament)); + } + + @Test(dependsOnMethods = {"addTeams"}) + public void createFights() { + final List tournamentFights = bubbleSortTournamentHandler.createFights(tournament, TeamsOrder.SORTED, 0, null); + //Check group has been created. + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 1); + Assert.assertEquals(groupProvider.getGroups(tournament).get(0).getFights().size(), tournamentFights.size()); + + Assert.assertEquals(tournamentFights.size(), 1); + } + + @Test(dependsOnMethods = {"createFights"}) + public void firstIteration() { + List tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 1); + + //The First fight is team4 vs. team3. It is won by team4 + Assert.assertEquals(tournamentFights.get(tournamentFights.size() - 1).getTeam1().getName(), "Team04"); + Assert.assertEquals(tournamentFights.get(tournamentFights.size() - 1).getTeam2().getName(), "Team03"); + tournamentFights.get(tournamentFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + tournamentFights.forEach(fight -> fight.getDuels().forEach(duel -> duel.setFinished(true))); + fightProvider.save(tournamentFights.get(tournamentFights.size() - 1)); + + //The Second fight must be done team4 vs. team2. It is draw! + bubbleSortTournamentHandler.generateNextFights(tournament, null); + tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 2); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 1); + List groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(0).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team04"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team02"); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //The Third fight must be done team2 vs. team1. It is won by team2 + bubbleSortTournamentHandler.generateNextFights(tournament, null); + tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 3); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 1); + groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(0).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team02"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team01"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //Check calculated order + final List ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(0), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team03"); + Assert.assertEquals(ranking.get(1).getName(), "Team04"); + Assert.assertEquals(ranking.get(2).getName(), "Team01"); + Assert.assertEquals(ranking.get(3).getName(), "Team02"); + } + + @Test(dependsOnMethods = {"firstIteration"}) + public void secondIteration() { + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 1); + Assert.assertEquals(groupProvider.getGroups(tournament).get(0).getLevel(), 0); + bubbleSortTournamentHandler.generateNextFights(tournament, null); + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 2); + Assert.assertEquals(groupProvider.getGroups(tournament).get(1).getLevel(), 1); + + //The First fight is team3 vs. team4. It is won by team3 + List tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 4); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 2); + List groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(1).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team03"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team04"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //The Second fight must be done team3 vs. team1. It is a draw! + bubbleSortTournamentHandler.generateNextFights(tournament, null); + tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 5); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 2); + groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(1).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team03"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team01"); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //Check calculated order previous group + List ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(0), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team03"); + Assert.assertEquals(ranking.get(1).getName(), "Team04"); + Assert.assertEquals(ranking.get(2).getName(), "Team01"); + Assert.assertEquals(ranking.get(3).getName(), "Team02"); + + //Check calculated order current group + ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(1), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team04"); + Assert.assertEquals(ranking.get(1).getName(), "Team03"); + Assert.assertEquals(ranking.get(2).getName(), "Team01"); + Assert.assertEquals(ranking.get(3).getName(), "Team02"); + } + + @Test(dependsOnMethods = {"secondIteration"}) + public void thirdIteration() { + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 2); + Assert.assertEquals(groupProvider.getGroups(tournament).get(1).getLevel(), 1); + bubbleSortTournamentHandler.generateNextFights(tournament, null); + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 3); + Assert.assertEquals(groupProvider.getGroups(tournament).get(2).getLevel(), 2); + + //The First fight is team4 vs. team3. It is a draw! + List tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 6); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 3); + List groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(2).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team04"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team03"); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //Does not generate more fights. The Tournament is over. + Assert.assertTrue(bubbleSortTournamentHandler.generateNextFights(tournament, null).isEmpty()); + + //Check calculated order + final List ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(2), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team04"); + Assert.assertEquals(ranking.get(1).getName(), "Team03"); + Assert.assertEquals(ranking.get(2).getName(), "Team01"); + Assert.assertEquals(ranking.get(3).getName(), "Team02"); + } + + + @AfterClass(alwaysRun = true) + public void deleteTournament() { + groupProvider.delete(tournament); + fightProvider.delete(tournament); + duelProvider.delete(tournament); + teamProvider.delete(tournament); + roleProvider.delete(tournament); + tournamentProvider.delete(tournament); + participantProvider.deleteAll(); + clubProvider.delete(club); + Assert.assertEquals(fightProvider.count(), 0); + Assert.assertEquals(duelProvider.count(), 0); + } +} diff --git a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/BubbleSortReversedTest.java b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/BubbleSortReversedTest.java new file mode 100644 index 000000000..19a3a3ba6 --- /dev/null +++ b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/BubbleSortReversedTest.java @@ -0,0 +1,333 @@ +package com.softwaremagico.kt.core.tests; + +/*- + * #%L + * Kendo Tournament Manager (Core) + * %% + * Copyright (C) 2021 - 2024 Softwaremagico + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * #L% + */ + +import com.softwaremagico.kt.core.managers.TeamsOrder; +import com.softwaremagico.kt.core.providers.ClubProvider; +import com.softwaremagico.kt.core.providers.DuelProvider; +import com.softwaremagico.kt.core.providers.FightProvider; +import com.softwaremagico.kt.core.providers.GroupProvider; +import com.softwaremagico.kt.core.providers.ParticipantProvider; +import com.softwaremagico.kt.core.providers.RankingProvider; +import com.softwaremagico.kt.core.providers.RoleProvider; +import com.softwaremagico.kt.core.providers.TeamProvider; +import com.softwaremagico.kt.core.providers.TournamentProvider; +import com.softwaremagico.kt.core.tournaments.BubbleSortTournamentHandler; +import com.softwaremagico.kt.persistence.entities.Club; +import com.softwaremagico.kt.persistence.entities.Fight; +import com.softwaremagico.kt.persistence.entities.Group; +import com.softwaremagico.kt.persistence.entities.Participant; +import com.softwaremagico.kt.persistence.entities.Role; +import com.softwaremagico.kt.persistence.entities.Team; +import com.softwaremagico.kt.persistence.entities.Tournament; +import com.softwaremagico.kt.persistence.values.RoleType; +import com.softwaremagico.kt.persistence.values.Score; +import com.softwaremagico.kt.persistence.values.TournamentType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +import java.util.Collections; +import java.util.List; + +@SpringBootTest +@Test(groups = {"bubleSortTest"}) +public class BubbleSortReversedTest extends AbstractTestNGSpringContextTests { + + private static final String CLUB_NAME = "ClubName"; + private static final String CLUB_COUNTRY = "ClubCountry"; + private static final String CLUB_CITY = "ClubCity"; + private static final int MEMBERS = 3; + private static final int TEAMS = 4; + private static final String TOURNAMENT_NAME = "scoreChampionshipTest"; + private Tournament tournament = null; + + + @Autowired + private TournamentProvider tournamentProvider; + + @Autowired + private ParticipantProvider participantProvider; + + @Autowired + private RoleProvider roleProvider; + + @Autowired + private TeamProvider teamProvider; + + @Autowired + private FightProvider fightProvider; + + @Autowired + private GroupProvider groupProvider; + + @Autowired + private ClubProvider clubProvider; + + @Autowired + private DuelProvider duelProvider; + + @Autowired + private RankingProvider rankingProvider; + + @Autowired + private BubbleSortTournamentHandler bubbleSortTournamentHandler; + + private Club club; + + @Test + public void addClub() { + club = clubProvider.save(new Club(CLUB_NAME, CLUB_COUNTRY, CLUB_CITY)); + } + + @Test(dependsOnMethods = "addClub") + public void addParticipants() { + for (int i = 0; i < MEMBERS * TEAMS; i++) { + participantProvider.save(new Participant(String.format("0000%s", i), String.format("name%s", i), String.format("lastname%s", i), club)); + } + } + + @Test(dependsOnMethods = "addParticipants") + public void addTournament() { + Assert.assertEquals(tournamentProvider.count(), 0); + Tournament newTournament = new Tournament(TOURNAMENT_NAME, 1, MEMBERS, TournamentType.BUBBLE_SORT, null); + tournament = tournamentProvider.save(newTournament); + Assert.assertEquals(tournamentProvider.count(), 1); + } + + @Test(dependsOnMethods = "addTournament") + public void addGroup() { + final Group group = new Group(); + group.setTournament(tournament); + group.setIndex(0); + group.setShiaijo(0); + groupProvider.addGroup(tournament, group); + Assert.assertEquals(groupProvider.count(), 1); + } + + @Test(dependsOnMethods = {"addTournament"}) + public void addRoles() { + for (Participant competitor : participantProvider.getAll()) { + roleProvider.save(new Role(tournament, competitor, RoleType.COMPETITOR)); + } + Assert.assertEquals(roleProvider.count(tournament), participantProvider.count()); + } + + @Test(dependsOnMethods = {"addGroup"}) + public void addTeams() { + int teamIndex = TEAMS; + Team team = null; + int teamMember = 0; + + final Group group = groupProvider.getGroups(tournament).get(0); + + for (Participant competitor : participantProvider.getAll()) { + // Create a new team. + if (team == null) { + team = new Team("Team" + String.format("%02d", teamIndex), tournament); + teamIndex--; + teamMember = 0; + } + + // Add member. + team.addMember(competitor); + team = teamProvider.save(team); + + if (teamMember == 0) { + groupProvider.addTeams(group.getId(), Collections.singletonList(team), null); + } + + teamMember++; + + // Team filled up, create a new team. + if (teamMember >= MEMBERS) { + team = null; + } + } + + Assert.assertEquals(TEAMS, teamProvider.count(tournament)); + } + + @Test(dependsOnMethods = {"addTeams"}) + public void createFights() { + final List tournamentFights = bubbleSortTournamentHandler.createFights(tournament, TeamsOrder.SORTED, 0, null); + //Check group has been created. + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 1); + Assert.assertEquals(groupProvider.getGroups(tournament).get(0).getFights().size(), tournamentFights.size()); + + Assert.assertEquals(tournamentFights.size(), 1); + } + + @Test(dependsOnMethods = {"createFights"}) + public void firstIteration() { + List tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 1); + + //The First fight is team4 vs. team3. It is won by team4 + Assert.assertEquals(tournamentFights.get(tournamentFights.size() - 1).getTeam1().getName(), "Team04"); + Assert.assertEquals(tournamentFights.get(tournamentFights.size() - 1).getTeam2().getName(), "Team03"); + tournamentFights.get(tournamentFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + tournamentFights.forEach(fight -> fight.getDuels().forEach(duel -> duel.setFinished(true))); + fightProvider.save(tournamentFights.get(tournamentFights.size() - 1)); + + //The Second fight must be done team4 vs. team2. It is won by team4 + bubbleSortTournamentHandler.generateNextFights(tournament, null); + tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 2); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 1); + List groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(0).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team04"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team02"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //The Third fight must be done team4 vs. team1. It is won by team4 + bubbleSortTournamentHandler.generateNextFights(tournament, null); + tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 3); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 1); + groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(0).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team04"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team01"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //Check calculated order + final List ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(0), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team03"); + Assert.assertEquals(ranking.get(1).getName(), "Team02"); + Assert.assertEquals(ranking.get(2).getName(), "Team01"); + Assert.assertEquals(ranking.get(3).getName(), "Team04"); + } + + @Test(dependsOnMethods = {"firstIteration"}) + public void secondIteration() { + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 1); + Assert.assertEquals(groupProvider.getGroups(tournament).get(0).getLevel(), 0); + bubbleSortTournamentHandler.generateNextFights(tournament, null); + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 2); + Assert.assertEquals(groupProvider.getGroups(tournament).get(1).getLevel(), 1); + + //The First fight is team3 vs. team2. It is won by team3 + List tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 4); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 2); + List groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(1).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team03"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team02"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //The Second fight must be done team3 vs. team1. It is won by team3 + bubbleSortTournamentHandler.generateNextFights(tournament, null); + tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 5); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 2); + groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(1).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team03"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team01"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //Check calculated order previous group + List ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(0), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team03"); + Assert.assertEquals(ranking.get(1).getName(), "Team02"); + Assert.assertEquals(ranking.get(2).getName(), "Team01"); + Assert.assertEquals(ranking.get(3).getName(), "Team04"); + + //Check calculated order current group + ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(1), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team02"); + Assert.assertEquals(ranking.get(1).getName(), "Team01"); + Assert.assertEquals(ranking.get(2).getName(), "Team03"); + Assert.assertEquals(ranking.get(3).getName(), "Team04"); + } + + @Test(dependsOnMethods = {"secondIteration"}) + public void thirdIteration() { + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 2); + Assert.assertEquals(groupProvider.getGroups(tournament).get(1).getLevel(), 1); + bubbleSortTournamentHandler.generateNextFights(tournament, null); + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 3); + Assert.assertEquals(groupProvider.getGroups(tournament).get(2).getLevel(), 2); + + //The First fight is team2 vs. team1. It is won by team2 + List tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 6); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 3); + List groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(2).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team02"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team01"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //Does not generate more fights. The Tournament is over. + Assert.assertTrue(bubbleSortTournamentHandler.generateNextFights(tournament, null).isEmpty()); + + //Check calculated order + List ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(2), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team01"); + Assert.assertEquals(ranking.get(1).getName(), "Team02"); + Assert.assertEquals(ranking.get(2).getName(), "Team03"); + Assert.assertEquals(ranking.get(3).getName(), "Team04"); + + //Order is the same if search for global. + ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team01"); + Assert.assertEquals(ranking.get(1).getName(), "Team02"); + Assert.assertEquals(ranking.get(2).getName(), "Team03"); + Assert.assertEquals(ranking.get(3).getName(), "Team04"); + } + + + @AfterClass(alwaysRun = true) + public void deleteTournament() { + groupProvider.delete(tournament); + fightProvider.delete(tournament); + duelProvider.delete(tournament); + teamProvider.delete(tournament); + roleProvider.delete(tournament); + tournamentProvider.delete(tournament); + participantProvider.deleteAll(); + clubProvider.delete(club); + Assert.assertEquals(fightProvider.count(), 0); + Assert.assertEquals(duelProvider.count(), 0); + } +} diff --git a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/BubbleSortTest.java b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/BubbleSortTest.java new file mode 100644 index 000000000..0f3e0c9c2 --- /dev/null +++ b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/BubbleSortTest.java @@ -0,0 +1,325 @@ +package com.softwaremagico.kt.core.tests; + +/*- + * #%L + * Kendo Tournament Manager (Core) + * %% + * Copyright (C) 2021 - 2024 Softwaremagico + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * #L% + */ + +import com.softwaremagico.kt.core.managers.TeamsOrder; +import com.softwaremagico.kt.core.providers.ClubProvider; +import com.softwaremagico.kt.core.providers.DuelProvider; +import com.softwaremagico.kt.core.providers.FightProvider; +import com.softwaremagico.kt.core.providers.GroupProvider; +import com.softwaremagico.kt.core.providers.ParticipantProvider; +import com.softwaremagico.kt.core.providers.RankingProvider; +import com.softwaremagico.kt.core.providers.RoleProvider; +import com.softwaremagico.kt.core.providers.TeamProvider; +import com.softwaremagico.kt.core.providers.TournamentProvider; +import com.softwaremagico.kt.core.tournaments.BubbleSortTournamentHandler; +import com.softwaremagico.kt.persistence.entities.Club; +import com.softwaremagico.kt.persistence.entities.Fight; +import com.softwaremagico.kt.persistence.entities.Group; +import com.softwaremagico.kt.persistence.entities.Participant; +import com.softwaremagico.kt.persistence.entities.Role; +import com.softwaremagico.kt.persistence.entities.Team; +import com.softwaremagico.kt.persistence.entities.Tournament; +import com.softwaremagico.kt.persistence.values.RoleType; +import com.softwaremagico.kt.persistence.values.Score; +import com.softwaremagico.kt.persistence.values.TournamentType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +import java.util.Collections; +import java.util.List; + +@SpringBootTest +@Test(groups = {"bubleSortTest"}) +public class BubbleSortTest extends AbstractTestNGSpringContextTests { + + private static final String CLUB_NAME = "ClubName"; + private static final String CLUB_COUNTRY = "ClubCountry"; + private static final String CLUB_CITY = "ClubCity"; + private static final int MEMBERS = 3; + private static final int TEAMS = 4; + private static final String TOURNAMENT_NAME = "scoreChampionshipTest"; + private Tournament tournament = null; + + + @Autowired + private TournamentProvider tournamentProvider; + + @Autowired + private ParticipantProvider participantProvider; + + @Autowired + private RoleProvider roleProvider; + + @Autowired + private TeamProvider teamProvider; + + @Autowired + private FightProvider fightProvider; + + @Autowired + private GroupProvider groupProvider; + + @Autowired + private ClubProvider clubProvider; + + @Autowired + private DuelProvider duelProvider; + + @Autowired + private RankingProvider rankingProvider; + + @Autowired + private BubbleSortTournamentHandler bubbleSortTournamentHandler; + + private Club club; + + @Test + public void addClub() { + club = clubProvider.save(new Club(CLUB_NAME, CLUB_COUNTRY, CLUB_CITY)); + } + + @Test(dependsOnMethods = "addClub") + public void addParticipants() { + for (int i = 0; i < MEMBERS * TEAMS; i++) { + participantProvider.save(new Participant(String.format("0000%s", i), String.format("name%s", i), String.format("lastname%s", i), club)); + } + } + + @Test(dependsOnMethods = "addParticipants") + public void addTournament() { + Assert.assertEquals(tournamentProvider.count(), 0); + Tournament newTournament = new Tournament(TOURNAMENT_NAME, 1, MEMBERS, TournamentType.BUBBLE_SORT, null); + tournament = tournamentProvider.save(newTournament); + Assert.assertEquals(tournamentProvider.count(), 1); + } + + @Test(dependsOnMethods = "addTournament") + public void addGroup() { + final Group group = new Group(); + group.setTournament(tournament); + group.setIndex(0); + group.setShiaijo(0); + groupProvider.addGroup(tournament, group); + Assert.assertEquals(groupProvider.count(), 1); + } + + @Test(dependsOnMethods = {"addTournament"}) + public void addRoles() { + for (Participant competitor : participantProvider.getAll()) { + roleProvider.save(new Role(tournament, competitor, RoleType.COMPETITOR)); + } + Assert.assertEquals(roleProvider.count(tournament), participantProvider.count()); + } + + @Test(dependsOnMethods = {"addGroup"}) + public void addTeams() { + int teamIndex = 0; + Team team = null; + int teamMember = 0; + + final Group group = groupProvider.getGroups(tournament).get(0); + + for (Participant competitor : participantProvider.getAll()) { + // Create a new team. + if (team == null) { + teamIndex++; + team = new Team("Team" + String.format("%02d", teamIndex), tournament); + teamMember = 0; + } + + // Add member. + team.addMember(competitor); + team = teamProvider.save(team); + + if (teamMember == 0) { + groupProvider.addTeams(group.getId(), Collections.singletonList(team), null); + } + + teamMember++; + + // Team filled up, create a new team. + if (teamMember >= MEMBERS) { + team = null; + } + } + + Assert.assertEquals(TEAMS, teamProvider.count(tournament)); + } + + @Test(dependsOnMethods = {"addTeams"}) + public void createFights() { + final List tournamentFights = bubbleSortTournamentHandler.createFights(tournament, TeamsOrder.SORTED, 0, null); + //Check group has been created. + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 1); + Assert.assertEquals(groupProvider.getGroups(tournament).get(0).getFights().size(), tournamentFights.size()); + + Assert.assertEquals(tournamentFights.size(), 1); + } + + @Test(dependsOnMethods = {"createFights"}) + public void firstIteration() { + List tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 1); + + //The First fight is team1 vs. team2. It is won by team1 + Assert.assertEquals(tournamentFights.get(tournamentFights.size() - 1).getTeam1().getName(), "Team01"); + Assert.assertEquals(tournamentFights.get(tournamentFights.size() - 1).getTeam2().getName(), "Team02"); + tournamentFights.get(tournamentFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + tournamentFights.forEach(fight -> fight.getDuels().forEach(duel -> duel.setFinished(true))); + fightProvider.save(tournamentFights.get(tournamentFights.size() - 1)); + + //The Second fight must be done team1 vs. team3. It is won by team1 + bubbleSortTournamentHandler.generateNextFights(tournament, null); + tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 2); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 1); + List groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(0).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team01"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team03"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //The Third fight must be done team1 vs. team4. It is won by team4 + bubbleSortTournamentHandler.generateNextFights(tournament, null); + tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 3); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 1); + groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(0).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team01"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team04"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor2Score(Score.KOTE); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //Check calculated order + final List ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(0), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team02"); + Assert.assertEquals(ranking.get(1).getName(), "Team03"); + Assert.assertEquals(ranking.get(2).getName(), "Team01"); + Assert.assertEquals(ranking.get(3).getName(), "Team04"); + } + + @Test(dependsOnMethods = {"firstIteration"}) + public void secondIteration() { + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 1); + Assert.assertEquals(groupProvider.getGroups(tournament).get(0).getLevel(), 0); + bubbleSortTournamentHandler.generateNextFights(tournament, null); + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 2); + Assert.assertEquals(groupProvider.getGroups(tournament).get(1).getLevel(), 1); + + //The First fight is team2 vs. team3. It is won by team3 + List tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 4); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 2); + List groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(1).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team02"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team03"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor2Score(Score.KOTE); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //The Second fight must be done team3 vs. team1. It is won by team1 + bubbleSortTournamentHandler.generateNextFights(tournament, null); + tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 5); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 2); + groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(1).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team03"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team01"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //Check calculated order previous group + List ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(0), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team02"); + Assert.assertEquals(ranking.get(1).getName(), "Team03"); + Assert.assertEquals(ranking.get(2).getName(), "Team01"); + Assert.assertEquals(ranking.get(3).getName(), "Team04"); + + //Check calculated order current group + ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(1), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team02"); + Assert.assertEquals(ranking.get(1).getName(), "Team01"); + Assert.assertEquals(ranking.get(2).getName(), "Team03"); + Assert.assertEquals(ranking.get(3).getName(), "Team04"); + } + + @Test(dependsOnMethods = {"secondIteration"}) + public void thirdIteration() { + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 2); + Assert.assertEquals(groupProvider.getGroups(tournament).get(1).getLevel(), 1); + bubbleSortTournamentHandler.generateNextFights(tournament, null); + Assert.assertEquals(groupProvider.getGroups(tournament).size(), 3); + Assert.assertEquals(groupProvider.getGroups(tournament).get(2).getLevel(), 2); + + //The First fight is team2 vs. team3. It is won by team2 + List tournamentFights = fightProvider.getFights(tournament); + Assert.assertEquals(tournamentFights.size(), 6); + Assert.assertEquals(bubbleSortTournamentHandler.getGroups(tournament).size(), 3); + List groupFights = bubbleSortTournamentHandler.getGroups(tournament).get(2).getFights(); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam1().getName(), "Team02"); + Assert.assertEquals(groupFights.get(groupFights.size() - 1).getTeam2().getName(), "Team01"); + groupFights.get(groupFights.size() - 1).getDuels().get(0).addCompetitor1Score(Score.DO); + groupFights.get(groupFights.size() - 1).getDuels().forEach(duel -> duel.setFinished(true)); + fightProvider.save(groupFights.get(groupFights.size() - 1)); + + //Does not generate more fights. The Tournament is over. + Assert.assertTrue(bubbleSortTournamentHandler.generateNextFights(tournament, null).isEmpty()); + + //Check calculated order + final List ranking = bubbleSortTournamentHandler.getTeamsOrderedByRanks(tournament, groupProvider.getGroups(tournament).get(2), + bubbleSortTournamentHandler.getDrawResolution(tournament)); + Assert.assertEquals(ranking.size(), 4); + Assert.assertEquals(ranking.get(0).getName(), "Team01"); + Assert.assertEquals(ranking.get(1).getName(), "Team02"); + Assert.assertEquals(ranking.get(2).getName(), "Team03"); + Assert.assertEquals(ranking.get(3).getName(), "Team04"); + } + + + @AfterClass(alwaysRun = true) + public void deleteTournament() { + groupProvider.delete(tournament); + fightProvider.delete(tournament); + duelProvider.delete(tournament); + teamProvider.delete(tournament); + roleProvider.delete(tournament); + tournamentProvider.delete(tournament); + participantProvider.deleteAll(); + clubProvider.delete(club); + Assert.assertEquals(fightProvider.count(), 0); + Assert.assertEquals(duelProvider.count(), 0); + } +} diff --git a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainFiFoTest.java b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainFiFoTest.java index 1414752b1..61f723bc7 100644 --- a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainFiFoTest.java +++ b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainFiFoTest.java @@ -263,7 +263,7 @@ public void loopStartsAgain() { Assert.assertEquals(tournamentFights.get(3).getTeam1().getName(), "Team01"); Assert.assertEquals(tournamentFights.get(3).getTeam2().getName(), "Team02"); - //Finish the fight. Team1 loose now + //Finish the fight. Team1 loses now tournamentFights.get(3).getDuels().get(0).addCompetitor2Score(Score.KOTE); tournamentFights.get(3).getDuels().forEach(duel -> duel.setFinished(true)); fightProvider.save(tournamentFights.get(3)); diff --git a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainLiFoTest.java b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainLiFoTest.java index dd7f1a75a..a327a2066 100644 --- a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainLiFoTest.java +++ b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainLiFoTest.java @@ -263,7 +263,7 @@ public void loopStartsAgain() { Assert.assertEquals(tournamentFights.get(3).getTeam1().getName(), "Team01"); Assert.assertEquals(tournamentFights.get(3).getTeam2().getName(), "Team02"); - //Finish the fight. Team1 loose now + //Finish the fight. Team1 loses now tournamentFights.get(3).getDuels().get(0).addCompetitor2Score(Score.KOTE); tournamentFights.get(3).getDuels().forEach(duel -> duel.setFinished(true)); fightProvider.save(tournamentFights.get(3)); diff --git a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainTest.java b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainTest.java index 4e49b94bc..e97f87215 100644 --- a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainTest.java +++ b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/KingOfTheMountainTest.java @@ -250,7 +250,7 @@ public void loopStartsAgain() { Assert.assertNotEquals(tournamentFights.get(3).getTeam2(), tournamentFights.get(2).getTeam2()); Assert.assertEquals(tournamentFights.get(3).getTeam2().getName(), "Team02"); - //Finish the fight. Team1 loose now + //Finish the fight. Team1 lose now tournamentFights.get(3).getDuels().get(0).addCompetitor2Score(Score.KOTE); tournamentFights.get(3).getDuels().forEach(duel -> duel.setFinished(true)); fightProvider.save(tournamentFights.get(3)); diff --git a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/QrTests.java b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/QrTests.java index 0dce1efee..1ed68b93d 100644 --- a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/QrTests.java +++ b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/QrTests.java @@ -42,7 +42,7 @@ @Test(groups = {"qrTest"}) public class QrTests extends AbstractTestNGSpringContextTests { - private final static String LOGO = "/kote.png"; + private static final String LOGO = "/kote.png"; private static final Color COLOR = Color.decode("#011d4a"); diff --git a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/TournamentExtraPropertiesTest.java b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/TournamentExtraPropertiesTest.java index cd13e0626..02b0f20a1 100644 --- a/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/TournamentExtraPropertiesTest.java +++ b/backend/kendo-tournament-core/src/test/java/com/softwaremagico/kt/core/tests/TournamentExtraPropertiesTest.java @@ -39,7 +39,7 @@ @Test(groups = {"tournamentExtraProperties"}) public class TournamentExtraPropertiesTest extends AbstractTransactionalTestNGSpringContextTests { - private final static String USER = "Me"; + private static final String USER = "Me"; @Autowired private TournamentProvider tournamentProvider; diff --git a/backend/kendo-tournament-core/src/test/resources/testng.xml b/backend/kendo-tournament-core/src/test/resources/testng.xml index 459c997cc..526a0f35b 100644 --- a/backend/kendo-tournament-core/src/test/resources/testng.xml +++ b/backend/kendo-tournament-core/src/test/resources/testng.xml @@ -11,6 +11,7 @@ + @@ -44,6 +45,9 @@ + + + diff --git a/backend/kendo-tournament-logger/src/main/java/com/softwaremagico/kt/logger/BasicLogger.java b/backend/kendo-tournament-logger/src/main/java/com/softwaremagico/kt/logger/BasicLogger.java index 7326627a4..94668b392 100644 --- a/backend/kendo-tournament-logger/src/main/java/com/softwaremagico/kt/logger/BasicLogger.java +++ b/backend/kendo-tournament-logger/src/main/java/com/softwaremagico/kt/logger/BasicLogger.java @@ -59,7 +59,8 @@ public static void warning(Logger logger, String className, String messageTempla arguments[i] = arguments[i].toString().replaceAll("[\n\r\t]", "_"); } } - logger.warn(className + ": " + messageTemplate, arguments); + final String templateWithClass = className + ": " + messageTemplate; + logger.warn(templateWithClass, arguments); } /** diff --git a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/encryption/BCryptPasswordConverter.java b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/encryption/BCryptPasswordConverter.java index aba4f6d4b..58a22b41d 100644 --- a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/encryption/BCryptPasswordConverter.java +++ b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/encryption/BCryptPasswordConverter.java @@ -30,7 +30,7 @@ @Converter public class BCryptPasswordConverter implements AttributeConverter { //From org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder - private static final Pattern BCRYPT_PATTERN = Pattern.compile("\\A\\$2(a|y|b)?\\$(\\d\\d)\\$[./0-9A-Za-z]{53}"); + private static final Pattern BCRYPT_PATTERN = Pattern.compile("\\A\\$2([ayb])?\\$(\\d\\d)\\$[./0-9A-Za-z]{53}"); private BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); diff --git a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/entities/Fight.java b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/entities/Fight.java index 3dfa9cb42..80a88ffda 100644 --- a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/entities/Fight.java +++ b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/entities/Fight.java @@ -167,7 +167,7 @@ public Team getWinner() { return null; } - public Team getLooser() { + public Team getLoser() { final Team winner = getWinner(); if (winner == null) { return null; diff --git a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/repositories/FightRepository.java b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/repositories/FightRepository.java index fb3adeb29..88e505b58 100644 --- a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/repositories/FightRepository.java +++ b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/repositories/FightRepository.java @@ -56,6 +56,8 @@ public interface FightRepository extends JpaRepository { long deleteByTournament(Tournament tournament); + long deleteByTournamentAndLevelGreaterThanEqual(Tournament tournament, int level); + Optional findFirstByTournamentOrderByLevelDesc(Tournament tournament); @Query(""" diff --git a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/repositories/GroupRepository.java b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/repositories/GroupRepository.java index 7de9774f8..a835aefe0 100644 --- a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/repositories/GroupRepository.java +++ b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/repositories/GroupRepository.java @@ -39,6 +39,8 @@ public interface GroupRepository extends JpaRepository { List findByTournamentAndLevelOrderByLevelAscIndexAsc(Tournament tournament, Integer level); + List findByTournamentAndLevelIsGreaterThanEqual(Tournament tournament, Integer level); + Group findByTournamentAndLevelAndIndex(Tournament tournament, Integer level, Integer index); int deleteByTournamentAndLevelAndIndex(Tournament tournament, Integer level, Integer index); diff --git a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/values/TournamentExtraPropertyKey.java b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/values/TournamentExtraPropertyKey.java index 38ac60aac..8e8160564 100644 --- a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/values/TournamentExtraPropertyKey.java +++ b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/values/TournamentExtraPropertyKey.java @@ -21,15 +21,26 @@ * #L% */ +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + public enum TournamentExtraPropertyKey { - MAXIMIZE_FIGHTS, - AVOID_DUPLICATES, - KING_INDEX, - KING_DRAW_RESOLUTION, - DIPLOMA_NAME_HEIGHT, - NUMBER_OF_WINNERS, - LEAGUE_FIGHTS_ORDER_GENERATION, - ODD_FIGHTS_RESOLVED_ASAP; + MAXIMIZE_FIGHTS(TournamentType.LEAGUE, TournamentType.CHAMPIONSHIP, TournamentType.CUSTOM_CHAMPIONSHIP, TournamentType.TREE), + AVOID_DUPLICATES(TournamentType.LOOP), + KING_INDEX(TournamentType.KING_OF_THE_MOUNTAIN, TournamentType.BUBBLE_SORT), + KING_DRAW_RESOLUTION(TournamentType.KING_OF_THE_MOUNTAIN, TournamentType.BUBBLE_SORT), + DIPLOMA_NAME_HEIGHT(TournamentType.values()), + NUMBER_OF_WINNERS(TournamentType.CHAMPIONSHIP, TournamentType.TREE, TournamentType.CUSTOM_CHAMPIONSHIP, TournamentType.LEAGUE), + LEAGUE_FIGHTS_ORDER_GENERATION(TournamentType.LEAGUE, TournamentType.CHAMPIONSHIP, TournamentType.TREE, TournamentType.CUSTOM_CHAMPIONSHIP), + ODD_FIGHTS_RESOLVED_ASAP(TournamentType.CHAMPIONSHIP, TournamentType.TREE, TournamentType.CUSTOM_CHAMPIONSHIP), + BUBBLE_SORT_ITERATION(TournamentType.BUBBLE_SORT); + + private final Set allowedTournaments; + + TournamentExtraPropertyKey(TournamentType... allowedTournaments) { + this.allowedTournaments = new HashSet<>(Arrays.asList(allowedTournaments)); + } public static TournamentExtraPropertyKey getType(String name) { @@ -40,4 +51,8 @@ public static TournamentExtraPropertyKey getType(String name) { } return null; } + + public Set getAllowedTournaments() { + return allowedTournaments; + } } diff --git a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/values/TournamentType.java b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/values/TournamentType.java index c5d0192da..05c599a48 100644 --- a/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/values/TournamentType.java +++ b/backend/kendo-tournament-persistence/src/main/java/com/softwaremagico/kt/persistence/values/TournamentType.java @@ -35,6 +35,8 @@ public enum TournamentType { KING_OF_THE_MOUNTAIN, + BUBBLE_SORT, + CUSTOMIZED; public static TournamentType getType(String name) { diff --git a/backend/kendo-tournament-persistence/src/test/java/com/softwaremagico/kt/persistence/repositories/ParticipantImageRepositoryTests.java b/backend/kendo-tournament-persistence/src/test/java/com/softwaremagico/kt/persistence/repositories/ParticipantImageRepositoryTests.java index 364baa91b..b140d7aed 100644 --- a/backend/kendo-tournament-persistence/src/test/java/com/softwaremagico/kt/persistence/repositories/ParticipantImageRepositoryTests.java +++ b/backend/kendo-tournament-persistence/src/test/java/com/softwaremagico/kt/persistence/repositories/ParticipantImageRepositoryTests.java @@ -44,7 +44,7 @@ @Test(groups = {"imageRepository"}) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public class ParticipantImageRepositoryTests extends AbstractTestNGSpringContextTests { - private final static String IMAGE_RESOURCE = "kendo.jpg"; + private static final String IMAGE_RESOURCE = "kendo.jpg"; @Autowired private ParticipantImageRepository photoRepository; diff --git a/backend/kendo-tournament-rest/src/main/java/com/softwaremagico/kt/rest/exceptions/ErrorResponse.java b/backend/kendo-tournament-rest/src/main/java/com/softwaremagico/kt/rest/exceptions/ErrorResponse.java index 0c88440cc..99e67392b 100644 --- a/backend/kendo-tournament-rest/src/main/java/com/softwaremagico/kt/rest/exceptions/ErrorResponse.java +++ b/backend/kendo-tournament-rest/src/main/java/com/softwaremagico/kt/rest/exceptions/ErrorResponse.java @@ -62,7 +62,7 @@ public String getCode() { return code; } if (message != null) { - return message.replaceAll(" ", "_").toLowerCase(); + return message.replace(" ", "_").toLowerCase(); } return null; } diff --git a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/ParticipantAccessTests.java b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/ParticipantAccessTests.java index afa95f071..db019c74d 100644 --- a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/ParticipantAccessTests.java +++ b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/ParticipantAccessTests.java @@ -60,17 +60,17 @@ @Test(groups = "participantAccess") public class ParticipantAccessTests extends AbstractTestNGSpringContextTests { - private final static String USER_FIRST_NAME = "Test"; - private final static String USER_LAST_NAME = "User"; + private static final String USER_FIRST_NAME = "Test"; + private static final String USER_LAST_NAME = "User"; private static final String USER_NAME = USER_FIRST_NAME + "." + USER_LAST_NAME; private static final String USER_PASSWORD = "password"; private static final String[] USER_ROLES = new String[]{"admin", "viewer"}; - private final static String CLUB_NAME = "Club"; + private static final String CLUB_NAME = "Club"; - private final static String PARTICIPANT_NAME = "Participant Name"; - private final static String PARTICIPANT_LASTNAME = "Participant Last Name"; + private static final String PARTICIPANT_NAME = "Participant Name"; + private static final String PARTICIPANT_LASTNAME = "Participant Last Name"; @Autowired private ObjectMapper objectMapper; diff --git a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/RestSimpleChampionshipTest.java b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/RestSimpleChampionshipTest.java index 788bd6b97..b653714d2 100644 --- a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/RestSimpleChampionshipTest.java +++ b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/RestSimpleChampionshipTest.java @@ -82,8 +82,8 @@ public class RestSimpleChampionshipTest extends AbstractTestNGSpringContextTests { private static final String USER_NAME = "admin"; - private final static String USER_FIRST_NAME = "Test"; - private final static String USER_LAST_NAME = "User"; + private static final String USER_FIRST_NAME = "Test"; + private static final String USER_LAST_NAME = "User"; private static final String USER_PASSWORD = "asd123"; private static final String[] USER_ROLES = new String[]{"admin", "viewer"}; diff --git a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/UserRegisterTests.java b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/UserRegisterTests.java index 49a902371..92a7cea77 100644 --- a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/UserRegisterTests.java +++ b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/rest/UserRegisterTests.java @@ -57,8 +57,8 @@ @Test(groups = "userRegister") public class UserRegisterTests extends AbstractTestNGSpringContextTests { - private final static String USER_FIRST_NAME = "Test"; - private final static String USER_LAST_NAME = "User"; + private static final String USER_FIRST_NAME = "Test"; + private static final String USER_LAST_NAME = "User"; private static final String USER_NAME = USER_FIRST_NAME + "." + USER_LAST_NAME; private static final String USER_PASSWORD = "password"; diff --git a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/BruteForceTests.java b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/BruteForceTests.java index 34c6fa986..853a67ac2 100644 --- a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/BruteForceTests.java +++ b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/BruteForceTests.java @@ -54,10 +54,10 @@ @ExtendWith(MockitoExtension.class) @Test(groups = "bruteForce") public class BruteForceTests extends AbstractTestNGSpringContextTests { - private final static String USER_NAME = "user"; - private final static String USER_FIRST_NAME = "Test"; - private final static String USER_LAST_NAME = "User"; - private final static String USER_PASSWORD = "password"; + private static final String USER_NAME = "user"; + private static final String USER_FIRST_NAME = "Test"; + private static final String USER_LAST_NAME = "User"; + private static final String USER_PASSWORD = "password"; private MockMvc mockMvc; diff --git a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/PasswordTests.java b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/PasswordTests.java index db3bdbc11..6483a1ceb 100644 --- a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/PasswordTests.java +++ b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/PasswordTests.java @@ -34,8 +34,8 @@ @SpringBootTest public class PasswordTests extends AbstractTestNGSpringContextTests { private static final String USER_NAME = "user"; - private final static String USER_FIRST_NAME = "Test"; - private final static String USER_LAST_NAME = "User"; + private static final String USER_FIRST_NAME = "Test"; + private static final String USER_LAST_NAME = "User"; private static final String USER_PASSWORD = "password"; private static final String USER_NEW_PASSWORD = "password2"; diff --git a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/TestAuthApi.java b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/TestAuthApi.java index 8319717b2..cf801e190 100644 --- a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/TestAuthApi.java +++ b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/TestAuthApi.java @@ -59,21 +59,21 @@ @Test(groups = "authApi") public class TestAuthApi extends AbstractTestNGSpringContextTests { private static final String USER_NAME = "user"; - private final static String USER_FIRST_NAME = "Test"; - private final static String USER_LAST_NAME = "User"; + private static final String USER_FIRST_NAME = "Test"; + private static final String USER_LAST_NAME = "User"; - private final static String USER_NEW_FIRST_NAME = "New Test"; - private final static String USER_NEW_LAST_NAME = "New User"; + private static final String USER_NEW_FIRST_NAME = "New Test"; + private static final String USER_NEW_LAST_NAME = "New User"; private static final String USER_PASSWORD = "password"; private static final String[] USER_ROLES = new String[]{"admin", "viewer"}; private static final String USER2_NAME = "user2"; - private final static String USER2_FIRST_NAME = "Test2"; - private final static String USER2_LAST_NAME = "User2"; + private static final String USER2_FIRST_NAME = "Test2"; + private static final String USER2_LAST_NAME = "User2"; private static final String USER2_PASSWORD = "password"; - private final static String USER2_NEW_FIRST_NAME = "New Test2"; - private final static String USER2_NEW_LAST_NAME = "New User2"; + private static final String USER2_NEW_FIRST_NAME = "New Test2"; + private static final String USER2_NEW_LAST_NAME = "New User2"; private MockMvc mockMvc; diff --git a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/UserRegistrationTest.java b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/UserRegistrationTest.java index d19e37f67..702b71024 100644 --- a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/UserRegistrationTest.java +++ b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/security/UserRegistrationTest.java @@ -61,10 +61,10 @@ public class UserRegistrationTest extends AbstractTestNGSpringContextTests { public static final String USER_NAME_2 = "Goku"; public static final String USER_FIRST_NAME_2 = "Goku"; public static final String USER_LAST_NAME_2 = "Son"; - private final static String USER_NAME = "user"; - private final static String USER_FIRST_NAME = "Test"; - private final static String USER_LAST_NAME = "User"; - private final static String USER_PASSWORD = "password"; + private static final String USER_NAME = "user"; + private static final String USER_FIRST_NAME = "Test"; + private static final String USER_LAST_NAME = "User"; + private static final String USER_PASSWORD = "password"; private static final String[] USER_ROLES = new String[] {"admin", "viewer"}; @Autowired diff --git a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/websockets/BasicWebsocketsTests.java b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/websockets/BasicWebsocketsTests.java index 378c65908..2dab26fb0 100644 --- a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/websockets/BasicWebsocketsTests.java +++ b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/websockets/BasicWebsocketsTests.java @@ -66,8 +66,8 @@ @AutoConfigureMockMvc(addFilters = false) public class BasicWebsocketsTests extends AbstractTestNGSpringContextTests { - private final static String USER_FIRST_NAME = "Test"; - private final static String USER_LAST_NAME = "User"; + private static final String USER_FIRST_NAME = "Test"; + private static final String USER_LAST_NAME = "User"; private static final String USER_NAME = USER_FIRST_NAME + "." + USER_LAST_NAME; private static final String USER_PASSWORD = "password"; diff --git a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/websockets/FightsWebsocketsTests.java b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/websockets/FightsWebsocketsTests.java index 72847a208..88940c69c 100644 --- a/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/websockets/FightsWebsocketsTests.java +++ b/backend/kendo-tournament-rest/src/test/java/com/softwaremagico/kt/websockets/FightsWebsocketsTests.java @@ -66,8 +66,8 @@ @AutoConfigureMockMvc(addFilters = false) public class FightsWebsocketsTests extends AbstractTestNGSpringContextTests { - private final static String USER_FIRST_NAME = "Test"; - private final static String USER_LAST_NAME = "User"; + private static final String USER_FIRST_NAME = "Test"; + private static final String USER_LAST_NAME = "User"; private static final String USER_NAME = USER_FIRST_NAME + "." + USER_LAST_NAME; private static final String USER_PASSWORD = "password"; diff --git a/docker/backend/Dockerfile b/docker/backend/Dockerfile index 5dd7a1f19..f7d567491 100644 --- a/docker/backend/Dockerfile +++ b/docker/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM eclipse-temurin:17-jre +FROM eclipse-temurin:22-jdk-alpine ARG release ARG machine_domain diff --git a/frontend/src/app/models/tournament-type.ts b/frontend/src/app/models/tournament-type.ts index edcb9b61d..f7b5c92e8 100644 --- a/frontend/src/app/models/tournament-type.ts +++ b/frontend/src/app/models/tournament-type.ts @@ -4,6 +4,7 @@ export enum TournamentType { LOOP = 'LOOP', // CUSTOM_CHAMPIONSHIP = 'CUSTOM_CHAMPIONSHIP', KING_OF_THE_MOUNTAIN = 'KING_OF_THE_MOUNTAIN', + BUBBLE_SORT = 'BUBBLE_SORT', CUSTOMIZED = 'CUSTOMIZED' } @@ -44,7 +45,7 @@ export namespace TournamentType { } export function needsDrawResolution(type: TournamentType | undefined): boolean { - return type === TournamentType.KING_OF_THE_MOUNTAIN; + return type === TournamentType.KING_OF_THE_MOUNTAIN || type === TournamentType.BUBBLE_SORT; } export function needsFifoWinner(type: TournamentType | undefined): boolean { diff --git a/frontend/src/app/views/fight-list/fight-list.component.html b/frontend/src/app/views/fight-list/fight-list.component.html index 759878f9c..dafa92aa2 100644 --- a/frontend/src/app/views/fight-list/fight-list.component.html +++ b/frontend/src/app/views/fight-list/fight-list.component.html @@ -18,14 +18,16 @@ matTooltip="{{'wizard' | translate}}"> auto_fix_high - - - + diff --git a/frontend/src/app/views/fight-list/league-generator/league-generator.component.ts b/frontend/src/app/views/fight-list/league-generator/league-generator.component.ts index 8440b1328..8a305d77e 100644 --- a/frontend/src/app/views/fight-list/league-generator/league-generator.component.ts +++ b/frontend/src/app/views/fight-list/league-generator/league-generator.component.ts @@ -65,7 +65,13 @@ export class LeagueGeneratorComponent extends RbacBasedComponent implements OnIn this.action = data.action; this.actionName = Action[data.action]; this.tournament = data.tournament; - this.drawResolution = DrawResolution.toArray(); + if (this.tournament.type === TournamentType.KING_OF_THE_MOUNTAIN) { + this.drawResolution = DrawResolution.toArray(); + } else if (TournamentType.BUBBLE_SORT) { + this.drawResolution = [DrawResolution.OLDEST_ELIMINATED, DrawResolution.NEWEST_ELIMINATED]; + } else { + this.drawResolution = []; + } this.canMaximizeFights = TournamentType.canMaximizeFights(this.tournament.type); this.needsDrawResolution = TournamentType.needsDrawResolution(this.tournament.type); @@ -215,7 +221,7 @@ export class LeagueGeneratorComponent extends RbacBasedComponent implements OnIn this.teamsOrder.push(...sortedTeams.values()); this.teamListData.teams = []; this.teamListData.filteredTeams = []; - if (this.tournament.type == TournamentType.LOOP) { + if (this.tournament.type == TournamentType.LOOP || this.tournament.type == TournamentType.BUBBLE_SORT) { this.teamsOrder = this.teamsOrder.reverse(); } }); diff --git a/frontend/src/app/views/tournament-list/tournament-dialog-box/tournament-dialog-box.component.html b/frontend/src/app/views/tournament-list/tournament-dialog-box/tournament-dialog-box.component.html index e3bea4e41..f3aaf9bf1 100644 --- a/frontend/src/app/views/tournament-list/tournament-dialog-box/tournament-dialog-box.component.html +++ b/frontend/src/app/views/tournament-list/tournament-dialog-box/tournament-dialog-box.component.html @@ -1,13 +1,13 @@ -

{{title}}

+

{{ title }}

- {{'tournamentType' | translate}} + {{ 'tournamentType' | translate }} - {{getTournamentTypeTranslationTag(type) | translate}} + {{ getTournamentTypeTranslationTag(type) | translate }} @@ -29,7 +29,8 @@

{{title}}

@@ -38,15 +39,15 @@

{{title}}

placeholder="{{'tournamentTeamSize' | translate}}">
- - {{'scoreRules' | translate}} + + {{ 'scoreRules' | translate }} - {{type.toLowerCase() | translate}} + {{ type.toLowerCase() | translate }} @@ -58,12 +59,12 @@

{{title}}

- {{'tournamentDuelsDurations' | translate}} + {{ 'tournamentDuelsDurations' | translate }} - {{number}} {{'seconds' | translate}} - ({{getMinutes(number)}} {{'minutes' | translate}} {{getSeconds(number)}} {{'seconds' | translate}}) + {{ number }} {{ 'seconds' | translate }} + ({{ getMinutes(number) }} {{ 'minutes' | translate }} {{ getSeconds(number) }} {{ 'seconds' | translate }}) @@ -79,17 +80,17 @@

{{title}}

mat-raised-button type="button"> image - {{'images' | translate}} + {{ 'images' | translate }} diff --git a/frontend/src/app/views/tournament-list/tournament-dialog-box/tournament-dialog-box.component.ts b/frontend/src/app/views/tournament-list/tournament-dialog-box/tournament-dialog-box.component.ts index 1e921f652..807666f12 100644 --- a/frontend/src/app/views/tournament-list/tournament-dialog-box/tournament-dialog-box.component.ts +++ b/frontend/src/app/views/tournament-list/tournament-dialog-box/tournament-dialog-box.component.ts @@ -31,6 +31,7 @@ export class TournamentDialogBoxComponent extends RbacBasedComponent { typeLeague: TournamentType = TournamentType.LEAGUE; typeKing: TournamentType = TournamentType.KING_OF_THE_MOUNTAIN; typeCustom: TournamentType = TournamentType.CUSTOMIZED; + typeSorting: TournamentType = TournamentType.BUBBLE_SORT; scoreTypeCustom: ScoreType = ScoreType.CUSTOM; selectedScore: ScoreType; @@ -169,4 +170,6 @@ export class TournamentDialogBoxComponent extends RbacBasedComponent { getSeconds(time: number): number { return time % 60; } + + protected readonly TournamentType = TournamentType; } diff --git a/frontend/src/assets/i18n/ca.json b/frontend/src/assets/i18n/ca.json index fbb03bd4f..75023d565 100644 --- a/frontend/src/assets/i18n/ca.json +++ b/frontend/src/assets/i18n/ca.json @@ -708,5 +708,7 @@ "teamsOrder": "Ordre dels equips:", "web": "Web", "oddFightsResolvedAsap": "Resol les exempcions sense combats com més aviat millor", - "oddFightsResolvedAsapHint": "Si el nombre d'equips o grups del torneig és imparell, és possible que durant els encreuament alguns equips no tinguin combats associats i es classifiquin per a la fase següent automàticament (exempcions). Amb aquesta opció t'assegures que aquests casos es resolen com més aviat millor." + "oddFightsResolvedAsapHint": "Si el nombre d'equips o grups del torneig és imparell, és possible que durant els encreuament alguns equips no tinguin combats associats i es classifiquin per a la fase següent automàticament (exempcions). Amb aquesta opció t'assegures que aquests casos es resolen com més aviat millor.", + "bubbleSort": "Torneig Destronar el Rei", + "bubbleSortHint": "Competidors amb pitjors rangs intenten pujar al seu rànquing fins a guanyar el rei. Qui no ho aconsegueix es converteix en el seu vasai i lluita per protegir el rei." } diff --git a/frontend/src/assets/i18n/de.json b/frontend/src/assets/i18n/de.json index 08ee10368..bd4bd475b 100644 --- a/frontend/src/assets/i18n/de.json +++ b/frontend/src/assets/i18n/de.json @@ -686,5 +686,7 @@ }, "daysFrom": "Bewerben Sie sich nur noch an diesen Tagen", "oddFightsResolvedAsap": "Ausnahmen so schnell wie möglich kampflos lösen", - "oddFightsResolvedAsapHint": "Wenn die Anzahl der Mannschaften oder Gruppen im Turnier ungerade ist, ist es möglich, dass einige Mannschaften während der Spiele keine zugehörigen Spiele haben und sich automatisch für die nächste Phase qualifizieren. Mit dieser Option stellen Sie sicher, dass diese Fälle schnellstmöglich gelöst werden." + "oddFightsResolvedAsapHint": "Wenn die Anzahl der Mannschaften oder Gruppen im Turnier ungerade ist, ist es möglich, dass einige Mannschaften während der Spiele keine zugehörigen Spiele haben und sich automatisch für die nächste Phase qualifizieren. Mit dieser Option stellen Sie sicher, dass diese Fälle schnellstmöglich gelöst werden.", + "bubbleSort": "Entthrone das Königsturnier", + "bubbleSortHint": "Konkurrenten mit niedrigeren Rängen versuchen in ihrer Rangliste aufzusteigen, bis sie den König schlagen. Wem es nicht gelingt, wird sein Vasall und kämpft für den Schutz des Königs." } diff --git a/frontend/src/assets/i18n/en.json b/frontend/src/assets/i18n/en.json index 163cb49de..e9825c91a 100644 --- a/frontend/src/assets/i18n/en.json +++ b/frontend/src/assets/i18n/en.json @@ -703,5 +703,7 @@ }, "daysFrom": "Apply only these days", "oddFightsResolvedAsap": "Resolve team byes as soon as possible", - "oddFightsResolvedAsapHint": "If the number of teams or groups in the tournament is odd, it is possible that during the matches some teams do not have associated matches and qualify for the next phase automatically (byes). With this option you ensure that byes are resolved as soon as possible." + "oddFightsResolvedAsapHint": "If the number of teams or groups in the tournament is odd, it is possible that during the matches some teams do not have associated matches and qualify for the next phase automatically (byes). With this option you ensure that byes are resolved as soon as possible.", + "bubbleSort": "Dethrone the King Tournament", + "bubbleSortHint": "Competitors with lower ranks try to rise in their ranking until they beat the king. He who does not succeed becomes his vassal and fights to protect the king." } diff --git a/frontend/src/assets/i18n/es.json b/frontend/src/assets/i18n/es.json index d53a50fc4..39e227174 100644 --- a/frontend/src/assets/i18n/es.json +++ b/frontend/src/assets/i18n/es.json @@ -704,5 +704,7 @@ }, "daysFrom": "Aplica solo estos días", "oddFightsResolvedAsap": "Resuelve las exenciones sin combates lo antes posible", - "oddFightsResolvedAsapHint": "Si el numero de equipos o grupos del torneo es impar, es posible que durante los cruces algunos equipos no tengan combates asociados y se clasifiquen para la fase siguiente automaticamente (exenciones). Con esta opción te aseguras que estos casos se resuelven lo antes posible." + "oddFightsResolvedAsapHint": "Si el numero de equipos o grupos del torneo es impar, es posible que durante los cruces algunos equipos no tengan combates asociados y se clasifiquen para la fase siguiente automaticamente (exenciones). Con esta opción te aseguras que estos casos se resuelven lo antes posible.", + "bubbleSort": "Torneo Destronar al Rey", + "bubbleSortHint": "Competidores con peores rangos intentan subir en su ranking hasta ganar al rey. El que no lo consigue se convierte en su vasayo y lucha por proteger al rey." } diff --git a/frontend/src/assets/i18n/it.json b/frontend/src/assets/i18n/it.json index 35364c6e9..e43977a83 100644 --- a/frontend/src/assets/i18n/it.json +++ b/frontend/src/assets/i18n/it.json @@ -692,5 +692,7 @@ }, "daysFrom": "Applicare solo in questi giorni", "oddFightsResolvedAsap": "Risolvere le esenzioni senza combattimenti il prima possibile", - "oddFightsResolvedAsapHint": "Se il numero di squadre o gruppi nel torneo è dispari, è possibile che durante le partite alcune squadre non abbiano partite associate e si qualifichino automaticamente alla fase successiva (esenzioni). Con questa opzione ti assicuri che questi casi vengano risolti il prima possibile." + "oddFightsResolvedAsapHint": "Se il numero di squadre o gruppi nel torneo è dispari, è possibile che durante le partite alcune squadre non abbiano partite associate e si qualifichino automaticamente alla fase successiva (esenzioni). Con questa opzione ti assicuri che questi casi vengano risolti il prima possibile.", + "bubbleSort": "Torneo Detronizzare il Re", + "bubbleSortHint": "I concorrenti con ranghi inferiori cercano di salire nella loro classifica fino a battere il re. Chi non ci riesce diventa suo vassallo e combatte per proteggere il re." } diff --git a/frontend/src/assets/i18n/nl.json b/frontend/src/assets/i18n/nl.json index 64946b823..d7679b1b0 100644 --- a/frontend/src/assets/i18n/nl.json +++ b/frontend/src/assets/i18n/nl.json @@ -686,5 +686,7 @@ }, "daysFrom": "Bewerben Sie sich nur noch an diesen Tagen", "oddFightsResolvedAsap": "Los vrijstellingen zo snel mogelijk op zonder strijd", - "oddFightsResolvedAsapHint": "Als het aantal teams of groepen in het toernooi oneven is, is het mogelijk dat tijdens de wedstrijden sommige teams geen geassocieerde wedstrijden hebben en zich automatisch kwalificeren voor de volgende fase. Met deze optie zorgt u ervoor dat deze zaken zo snel mogelijk worden opgelost." + "oddFightsResolvedAsapHint": "Als het aantal teams of groepen in het toernooi oneven is, is het mogelijk dat tijdens de wedstrijden sommige teams geen geassocieerde wedstrijden hebben en zich automatisch kwalificeren voor de volgende fase. Met deze optie zorgt u ervoor dat deze zaken zo snel mogelijk worden opgelost.", + "bubbleSort": "Sorteertoernooi", + "bubbleSortHint": "Concurrenten met een lagere rang proberen in hun rangorde te stijgen totdat ze de koning verslaan. Hij die niet slaagt, wordt zijn vazal en vecht om de koning te beschermen." }