Skip to content

Commit

Permalink
Add lab 08 solution (#150)
Browse files Browse the repository at this point in the history
  • Loading branch information
hspasov authored Dec 21, 2023
1 parent e9aff1a commit 5fee212
Show file tree
Hide file tree
Showing 4 changed files with 222 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package bg.sofia.uni.fmi.mjt.football;

public enum Foot {
LEFT, RIGHT;

public static Foot of(String foot) {
return Foot.valueOf(foot.toUpperCase());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package bg.sofia.uni.fmi.mjt.football;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.AbstractMap;
import java.util.AbstractMap.SimpleEntry;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class FootballPlayerAnalyzer {

private static final int RATING_VARIANCE = 3;
private final List<Player> players;

public FootballPlayerAnalyzer(Reader reader) {
try (var br = new BufferedReader(reader)) {
players = br.lines()//
.skip(1)//
.map(Player::of)//
.toList();
} catch (IOException ex) {
throw new IllegalArgumentException("Could not load dataset", ex);
}
}

public List<Player> getAllPlayers() {
return List.copyOf(players);
}

public Set<String> getAllNationalities() {
return players.stream()//
.map(Player::nationality)//
.collect(Collectors.toUnmodifiableSet());
}

public Player getHighestPaidPlayerByNationality(String nationality) {
if (null == nationality) {
throw new IllegalArgumentException("Provided nationality cannot be null");
}

return players.stream()//
.filter(p -> p.nationality().equals(nationality))//
.max(Comparator.comparingLong(Player::wageEuro))//
.orElseThrow(NoSuchElementException::new);
}

public Map<Position, Set<Player>> groupByPosition() {
return players.stream()//
.flatMap(this::mapPlayerToPositionEntry)//
.collect(Collectors.toUnmodifiableMap(SimpleEntry::getKey, this::newSetFromPlayerEntry,
this::mergeSets));
}

private Stream<SimpleEntry<Position, Player>> mapPlayerToPositionEntry(Player player) {
return player.positions()//
.stream()//
.map(pos -> new AbstractMap.SimpleEntry<>(pos, player));
}

private Set<Player> newSetFromPlayerEntry(SimpleEntry<Position, Player> playerEntry) {
Set<Player> playerSet = new HashSet<>();
playerSet.add(playerEntry.getValue());

return playerSet;
}

private Set<Player> mergeSets(Set<Player> set1, Set<Player> set2) {
set1.addAll(set2);

return set1;
}

public Optional<Player> getTopProspectPlayerForPositionInBudget(Position position, long budget) {
if (null == position) {
throw new IllegalArgumentException("Provided position cannot be null");
}
if (budget < 0) {
throw new IllegalArgumentException("Provided budget cannot be negative");
}

return players.stream()//
.filter(p -> p.positions().contains(position))//
.filter(p -> p.valueEuro() <= budget)//
.max(Comparator.comparingDouble(this::calculatePlayerProspectRating));
}

private double calculatePlayerProspectRating(Player player) {
return ((double) player.overallRating() + player.potential()) / player.age();
}

public Set<Player> getSimilarPlayers(Player player) {
if (null == player) {
throw new IllegalArgumentException("Provided player cannot be null");
}

return players.stream()//
.filter(p -> canPlayWithSameFoot(p, player))//
.filter(p -> canPlaySamePosition(p, player))//
.filter(p -> isSimilarRating(p, player))//
.collect(Collectors.toUnmodifiableSet());
}

private boolean canPlayWithSameFoot(Player player, Player targetPlayer) {
return player.preferredFoot() == targetPlayer.preferredFoot();
}

private boolean canPlaySamePosition(Player player, Player targetPlayer) {
return player.positions()//
.stream()//
.anyMatch(pos -> targetPlayer.positions().contains(pos));
}

private boolean isSimilarRating(Player player, Player targetPlayer) {
int overallRating = player.overallRating();
int targetOverallRating = targetPlayer.overallRating();

return (targetOverallRating - RATING_VARIANCE) <= overallRating
&& overallRating <= (targetOverallRating + RATING_VARIANCE);
}

public Set<Player> getPlayersByFullNameKeyword(String keyword) {
if (null == keyword) {
throw new IllegalArgumentException("Provided keyword cannot be null");
}

return players.stream()//
.filter(p -> p.fullName().contains(keyword))//
.collect(Collectors.toUnmodifiableSet());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package bg.sofia.uni.fmi.mjt.football;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;

public record Player(String name, String fullName, LocalDate birthDate, int age, double heightCm, double weightKg,
List<Position> positions, String nationality, int overallRating, int potential, long valueEuro, long wageEuro,
Foot preferredFoot) {

private static final int NAME = 0;
private static final int FULL_NAME = 1;
private static final int BIRTH_DATE = 2;
private static final int AGE = 3;
private static final int HEIGHT_CM = 4;
private static final int WEIGHT_KG = 5;
private static final int POSITIONS = 6;
private static final int NATIONALITY = 7;
private static final int OVERALL_RATING = 8;
private static final int POTENTIAL = 9;
private static final int VALUE_EURO = 10;
private static final int WAGE_EURO = 11;
private static final int PREFERRED_FOOT = 12;

private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("M/d/yyyy");

public static Player of(String line) {
String[] tokens = line.split(";");

String name = tokens[NAME];
String fullName = tokens[FULL_NAME];
LocalDate birthDate = parseDate(tokens[BIRTH_DATE]);
int age = Integer.parseInt(tokens[AGE]);
double heightCm = Double.parseDouble(tokens[HEIGHT_CM]);
double weightKg = Double.parseDouble(tokens[WEIGHT_KG]);
List<Position> positions = Arrays.stream(tokens[POSITIONS].split(",")).map(Position::valueOf).toList();
String nationality = tokens[NATIONALITY];
int overallRating = Integer.parseInt(tokens[OVERALL_RATING]);
int potential = Integer.parseInt(tokens[POTENTIAL]);
long valueEuro = Long.parseLong(tokens[VALUE_EURO]);
long wageEuro = Long.parseLong(tokens[WAGE_EURO]);
Foot preferredFoot = Foot.of(tokens[PREFERRED_FOOT]);

return new Player(name, fullName, birthDate, age, heightCm, weightKg, positions, nationality, overallRating,
potential, valueEuro, wageEuro, preferredFoot);
}

private static LocalDate parseDate(String date) {
return LocalDate.parse(date, DATE_FORMATTER);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package bg.sofia.uni.fmi.mjt.football;

public enum Position {
// Diagram: https://fifauteam.com/fifa-21-positions/

ST, // Striker
LM, // Left Midfielder
CF, // Centre Forward
GK, // Goalkeeper
RW, // Right Winger
CM, // Centre Midfielder
LW, // Left Winger
CDM, // Defensive Midfielder
CAM, // Attacking midfielder
RB, // Right back
LB, // Left back
LWB, // Left Wing-back
RM, // Right Midfielder
RWB, // Right Wing-back
CB; // Centre Back
}

0 comments on commit 5fee212

Please sign in to comment.