diff --git a/.gitignore b/.gitignore index 6eef95a..265b8b1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ build/ .idea/jarRepositories.xml .idea/compiler.xml .idea/libraries/ +.idea *.iws *.iml *.ipr diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index 14746e7..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 72be7ed..e87b105 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,6 +12,7 @@ repositories { dependencies { testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation("org.junit.jupiter:junit-jupiter") + testImplementation("org.jfree:jfreechart:1.5.3") } tasks.test { diff --git a/src/main/java/ru/urfu/Main.java b/src/main/java/ru/urfu/Main.java index 5845f6d..b5a9126 100644 --- a/src/main/java/ru/urfu/Main.java +++ b/src/main/java/ru/urfu/Main.java @@ -1,17 +1,18 @@ -package ru.urfu; +package main.java.ru.urfu; + +// import main.java.ru.urfu.console.Communicator; + +import main.java.ru.urfu.presentation.controller.Controller; +import main.java.ru.urfu.presentation.view.ConsoleView; +import main.java.ru.urfu.resolver.Resolver; -//TIP To Run code, press or -// click the icon in the gutter. public class Main { public static void main(String[] args) { - //TIP Press with your caret at the highlighted text - // to see how GIGA IDE suggests fixing it. - System.out.printf("Hello and welcome!"); + // Communicator.runChampionship(); + var console = new ConsoleView(); + var resolver = new Resolver(); - for (int i = 1; i <= 5; i++) { - //TIP Press to start debugging your code. We have set one breakpoint - // for you, but you can always add more by pressing . - System.out.println("i = " + i); - } + var controller = new Controller(console, resolver); + controller.start(); } } \ No newline at end of file diff --git a/src/main/java/ru/urfu/console/Communicator.java b/src/main/java/ru/urfu/console/Communicator.java new file mode 100644 index 0000000..1674a44 --- /dev/null +++ b/src/main/java/ru/urfu/console/Communicator.java @@ -0,0 +1,14 @@ +package main.java.ru.urfu.console; + + +import main.java.ru.urfu.parser.CsvParser; +import main.java.ru.urfu.resolver.Resolver; +import main.java.ru.urfu.mapper.Mapper; +import main.java.ru.urfu.drawer.Drawer; + +import java.util.Scanner; + +public class Communicator { + public static void runChampionship() { + } +} \ No newline at end of file diff --git a/src/main/java/ru/urfu/drawer/Drawer.java b/src/main/java/ru/urfu/drawer/Drawer.java new file mode 100644 index 0000000..d83de4b --- /dev/null +++ b/src/main/java/ru/urfu/drawer/Drawer.java @@ -0,0 +1,43 @@ +package main.java.ru.urfu.drawer; + +import main.java.ru.urfu.model.Position; +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartFrame; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.labels.StandardPieSectionLabelGenerator; +import org.jfree.chart.plot.PiePlot; +import org.jfree.chart.plot.Plot; +import org.jfree.data.general.DefaultPieDataset; + +import java.awt.*; +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.Map; +import java.util.Scanner; + +public class Drawer { + public void drawDiagramPlayersByPosition(Map positionsCount) { + DefaultPieDataset dataset = new DefaultPieDataset<>(); + + positionsCount.forEach((pos, count) -> + dataset.setValue(pos.getTitleRu(), count) + ); + + JFreeChart chart = ChartFactory.createPieChart("Распределение по позициям", dataset, true, true, false); + + PiePlot plot = (PiePlot) chart.getPlot(); + plot.setLabelGenerator(new StandardPieSectionLabelGenerator( + "{0}: {1} ({2})", + new DecimalFormat("0"), + new DecimalFormat("0.00%") + )); + + plot.setSimpleLabels(true); + plot.setLabelBackgroundPaint(Color.WHITE); + + ChartFrame frame = new ChartFrame("Распределение по позициям", chart); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setVisible(true); + } +} diff --git a/src/main/java/ru/urfu/mapper/Mapper.java b/src/main/java/ru/urfu/mapper/Mapper.java new file mode 100644 index 0000000..d50a29e --- /dev/null +++ b/src/main/java/ru/urfu/mapper/Mapper.java @@ -0,0 +1,23 @@ +package main.java.ru.urfu.mapper; + +import main.java.ru.urfu.model.Player; +import main.java.ru.urfu.model.Position; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class Mapper { + + private List players = new ArrayList<>(); + + public void setPlayers(List players) { + this.players = players; + } + + public Map getPlayersByPosition() { + return players.stream() + .collect(Collectors.groupingBy(Player::position, Collectors.counting())); + } +} diff --git a/src/main/java/ru/urfu/model/Player.java b/src/main/java/ru/urfu/model/Player.java new file mode 100644 index 0000000..efd9d45 --- /dev/null +++ b/src/main/java/ru/urfu/model/Player.java @@ -0,0 +1,16 @@ +package main.java.ru.urfu.model; + +public record Player( + String name, + String team, + String city, + Position position, + String nationality, + String agency, + int transferCost, + int goals, + int assists, + int yellowCards, + int redCards +) { +} \ No newline at end of file diff --git a/src/main/java/ru/urfu/model/Position.java b/src/main/java/ru/urfu/model/Position.java new file mode 100644 index 0000000..682483d --- /dev/null +++ b/src/main/java/ru/urfu/model/Position.java @@ -0,0 +1,19 @@ +package main.java.ru.urfu.model; + +public enum Position { + GOALKEEPER("Вратарь"), + DEFENDER("Защитник"), + MIDFIELD("Полузащитик"), + FORWARD("Нападающий"); + + private final String titleRu; + + Position(String title){ + this.titleRu = title; + } + + public String getTitleRu(){ + return this.titleRu; + } + +} diff --git a/src/main/java/ru/urfu/parser/CsvParser.java b/src/main/java/ru/urfu/parser/CsvParser.java new file mode 100644 index 0000000..658a801 --- /dev/null +++ b/src/main/java/ru/urfu/parser/CsvParser.java @@ -0,0 +1,47 @@ +package main.java.ru.urfu.parser; + +import main.java.ru.urfu.model.Position; +import main.java.ru.urfu.model.Player; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Scanner; + +public class CsvParser { + public static ArrayList parserCsvToList(String pathString) { + var path = Paths.get(pathString); + var scan = getScanner(path); + var playersList = new ArrayList(); + + scan.nextLine(); + while (scan.hasNextLine()) { + playersList.add(parseRowToPlayer(scan.nextLine())); + } + return playersList; + } + + private static Scanner getScanner(Path path) { + try { + return new Scanner(path); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static Player parseRowToPlayer(String row) { + var cells = row.split(";"); + return new Player(cells[0], + cells[1], + cells[2], + Position.valueOf(cells[3]), + cells[4], + cells[5], + Integer.parseInt(cells[6]), + Integer.parseInt(cells[7]), + Integer.parseInt(cells[8]), + Integer.parseInt(cells[9]), + Integer.parseInt(cells[10])); + } +} diff --git a/src/main/java/ru/urfu/presentation/controller/Controller.java b/src/main/java/ru/urfu/presentation/controller/Controller.java new file mode 100644 index 0000000..4d01dea --- /dev/null +++ b/src/main/java/ru/urfu/presentation/controller/Controller.java @@ -0,0 +1,83 @@ +package main.java.ru.urfu.presentation.controller; + +import main.java.ru.urfu.drawer.Drawer; +import main.java.ru.urfu.mapper.Mapper; +import main.java.ru.urfu.model.Player; +import main.java.ru.urfu.parser.CsvParser; +import main.java.ru.urfu.presentation.view.ConsoleView; +import main.java.ru.urfu.resolver.Resolver; + +import java.util.List; +import java.util.Scanner; + +public class Controller { + private final ConsoleView view; + private final Scanner scanner; + private final Resolver resolver; + private final Mapper mapper; + private final Drawer drawer; + + + public Controller(ConsoleView view, Resolver resolver) { + this.view = view; + this.resolver = resolver; + scanner = new Scanner(System.in); + drawer = new Drawer(); + mapper = new Mapper(); + } + + public void start() { + view.showWelcome(); + mainCycle: + while (true) { + view.showEnterCommand(); + + switch (scanner.nextLine()) { + case "F" -> onEnterFile(); + case "1" -> onTask1Request(); + case "2" -> onTask2Request(); + case "3" -> onTask3Request(); + case "4" -> onTask4Request(); + case "G" -> onChartRequest(); + default -> { + break mainCycle; + } + } + } + } + + private void onEnterFile() { + view.showFilePath(); + try { + List players = CsvParser.parserCsvToList(scanner.nextLine()); + resolver.setPlayers(players); + mapper.setPlayers(players); + } catch (Exception e) { + this.onFileError(); + } + } + + private void onFileError() { + view.showFileError(); + } + + private void onTask1Request() { + view.showCountWithoutAgency(resolver.getCountWithoutAgency()); + } + + private void onTask2Request() { + view.showMaxDefenderGoalsCount(resolver.getMaxDefenderGoalsCount()); + } + + private void onTask3Request() { + view.showTheExpensiveGermanPlayerPosition(resolver.getTheExpensiveGermanPlayerPosition()); + } + + private void onTask4Request() { + view.showTheRudestTeam(resolver.getTheRudestTeam()); + } + + private void onChartRequest() { + drawer.drawDiagramPlayersByPosition(mapper.getPlayersByPosition()); + } +} diff --git a/src/main/java/ru/urfu/presentation/view/ConsoleView.java b/src/main/java/ru/urfu/presentation/view/ConsoleView.java new file mode 100644 index 0000000..55bbdc1 --- /dev/null +++ b/src/main/java/ru/urfu/presentation/view/ConsoleView.java @@ -0,0 +1,43 @@ +package main.java.ru.urfu.presentation.view; + +public class ConsoleView { + public void showWelcome() { + System.out.println(""" + Конанды: + F - выбрать файл для анализа + 1 - решение задачи 1 + 2 - решение задачи 2 + 3 - решение задачи 3 + 4 - решение задачи 4 + G - показать график + Любая иная клавиша - завершить работу"""); + } + + public void showEnterCommand() { + System.out.print("Введите команду: "); + } + + public void showFilePath() { + System.out.print("Полный путь до .csv файла: "); + } + + public void showFileError() { + System.out.println("Неправильный путь до файла"); + } + + public void showCountWithoutAgency(int count) { + System.out.printf("Количество игроков без агентсва: %d\n", count); + } + + public void showMaxDefenderGoalsCount(int count) { + System.out.printf("Максимальное количество голов у защитника: %d\n", count); + } + + public void showTheExpensiveGermanPlayerPosition(String position) { + System.out.printf("Название позиции самого дорогого немецкого игрока: %s\n", position); + } + + public void showTheRudestTeam(String team) { + System.out.printf("Команда с наибольшим средним числом удалений на одного игрока: %s\n", team); + } +} diff --git a/src/main/java/ru/urfu/resolver/IResolver.java b/src/main/java/ru/urfu/resolver/IResolver.java index c806b3a..2ae0bc2 100644 --- a/src/main/java/ru/urfu/resolver/IResolver.java +++ b/src/main/java/ru/urfu/resolver/IResolver.java @@ -1,4 +1,4 @@ -package ru.urfu.resolver; +package main.java.ru.urfu.resolver; public interface IResolver { // Выведите количество игроков, интересы которых не представляет агентство. diff --git a/src/main/java/ru/urfu/resolver/Resolver.java b/src/main/java/ru/urfu/resolver/Resolver.java new file mode 100644 index 0000000..df8b856 --- /dev/null +++ b/src/main/java/ru/urfu/resolver/Resolver.java @@ -0,0 +1,55 @@ +package main.java.ru.urfu.resolver; + +import main.java.ru.urfu.model.Player; +import main.java.ru.urfu.model.Position; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class Resolver implements IResolver { + + private List players = new ArrayList<>(); + + public void setPlayers(List players) { + this.players = players; + } + + @Override + public int getCountWithoutAgency() { + return (int) players.stream() + .filter(p -> p.agency().isEmpty()) + .count(); + } + + @Override + public int getMaxDefenderGoalsCount() { + return players.stream() + .filter(p -> p.position().equals(Position.DEFENDER)) + .mapToInt(Player::goals) + .max() + .orElse(0); + } + + @Override + public String getTheExpensiveGermanPlayerPosition() { + return players.stream() + .filter(p -> p.nationality().equals("Germany")) + .max(Comparator.comparing(Player::transferCost)) + .map(Player::position) + .map(Position::getTitleRu) + .orElse("Нет немецких игроков"); + } + + @Override + public String getTheRudestTeam() { + return players.stream() + .collect(Collectors.groupingBy(Player::team, Collectors.averagingDouble(Player::redCards))) + .entrySet().stream() + .max(Map.Entry.comparingByValue()) + .map(Map.Entry::getKey) + .orElse("Команд не найдено"); + } +} diff --git a/src/test/java/ru/urfu/MapperTest.java b/src/test/java/ru/urfu/MapperTest.java new file mode 100644 index 0000000..f622786 --- /dev/null +++ b/src/test/java/ru/urfu/MapperTest.java @@ -0,0 +1,64 @@ +package test.java.ru.urfu; + +import main.java.ru.urfu.mapper.Mapper; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +import main.java.ru.urfu.model.Player; +import main.java.ru.urfu.model.Position; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class MapperTest { + @Test + void testGetPlayersByPositionAll() { + List players = List.of( + new Player("Player 1", "Team A", "City A", Position.GOALKEEPER, "Nat 1", "Agency 1", 100, 0, 0, 0, 0), + new Player("Player 2", "Team A", "City A", Position.DEFENDER, "Nat 1", "Agency 1", 100, 0, 0, 0, 0), + new Player("Player 3", "Team B", "City B", Position.GOALKEEPER, "Nat 2", "Agency 2", 100, 0, 0, 0, 0), + new Player("Player 4", "Team B", "City B", Position.MIDFIELD, "Nat 2", "Agency 2", 100, 0, 0, 0, 0), + new Player("Player 5", "Team C", "City C", Position.FORWARD, "Nat 3", "Agency 3", 100, 0, 0, 0, 0) + ); + + Mapper mapper = new Mapper(); + mapper.setPlayers(players); + Map playersByPosition = mapper.getPlayersByPosition(); + + assertEquals(2L, playersByPosition.get(Position.GOALKEEPER)); + assertEquals(1L, playersByPosition.get(Position.DEFENDER)); + assertEquals(1L, playersByPosition.get(Position.MIDFIELD)); + assertEquals(1L, playersByPosition.get(Position.FORWARD)); + } + + @Test + void testGetPlayersByPositionPart() { + List players = List.of( + new Player("Player 1", "Team A", "City A", Position.GOALKEEPER, "Nat 1", "Agency 1", 100, 0, 0, 0, 0), + new Player("Player 2", "Team A", "City A", Position.DEFENDER, "Nat 1", "Agency 1", 100, 0, 0, 0, 0), + new Player("Player 3", "Team B", "City B", Position.GOALKEEPER, "Nat 2", "Agency 2", 100, 0, 0, 0, 0), + new Player("Player 4", "Team B", "City B", Position.MIDFIELD, "Nat 2", "Agency 2", 100, 0, 0, 0, 0) + ); + + Mapper mapper = new Mapper(); + mapper.setPlayers(players); + Map playersByPosition = mapper.getPlayersByPosition(); + + assertEquals(2L, playersByPosition.get(Position.GOALKEEPER)); + assertEquals(1L, playersByPosition.get(Position.DEFENDER)); + assertEquals(1L, playersByPosition.get(Position.MIDFIELD)); + } + + @Test + void testGetPlayersByPositionZero() { + List players = Collections.emptyList(); + + Mapper mapper = new Mapper(); + mapper.setPlayers(players); + Map playersByPosition = mapper.getPlayersByPosition(); + + assertEquals(0, playersByPosition.size()); + } +} diff --git a/src/test/java/ru/urfu/ResolverTest.java b/src/test/java/ru/urfu/ResolverTest.java new file mode 100644 index 0000000..118a032 --- /dev/null +++ b/src/test/java/ru/urfu/ResolverTest.java @@ -0,0 +1,92 @@ +package test.java.ru.urfu; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +import main.java.ru.urfu.resolver.Resolver; +import main.java.ru.urfu.model.Player; +import main.java.ru.urfu.model.Position; + +import java.util.Collections; +import java.util.List; + +public class ResolverTest { + + @Test + void getCountWithoutAgencyTest() { + List players = List.of( + new Player("Player 1", "Team A", "City A", Position.GOALKEEPER, "Nat 1", "Agency 1", 100, 0, 0, 0, 0), + new Player("Player 2", "Team A", "City A", Position.DEFENDER, "Nat 1", "", 100, 0, 0, 0, 0), + new Player("Player 3", "Team B", "City B", Position.GOALKEEPER, "Nat 2", "", 100, 0, 0, 0, 0) + ); + Resolver resolver = new Resolver(); + resolver.setPlayers(players); + assertEquals(2, resolver.getCountWithoutAgency()); + + List emptyPlayers = Collections.emptyList(); + Resolver resolverEmpty = new Resolver(); + resolverEmpty.setPlayers(emptyPlayers); + assertEquals(0, resolverEmpty.getCountWithoutAgency()); + } + + @Test + void getMaxDefenderGoalsCountTest() { + List players = List.of( + new Player("Player 1", "Team A", "City A", Position.GOALKEEPER, "Nat 1", "Agency 1", 100, 20, 0, 0, 0), + new Player("Player 2", "Team A", "City A", Position.DEFENDER, "Nat 1", "Agency 1", 100, 1, 0, 0, 0), + new Player("Player 3", "Team B", "City B", Position.FORWARD, "Nat 2", "Agency 2", 100, 69, 0, 0, 0), + new Player("Player 4", "Team B", "City B", Position.DEFENDER, "Nat 2", "Agency 2", 100, 23, 0, 0, 0), + new Player("Player 5", "Team C", "City C", Position.DEFENDER, "Nat 3", "Agency 3", 100, 45, 0, 0, 0) + ); + Resolver resolver = new Resolver(); + resolver.setPlayers(players); + assertEquals(45, resolver.getMaxDefenderGoalsCount()); + + List emptyPlayers = Collections.emptyList(); + Resolver resolverEmpty = new Resolver(); + resolverEmpty.setPlayers(emptyPlayers); + assertEquals(0, resolverEmpty.getMaxDefenderGoalsCount()); + } + + @Test + void getTheExpensiveGermanPlayerPositionTest() { + List players = List.of( + new Player("Player 1", "Team A", "City A", Position.GOALKEEPER, "Germany", "Agency 1", 15, 20, 0, 0, 0), + new Player("Player 2", "Team A", "City A", Position.DEFENDER, "Germany", "Agency 1", 0, 1, 0, 0, 0), + new Player("Player 3", "Team B", "City B", Position.FORWARD, "France", "Agency 2", 100, 69, 0, 0, 0), + new Player("Player 4", "Team B", "City B", Position.DEFENDER, "Germany", "Agency 2", 20, 23, 0, 0, 0), + new Player("Player 5", "Team C", "City C", Position.DEFENDER, "Russian", "Agency 3", 500000, 45, 0, 0, 0) + ); + Resolver resolver = new Resolver(); + resolver.setPlayers(players); + assertEquals("Защитник", resolver.getTheExpensiveGermanPlayerPosition()); + + List noGermanPlayers = List.of( + new Player("Player 1", "Team A", "City A", Position.GOALKEEPER, "France", "Agency 1", 15, 20, 0, 0, 0), + new Player("Player 2", "Team A", "City A", Position.DEFENDER, "Russian", "Agency 1", 0, 1, 0, 0, 0) + ); + Resolver resolverNoGerman = new Resolver(); + resolverNoGerman.setPlayers(noGermanPlayers); + assertEquals("Нет немецких игроков", resolverNoGerman.getTheExpensiveGermanPlayerPosition()); + } + + @Test + void getTheRudestTeamTest() { + List players = List.of( + new Player("Player 1", "Team A", "City A", Position.GOALKEEPER, "Nat 1", "Agency 1", 100, 20, 0, 0, 2), + new Player("Player 2", "Team A", "City A", Position.DEFENDER, "Nat 1", "Agency 1", 100, 1, 0, 0, 0), + new Player("Player 3", "Team B", "City B", Position.FORWARD, "Nat 2", "Agency 2", 100, 69, 0, 0, 1), + new Player("Player 4", "Team B", "City B", Position.DEFENDER, "Nat 2", "Agency 2", 100, 23, 0, 0, 6), + new Player("Player 5", "Team C", "City C", Position.DEFENDER, "Nat 3", "Agency 3", 100, 45, 0, 0, 3) + ); + Resolver resolver = new Resolver(); + resolver.setPlayers(players); + assertEquals("Team B", resolver.getTheRudestTeam()); + + List emptyPlayers = Collections.emptyList(); + Resolver resolverEmpty = new Resolver(); + resolverEmpty.setPlayers(emptyPlayers); + assertEquals("Команд не найдено", resolverEmpty.getTheRudestTeam()); + } +}