Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scoring change updates #431

Merged
merged 7 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions src/main/java/trap/report/ExcelHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,25 @@ public static void setCurrentSeasonHeader(Sheet sheet) {

public static void createFile(Workbook workbook) throws IOException {
long start = System.currentTimeMillis();
String filename = generateFilename();

logger.info("Creating file: {}", filename);
try (FileOutputStream fileOutputStream = new FileOutputStream(filename)) {
logger.info("Writing file...");
workbook.write(fileOutputStream);
logger.info("File written successfully.");
} catch (IOException e) {
logger.error("Error writing file: {}", e.getMessage());
throw e;
}

logger.info("Created file in {} ms", System.currentTimeMillis() - start);
}

private static String generateFilename() {
var formatter = new SimpleDateFormat("yyyyMMddHHmmss");
var currentDate = formatter.format(new Date());
var filename = "league-data-" + currentDate + ".xlsx";
logger.info("Creating file");
FileOutputStream fileOutputStream = new FileOutputStream(filename);
logger.info("Writing file");
workbook.write(fileOutputStream);
logger.info("closing output stream");
fileOutputStream.flush();
fileOutputStream.close();
logger.info("Created file {}", filename);
logger.info("Wrote the contents to a file in {} ms", System.currentTimeMillis() - start);
return "league-data-" + currentDate + ".xlsx";
}

public static void addCleanData(Row row, RoundScore rowData) {
Expand Down
72 changes: 56 additions & 16 deletions src/main/java/trap/report/ReportHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,18 @@ public void generateExcelFile() throws Exception {
}

private List<RoundScore> generateRoundScores() {
List<RoundScore> allRoundScores;
try {
allRoundScores = new ArrayList<>();
for (var type : trapTypes) {
allRoundScores.addAll(generateRoundScores(type));
}

return allRoundScores;
} catch (IOException | CsvException e) {
throw new RuntimeException(e);
return Arrays.stream(trapTypes)
.flatMap(type -> {
try {
return generateRoundScores(type).stream();
} catch (IOException | CsvException e) {
throw new RuntimeException("Error generating round scores for type: " + type, e);
}
})
.toList();
} catch (RuntimeException e) {
throw new RuntimeException("Error generating round scores", e);
}
}

Expand All @@ -118,12 +120,41 @@ private Workbook getWorkbook() throws IOException {
}

private List<RoundScore> generateRoundScores(String type) throws IOException, CsvException {
var reader = new CSVReader(new FileReader(type + ".csv"));
var roundScores = reader.readAll();
roundScores.removeFirst();
var roundScoresList = new ArrayList<RoundScore>();
roundScores.forEach(s -> roundScoresList.add(new RoundScore(Integer.parseInt(s[1]), trimString(s[2]), Integer.parseInt(s[3]), trimString(s[4]), trimString(s[5]), trimString(s[6]), trimString(s[7]).replace("Club", "Team"), trimString(s[8]), trimString(s[10]), trimString(s[11]), setStringToZero(s[12]), setStringToZero(s[13]), setStringToZero(s[14]), setStringToZero(s[15]), setStringToZero(s[16]), setStringToZero(s[17]), setStringToZero(s[18]), setStringToZero(s[19]), type)));
return roundScoresList;
try (var reader = new CSVReader(new FileReader(type + ".csv"))) {
var roundScores = reader.readAll();
if (roundScores.isEmpty()) {
return new ArrayList<>(); // or handle as appropriate
}
roundScores.removeFirst(); // Remove the header row

return roundScores.stream()
.map(s -> createRoundScore(s, type))
.toList();
}
}

private RoundScore createRoundScore(String[] data, String type) {
return new RoundScore(
parseInteger(data[1]),
trimString(data[2]),
parseInteger(data[3]),
trimString(data[4]),
trimString(data[5]),
trimString(data[6]),
trimString(data[7]).replace("Club", "Team"),
trimString(data[8]),
trimString(data[10]),
trimString(data[11]),
setStringToZero(data[12]),
setStringToZero(data[13]),
setStringToZero(data[14]),
setStringToZero(data[15]),
setStringToZero(data[16]),
setStringToZero(data[17]),
setStringToZero(data[18]),
setStringToZero(data[19]),
type
);
}

private void populateCleanData(Sheet sheet, List<RoundScore> allRoundScores) {
Expand Down Expand Up @@ -309,6 +340,7 @@ private List<IndividualTotal> getTeamScoresByTotal(Map<String, IndividualTotal>
return teamScoresByTotal;
}

// Team-Individual-Scores tab
private void populateTeamIndividualData(Workbook workbook, String sheetName, List<IndividualTotal> teamScoresByTotal) {
var sheet = workbook.getSheet(sheetName);
var startTime = System.currentTimeMillis();
Expand Down Expand Up @@ -351,8 +383,16 @@ private void populateAllIndividualData(Workbook workbook, String sheetName, Map<
logger.info("Individual All Scores data populated in {} ms", System.currentTimeMillis() - trueStart);
}

private int parseInteger(String number) {
try {
return Integer.parseInt(number);
} catch (NumberFormatException e) {
return 0;
}
}

private int setStringToZero(String number) {
return "".equals(number) ? 0 : Integer.parseInt(number);
return number.isEmpty() ? 0 : parseInteger(number);
}

private String trimString(String s) {
Expand Down
170 changes: 105 additions & 65 deletions src/main/java/trap/report/TrapHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,106 +10,146 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class TrapHelper {
private static final Map<String, Integer> roundCounts = determineEventsToCount();

public Map<String, ArrayList<RoundTotal>> calculatePlayerRoundTotals(List<RoundScore> roundScores) {
var playerRoundTotals = new HashMap<String, ArrayList<RoundTotal>>();
for (var r : roundScores) {
playerRoundTotals.put(r.getUniqueName(), new ArrayList<>());
}
for (var r : roundScores) {
var currentPlayerRoundTotal = playerRoundTotals.get(r.getUniqueName());
public Map<String, List<RoundTotal>> calculatePlayerRoundTotals(List<RoundScore> roundScores) {
Map<String, List<RoundTotal>> playerRoundTotals = new HashMap<>();

// Initialize map with empty lists for each unique player
roundScores.forEach(r -> playerRoundTotals.put(r.getUniqueName(), new ArrayList<>()));

// Process each round score
for (RoundScore r : roundScores) {
List<RoundTotal> currentPlayerRoundTotal = playerRoundTotals.get(r.getUniqueName());

// If it's a single round, process round 1 and optionally round 2
if (singleRound(r.getType())) {
currentPlayerRoundTotal.add(new RoundTotal(r.getEventId(), r.getLocationId(), r.getTeam(), r.getAthlete(), r.getClassification(), r.getGender(), r.getRound1(), r.getType()));
addRound(currentPlayerRoundTotal, r, r.getRound1());
if (r.getRound2() > 0) {
currentPlayerRoundTotal.add(new RoundTotal(r.getEventId(), r.getLocationId(), r.getTeam(), r.getAthlete(), r.getClassification(), r.getGender(), r.getRound2(), r.getType()));
addRound(currentPlayerRoundTotal, r, r.getRound2());
}
} else {
currentPlayerRoundTotal.add(new RoundTotal(r.getEventId(), r.getLocationId(), r.getTeam(), r.getAthlete(), r.getClassification(), r.getGender(), r.getRound1() + r.getRound2(), r.getType()));
if (r.getRound3() + r.getRound4() > 0) {
currentPlayerRoundTotal.add(new RoundTotal(r.getEventId(), r.getLocationId(), r.getTeam(), r.getAthlete(), r.getClassification(), r.getGender(), r.getRound3() + r.getRound4(), r.getType()));
if (r.getRound5() + r.getRound6() > 0) {
currentPlayerRoundTotal.add(new RoundTotal(r.getEventId(), r.getLocationId(), r.getTeam(), r.getAthlete(), r.getClassification(), r.getGender(), r.getRound5() + r.getRound6(), r.getType()));
if (r.getRound7() + r.getRound8() > 0) {
currentPlayerRoundTotal.add(new RoundTotal(r.getEventId(), r.getLocationId(), r.getTeam(), r.getAthlete(), r.getClassification(), r.getGender(), r.getRound7() + r.getRound8(), r.getType()));
}
}
}
addRound(currentPlayerRoundTotal, r, r.getRound1() + r.getRound2());
addMultipleRounds(currentPlayerRoundTotal, r);
}
playerRoundTotals.put(r.getUniqueName(), currentPlayerRoundTotal);
}

return playerRoundTotals;
}

public Map<String, ArrayList<IndividualTotal>> calculatePlayerIndividualTotal(List<RoundScore> roundScores, Map<String, ArrayList<RoundTotal>> playerRoundTotals) {
var playerIndividualTotal = new HashMap<String, ArrayList<IndividualTotal>>();
for (var r : roundScores) {
playerIndividualTotal.put(r.getUniqueName(), new ArrayList<>());
// Helper method to add individual rounds
private void addRound(List<RoundTotal> totals, RoundScore r, int total) {
totals.add(new RoundTotal(r.getEventId(), r.getLocationId(), r.getTeam(), r.getAthlete(),
r.getClassification(), r.getGender(), total, r.getType()));
}

// Helper method to add rounds 3 to 8 if applicable
private void addMultipleRounds(List<RoundTotal> totals, RoundScore r) {
int[] additionalRounds = {r.getRound3() + r.getRound4(), r.getRound5() + r.getRound6(), r.getRound7() + r.getRound8()};

for (int round : additionalRounds) {
if (round > 0) {
addRound(totals, r, round);
} else {
break; // Stop processing once a round with zero total is found
}
}
for (var playerRoundTotal : playerRoundTotals.values()) {
var roundsToCount = getRoundsToCount(playerRoundTotal.getFirst().getType());
var indTotal = new ArrayList<IndividualTotal>();
}

public Map<String, List<IndividualTotal>> calculatePlayerIndividualTotal(List<RoundScore> roundScores, Map<String, List<RoundTotal>> playerRoundTotals) {
Map<String, List<IndividualTotal>> playerIndividualTotal = new HashMap<>();

// Initialize scores with empty lists
roundScores.forEach(r -> playerIndividualTotal.put(r.getUniqueName(), new ArrayList<>()));

for (List<RoundTotal> playerRoundTotal : playerRoundTotals.values()) {
if (playerRoundTotal.isEmpty()) continue;

String playerName = playerRoundTotal.getFirst().getUniqueName();
int roundsToCount = getEventsToCount(playerRoundTotal.getFirst().getType());
List<IndividualTotal> indTotal = new ArrayList<>();

// Sort in descending order based on total score
playerRoundTotal.sort(Comparator.comparingInt(RoundTotal::getTotal).reversed());
for (var t : playerRoundTotal) {
if (indTotal.size() < (roundsToCount - 1)) {
indTotal.add(new IndividualTotal(t.getLocationId(), t.getTeam(), t.getAthlete(), t.getClassification(), t.getGender(), t.getTotal(), t.getType()));
} else {
var locationIds = new HashSet<Integer>();
indTotal.forEach(l -> locationIds.add(l.getLocationId()));
// if location doesn't already exist
if (!locationIds.contains(t.getLocationId())) {
indTotal.add(new IndividualTotal(t.getLocationId(), t.getTeam(), t.getAthlete(), t.getClassification(), t.getGender(), t.getTotal(), t.getType()));
break;
}
// if location isn't the same as the other 3
if (locationIds.size() == 2 || locationIds.size() == 3) {
indTotal.add(new IndividualTotal(t.getLocationId(), t.getTeam(), t.getAthlete(), t.getClassification(), t.getGender(), t.getTotal(), t.getType()));
break;
}

Set<Integer> locationIds = new HashSet<>();
for (RoundTotal t : playerRoundTotal) {
if (indTotal.size() < roundsToCount - 1) {
// Add round directly until we reach the number of rounds to count
indTotal.add(toIndividualTotal(t));
locationIds.add(t.getLocationId());
} else if (shouldAddRound(t, locationIds)) {
// Handle special case when location constraints are applied
indTotal.add(toIndividualTotal(t));
break;
}
}
playerIndividualTotal.put(playerRoundTotal.getFirst().getUniqueName(), indTotal);

playerIndividualTotal.put(playerName, indTotal);
}

return playerIndividualTotal;
}

public Map<String, IndividualTotal> calculatePlayerFinalTotal(Map<String, ArrayList<IndividualTotal>> playerIndividualTotal) {
var playerFinalTotal = new HashMap<String, IndividualTotal>();
for (Map.Entry<String, ArrayList<IndividualTotal>> entry : playerIndividualTotal.entrySet()) {
var key = entry.getKey();
ArrayList<IndividualTotal> value = entry.getValue();
if (!value.isEmpty()) {
int total = 0;
for (var t : value) {
total += t.getTotal();
}
playerFinalTotal.put(key, new IndividualTotal(0, value.getFirst().getTeam(), value.getFirst().getAthlete(), value.getFirst().getClassification(), value.getFirst().getGender(), total, value.getFirst().getType()));
}
private IndividualTotal toIndividualTotal(RoundTotal t) {
return new IndividualTotal(t.getLocationId(), t.getTeam(), t.getAthlete(), t.getClassification(), t.getGender(), t.getTotal(), t.getType());
}

// Method to determine if a round should be added based on location constraints
private boolean shouldAddRound( RoundTotal t, Set<Integer> locationIds) {
int locationId = t.getLocationId();
// Check if the location doesn't already exist
if (!locationIds.contains(locationId)) {
locationIds.add(locationId);
return true;
}
// If there are already 2 or 3 unique locations, consider adding the round
return locationIds.size() == 2 || locationIds.size() == 3;
}

public Map<String, IndividualTotal> calculatePlayerFinalTotal(Map<String, List<IndividualTotal>> playerIndividualTotals) {
var playerFinalTotals = new HashMap<String, IndividualTotal>();
playerIndividualTotals.forEach((key, totals) -> {
if (!totals.isEmpty()) {
var firstTotal = totals.getFirst();
int totalScore = totals.stream().mapToInt(IndividualTotal::getTotal).sum();

playerFinalTotals.put(key, new IndividualTotal(
0,
firstTotal.getTeam(),
firstTotal.getAthlete(),
firstTotal.getClassification(),
firstTotal.getGender(),
totalScore,
firstTotal.getType()
));
}
});

return playerFinalTotal;
return playerFinalTotals;
}

private boolean singleRound(String roundType) {
return roundType.equals("clays") || roundType.equals("doubles") || roundType.equals("doublesskeet");
public boolean singleRound(String roundType) {
Set<String> validRounds = Set.of("clays", "doubles", "doublesskeet", "fivestand");
return validRounds.contains(roundType);
}

private static Map<String, Integer> determineRoundsToCount() {
private static Map<String, Integer> determineEventsToCount() {
var roundCounts = new HashMap<String, Integer>();
roundCounts.put("singles", 4);
roundCounts.put("doubles", 4);
roundCounts.put("handicap", 4);
roundCounts.put("skeet", 3);
roundCounts.put("skeet", 4);
roundCounts.put("clays", 3);
roundCounts.put("fivestand", 3);
roundCounts.put("doublesskeet", 3);
roundCounts.put("fivestand", 4);
roundCounts.put("doublesskeet", 4);
return roundCounts;
}

public static int getRoundsToCount(String type) {
return Integer.parseInt(determineRoundsToCount().get(type).toString());
public static int getEventsToCount(String type) {
return roundCounts.getOrDefault(type, 0); // Default to 0 if type not found
}
}
Loading