Skip to content

Commit

Permalink
Merge pull request #476 from softwaremagico/473-add-new-tournament-br…
Browse files Browse the repository at this point in the history
…ackets-options-to-solve-odd-teams-as-soon-as-possible

473 add new tournament brackets options to solve odd teams as soon as possible
  • Loading branch information
softwaremagico authored Jun 19, 2024
2 parents 6631bbb + d7a0bae commit d77615b
Show file tree
Hide file tree
Showing 35 changed files with 845 additions and 137 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-625.5h-blueviolet.svg)]()
[![Time](https://img.shields.io/badge/development-633.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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,24 @@
import com.softwaremagico.kt.logger.ExceptionType;
import com.softwaremagico.kt.persistence.entities.GroupLink;
import com.softwaremagico.kt.persistence.entities.Tournament;
import com.softwaremagico.kt.persistence.repositories.GroupLinkRepository;
import org.springframework.stereotype.Controller;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@Controller
public class GroupLinkController extends BasicInsertableController<GroupLink, GroupLinkDTO, GroupLinkRepository,
GroupLinkProvider, GroupLinkConverterRequest, GroupLinkConverter> {
public class GroupLinkController {

private final TournamentProvider tournamentProvider;
private final GroupLinkProvider groupLinkProvider;
private final GroupLinkConverter groupLinkConverter;

public GroupLinkController(GroupLinkProvider provider, GroupLinkConverter converter, TournamentProvider tournamentProvider) {
super(provider, converter);
public GroupLinkController(TournamentProvider tournamentProvider, GroupLinkProvider groupLinkProvider, GroupLinkConverter groupLinkConverter) {
this.tournamentProvider = tournamentProvider;
this.groupLinkProvider = groupLinkProvider;
this.groupLinkConverter = groupLinkConverter;
}


Expand All @@ -58,7 +62,12 @@ public List<GroupLinkDTO> getLinks(Integer tournamentId) {
}

public List<GroupLinkDTO> getLinks(Tournament tournament) {
return convertAll(getProvider().generateLinks(tournament));
return convertAll(groupLinkProvider.generateLinks(tournament));
}

private List<GroupLinkDTO> convertAll(Collection<GroupLink> entities) {
return new ArrayList<>(groupLinkConverter.convertAll(entities.stream().map(this::createConverterRequest)
.collect(Collectors.toCollection(ArrayList::new))));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.softwaremagico.kt.core.converters.TournamentExtraPropertyConverter;
import com.softwaremagico.kt.core.converters.models.TournamentExtraPropertyConverterRequest;
import com.softwaremagico.kt.core.exceptions.TournamentNotFoundException;
import com.softwaremagico.kt.core.providers.GroupProvider;
import com.softwaremagico.kt.core.providers.TournamentExtraPropertyProvider;
import com.softwaremagico.kt.core.providers.TournamentProvider;
import com.softwaremagico.kt.persistence.entities.TournamentExtraProperty;
Expand All @@ -42,14 +43,17 @@ public class TournamentExtraPropertyController extends BasicInsertableController

private final TournamentProvider tournamentProvider;
private final TournamentConverter tournamentConverter;
private final GroupProvider groupProvider;


@Autowired
protected TournamentExtraPropertyController(TournamentExtraPropertyProvider provider, TournamentExtraPropertyConverter converter,
TournamentProvider tournamentProvider, TournamentConverter tournamentConverter) {
TournamentProvider tournamentProvider, TournamentConverter tournamentConverter,
GroupProvider groupProvider) {
super(provider, converter);
this.tournamentProvider = tournamentProvider;
this.tournamentConverter = tournamentConverter;
this.groupProvider = groupProvider;
}

@Override
Expand All @@ -60,6 +64,10 @@ protected TournamentExtraPropertyConverterRequest createConverterRequest(Tournam
@Override
public TournamentExtraPropertyDTO update(TournamentExtraPropertyDTO dto, String username) {
getProvider().deleteByTournamentAndProperty(tournamentConverter.reverse(dto.getTournament()), dto.getPropertyKey());
//Remove any existing group if changed.
if (dto.getPropertyKey() == TournamentExtraPropertyKey.ODD_FIGHTS_RESOLVED_ASAP) {
groupProvider.delete(tournamentConverter.reverse(dto.getTournament()));
}
return super.update(dto, username);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,25 @@
import com.softwaremagico.kt.persistence.entities.GroupLink;
import com.softwaremagico.kt.persistence.entities.Tournament;
import com.softwaremagico.kt.persistence.entities.TournamentExtraProperty;
import com.softwaremagico.kt.persistence.repositories.GroupLinkRepository;
import com.softwaremagico.kt.persistence.values.TournamentExtraPropertyKey;
import com.softwaremagico.kt.utils.GroupUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

import static com.softwaremagico.kt.core.tournaments.TreeTournamentHandler.DEFAULT_ODD_TEAMS_RESOLUTION_ASAP;

@Service
public class GroupLinkProvider extends CrudProvider<GroupLink, Integer, GroupLinkRepository> {
public class GroupLinkProvider {

private final TournamentExtraPropertyProvider tournamentExtraPropertyProvider;
private final GroupProvider groupProvider;

public GroupLinkProvider(GroupLinkRepository groupLinkRepository, TournamentExtraPropertyProvider tournamentExtraPropertyProvider,
public GroupLinkProvider(TournamentExtraPropertyProvider tournamentExtraPropertyProvider,
GroupProvider groupProvider) {
super(groupLinkRepository);
this.tournamentExtraPropertyProvider = tournamentExtraPropertyProvider;
this.groupProvider = groupProvider;
}
Expand Down Expand Up @@ -93,23 +94,34 @@ public Group getDestination(Group sourceGroup, int numberOfWinners, int winnerOr
final List<Group> currentLevelGroups = groups.stream().filter(group -> Objects.equals(group.getLevel(), sourceGroup.getLevel())).toList();
final List<Group> nextLevelGroups = groups.stream().filter(group -> Objects.equals(group.getLevel(), sourceGroup.getLevel() + 1)).toList();
try {
return nextLevelGroups.get(obtainPositionOfWinner(groups, sourceGroup.getIndex(), currentLevelGroups.size(), numberOfWinners, winnerOrder,
sourceGroup.getLevel()));
final TournamentExtraProperty oddTeamsResolvedAsapProperty = tournamentExtraPropertyProvider
.getByTournamentAndProperty(sourceGroup.getTournament(),
TournamentExtraPropertyKey.ODD_FIGHTS_RESOLVED_ASAP, DEFAULT_ODD_TEAMS_RESOLUTION_ASAP);
if (Boolean.parseBoolean(oddTeamsResolvedAsapProperty.getPropertyValue()) && sourceGroup.getLevel() == 0
//If it has the same number of groups, can be use the standard way.
&& currentLevelGroups.size() != nextLevelGroups.size() && !GroupUtils.isPowerOfTwo(currentLevelGroups.size())) {
return nextLevelGroups.get(obtainPositionOfWinnerRemovingOddNumbers(sourceGroup.getIndex(),
currentLevelGroups.size(), nextLevelGroups.size(), winnerOrder));
} else {
return nextLevelGroups.get(obtainPositionOfWinnerAsBinaryTree(groups, sourceGroup.getIndex(),
currentLevelGroups.size(), numberOfWinners, winnerOrder, sourceGroup.getLevel()));
}
} catch (IndexOutOfBoundsException e) {
return null;
}
}

private int obtainPositionOfWinner(List<Group> groups, int sourceGroupLevelIndex, int sourceGroupLevelSize, int numberOfWinners,
int winnerOrder, int sourceLevel) {
private int obtainPositionOfWinnerAsBinaryTree(List<Group> groups, int sourceGroupLevelIndex, int sourceGroupLevelSize, int numberOfWinners,
int winnerOrder, int sourceLevel) {
final List<Group> previousLevelGroups;
if (sourceLevel > 0) {
previousLevelGroups = groups.stream().filter(group -> Objects.equals(group.getLevel(), 0)).toList();
} else {
previousLevelGroups = new ArrayList<>();
}

//Special case: two odd number of groups in two consecutive levels. Only one winner. Ensure no team pass two levels without fighting.
//Special case: two odd number of groups in two consecutive levels. Only one winner.
//Ensure no team passes two levels without fighting.
if (numberOfWinners == 1 && previousLevelGroups.size() % 2 == 1 && sourceGroupLevelSize % 2 == 1
&& previousLevelGroups.size() != sourceGroupLevelSize) {
return (sourceGroupLevelIndex + 1) / 2;
Expand All @@ -121,24 +133,24 @@ private int obtainPositionOfWinner(List<Group> groups, int sourceGroupLevelIndex
if (winnerOrder == 0) {
return sourceGroupLevelIndex;
} else if (winnerOrder == 1) {
//Second winner to next group. Last one goes to first group.
//Second winner to next group. The Last one goes to the first group.
return (sourceGroupLevelIndex + 1) % sourceGroupLevelSize;
}
}

//Standard case.
if (winnerOrder == 0) {
//Half groups number on next level.
//Half-groups number on next level.
if (sourceLevel > 0 || numberOfWinners == 1) {
return sourceGroupLevelIndex / 2;
} else {
//Same number of groups on next level (needed two winners).
//Same number of groups on the next level (needed for two winners).
return sourceGroupLevelIndex;
}
} else if (winnerOrder == 1) {
//Second winner in standard case, goes to the opposite group.
if (sourceLevel > 0) {
//+1 for rounding, -1 as list starts in 0.
//+1 for rounding, -1 as a list starts in 0.
return (sourceGroupLevelSize - sourceGroupLevelIndex + 1) / 2 - 1;
} else {
return (sourceGroupLevelSize - sourceGroupLevelIndex - 1);
Expand All @@ -147,4 +159,25 @@ private int obtainPositionOfWinner(List<Group> groups, int sourceGroupLevelIndex
return -1;
}
}

private int obtainPositionOfWinnerRemovingOddNumbers(int sourceGroupLevelIndex, int sourceGroupLevelSize, int destinationGroupLevelSize,
int winnerOrder) {
//Standard case.
if (winnerOrder == 0) {
if (sourceGroupLevelIndex <= (sourceGroupLevelSize - 1) / 2) {
return sourceGroupLevelIndex;
} else {
return destinationGroupLevelSize - (sourceGroupLevelSize - sourceGroupLevelIndex - 1) - 1;
}
} else if (winnerOrder == 1) {
if (sourceGroupLevelIndex <= (sourceGroupLevelSize - 1) / 2) {
//Last -1 is for list starts at 0.
return (destinationGroupLevelSize / 2) + (sourceGroupLevelIndex / 2);
} else {
return (destinationGroupLevelSize / 2) - ((sourceGroupLevelSize - (sourceGroupLevelIndex + 1)) / 2) - 1;
}
} else {
return -1;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,31 @@ public TournamentExtraPropertyProvider(TournamentExtraPropertyRepository reposit
super(repository);
}


public List<TournamentExtraProperty> getAll(Tournament tournament) {
return getRepository().findByTournament(tournament);
}


public TournamentExtraProperty getByTournamentAndProperty(Tournament tournament, TournamentExtraPropertyKey key, Object defaultValue) {
TournamentExtraProperty extraProperty = getByTournamentAndProperty(tournament, key);
if (extraProperty == null) {
extraProperty = save(new TournamentExtraProperty(tournament, key, String.valueOf(defaultValue)));
}
return extraProperty;
}


public TournamentExtraProperty getByTournamentAndProperty(Tournament tournament, TournamentExtraPropertyKey key) {
return getRepository().findByTournamentAndPropertyKey(tournament, key);
}


public List<TournamentExtraProperty> getLatestPropertiesByCreatedBy(String createdBy) {
return getRepository().findDistinctPropertyKeyByCreatedByHashOrderByCreatedAtDesc(createdBy);
}


public int delete(Tournament tournament) {
return getRepository().deleteByTournament(tournament);
}
Expand All @@ -61,12 +74,14 @@ public void deleteByTournamentAndProperty(Tournament tournament, TournamentExtra
getRepository().flush();
}


@Override
public TournamentExtraProperty save(TournamentExtraProperty entity) {
deleteByTournamentAndProperty(entity.getTournament(), entity.getPropertyKey());
return getRepository().save(entity);
}


@Override
public List<TournamentExtraProperty> saveAll(Collection<TournamentExtraProperty> tournamentExtraProperties) {
tournamentExtraProperties.forEach(tournamentExtraProperty ->
Expand Down
Loading

0 comments on commit d77615b

Please sign in to comment.