diff --git a/README.md b/README.md index 5d686e9f..bc6fb75b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,23 @@ # Java Core June 2021 -## *Nikolaev Artem* +## *Belyaevskov Alexander* | Number | Solution | Short description | --- | --- | --- | -| HW1 | [Console printer](https://github.com/NikolaevArtem/Java_Core_June_2021/tree/master/src/main/java/homework_1) | The app that reads input arguments and prints them, until "error" argument | +| HW1 | [Console printer](https://github.com/NikolaevArtem/Java_Core_June_2021/tree/feature/AlexanderBelyaevskov/src/main/java/homework_1) | The app that reads input arguments and prints them, until "error" argument | +| HW2 | [Traffic light](https://github.com/NikolaevArtem/Java_Core_June_2021/blob/feature/AlexanderBelyaevskov/src/main/java/homework_2/TrafficLight/TrafficLight.java) | App reads current time in seconds from the console and prints the traffic light | +| HW2 | [Pyramid printer](https://github.com/NikolaevArtem/Java_Core_June_2021/blob/feature/AlexanderBelyaevskov/src/main/java/homework_2/PyramidPrinter/PyramidPrinter.java) | App reads positive integer numbers from the console and prints pyramid of "x" characters | +| HW2 | [Random chars table](https://github.com/NikolaevArtem/Java_Core_June_2021/blob/feature/AlexanderBelyaevskov/src/main/java/homework_2/RandomCharsTable/RandomCharsTable.java) | App reads from the console width and length of the chart, strategy keyword (even or odd). Prints to the console the chart of random chars from A to Z, and in separate line all the chars (from the chart) that match strategy | +| HW3 | [Immutable class example](https://github.com/NikolaevArtem/Java_Core_June_2021/blob/feature/AlexanderBelyaevskov/src/main/java/homework_3/ImmutableTask.java) | Example of an immutable class | +| HW4 | [Custom file reader](https://github.com/NikolaevArtem/Java_Core_June_2021/blob/feature/AlexanderBelyaevskov/src/main/java/homework_4/custom_file_reader/CustomFileReader.java) | Examples of 3 methods implementations for file reading | +| HW4 | [Singleton](https://github.com/NikolaevArtem/Java_Core_June_2021/tree/feature/AlexanderBelyaevskov/src/main/java/homework_4/singleton) | Examples of an singleton class | +| HW4 | [Custom Annotation](https://github.com/NikolaevArtem/Java_Core_June_2021/tree/feature/AlexanderBelyaevskov/src/main/java/homework_4/custom_annotation) | Example of an annotation that changes field name in ToString() method | +| HW5 | [Power of number](https://github.com/NikolaevArtem/Java_Core_June_2021/blob/feature/AlexanderBelyaevskov/src/main/java/homework_5/power_of_number/PowerOfNumber.java) | Power of number implementation with recursion method | +| HW5 | [Custom regex matcher](https://github.com/NikolaevArtem/Java_Core_June_2021/blob/feature/AlexanderBelyaevskov/src/main/java/homework_5/custom_regex_matcher/CustomRegexMatcher.java) | Input email argument check with regex | +| HW6 | [Map problems generator](https://github.com/NikolaevArtem/Java_Core_June_2021/blob/feature/AlexanderBelyaevskov/src/main/java/homework_6/map_problems_generator/MapProblemsCollisionGenerator.java) | Implement a class with overdid equals() and hashCode() methods, which generates 100% collision when used as key in HashMap collection.| +| HW7 | [Funtional interface](https://github.com/NikolaevArtem/Java_Core_June_2021/blob/feature/AlexanderBelyaevskov/src/main/java/homework_7/Main.java) | Custom functional interface implementation.| +| Course project | [Sea battle](https://github.com/NikolaevArtem/Java_Core_June_2021/blob/feature/AlexanderBelyaevskov/src/main/java/course_project/Main.java) | Sea battle console game.| + +[CodingBat done page](https://codingbat.com/done?user=abelyaevskov@gmail.com&tag=6930560875) [Link to markdown giude](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) diff --git a/build.gradle b/build.gradle index b91dc843..2b34ac84 100644 --- a/build.gradle +++ b/build.gradle @@ -10,6 +10,7 @@ repositories { } dependencies { + implementation 'org.junit.jupiter:junit-jupiter:5.7.0' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' } diff --git a/src/main/java/course_project/Game.java b/src/main/java/course_project/Game.java new file mode 100644 index 00000000..885e7fdf --- /dev/null +++ b/src/main/java/course_project/Game.java @@ -0,0 +1,168 @@ +package course_project; + +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Scanner; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class Game { + + private final Scanner reader; + private final SeaBattleMap[] battleMaps = new SeaBattleMap[2]; + private final String mapsSpacing = " "; + + private SeaBattleMap activeBattleMap; + private String activePlayer; + + private GameStatus status; + private String currentInput; + + Game() { + reader = new Scanner(new InputStreamReader(System.in)); + } + + void run() { + System.out.println("Welcome to SEA BATTLE console game!"); + System.out.println("Follow instructions to play the game or type \"exit\" anytyme to terminate program"); + try { + start(); + runBattle(); + } finally { + reader.close(); + } + } + + private void start() { + status = GameStatus.SettingShips; + setBattleMaps(); + setShips(); + } + + private void runBattle() { + status = GameStatus.Battle; + + activeBattleMap = battleMaps[1]; + activePlayer = battleMaps[0].getPlayerName(); + + mainLoop: + while (true) { + for (int i = 0, j = 1; i < 2; i++, j--) { + while (true) { + printBattleMaps(); + if (readShootCommand()) + if (!activeBattleMap.shoot(new Point(currentInput))) { + break; + } + if (activeBattleMap.getShips().size() == 0) { + System.out.printf("%s wins! Congrats!", activePlayer); + System.out.println(); + break mainLoop; + } + } + activeBattleMap = battleMaps[i]; + activePlayer = battleMaps[j].getPlayerName(); + } + } + } + + private void setBattleMaps() { + for (int i = 0; i < 2; i++) { + battleMaps[i] = new SeaBattleMap(10, "Player " + (i + 1)); + } + } + + private boolean readShootCommand() { + System.out.printf("%s make a shoot (e.g. A1 or E9): ", activePlayer); + currentInput = reader.nextLine(); + if (currentInput.equals("exit")) { + throw new RuntimeException("Terminated by user"); + } + String shootValidationPattern = "[A-J]([1-9]{1}|10)$"; + if (!currentInput.matches(shootValidationPattern)) { + printErrorMessage("Wrong shoot command!"); + return false; + } + return true; + } + + private void printBattleMap(SeaBattleMap battleMap) { + System.out.println( + battleMap.getView(status).stream().collect(Collectors.joining(System.lineSeparator())) + ); + } + + private void printBattleMaps() { + ArrayList view1 = battleMaps[0].getView(status); + ArrayList view2 = battleMaps[1].getView(status); + + System.out.println( + Stream.iterate(0, i -> i + 1) + .limit(view1.size()) + .map(i -> view1.get(i).concat(mapsSpacing).concat(view2.get(i))) + .collect(Collectors.joining(System.lineSeparator())) + ); + } + + private void setShips() { + for (SeaBattleMap battleMap : battleMaps) { + activeBattleMap = battleMap; + while (true) { + if (setNSizeShip(4)) + break; + } + while (true) { + if (setNSizeShip(3)) + break; + } + while (true) { + if (setNSizeShip(2)) + break; + } + while (true) { + if (setNSizeShip(1)) + break; + } + } + } + + private boolean setNSizeShip(int size) { + int shipsCount = 5 - size - activeBattleMap.getNSizedShipsCount(size); + for (int i = 0; i < shipsCount; i++) { + printBattleMap(activeBattleMap); + System.out.printf("%s, enter position and location type (R = right, D = down) " + + "to set %s-size ship (e.g. A1 R or A1 D): ", activeBattleMap.getPlayerName(), size); + String input = reader.nextLine(); + if (input.equals("exit")) { + throw new RuntimeException("Terminated by user"); + } + String setShipsValidationPattern = "[A-J]([1-9]{1}|10)\\s([RD])$"; + if (!input.matches(setShipsValidationPattern)) { + printErrorMessage("Wrong ship position command!"); + return false; + } + + String[] inputParts = input.split("\\s"); + + ShipLocationType shipLocationType = ShipLocationType.TO_RIGHT; + if (inputParts[1].equals("D")) { + shipLocationType = ShipLocationType.TO_DOWN; + } + try { + activeBattleMap.addShip(new Point(inputParts[0]), size, shipLocationType); + } catch (IllegalArgumentException e) { + printErrorMessage(e.getMessage()); + return false; + } + + } + return true; + } + + private void printErrorMessage(String message) { + final String ANSI_RED = "\u001B[31m"; + final String ANSI_BLACK = "\u001B[0m"; + System.out.println(ANSI_RED + message + ANSI_BLACK); + } + +} diff --git a/src/main/java/course_project/GameStatus.java b/src/main/java/course_project/GameStatus.java new file mode 100644 index 00000000..4068b5fa --- /dev/null +++ b/src/main/java/course_project/GameStatus.java @@ -0,0 +1,7 @@ +package course_project; + +enum GameStatus { + + SettingShips, + Battle +} diff --git a/src/main/java/course_project/Main.java b/src/main/java/course_project/Main.java new file mode 100644 index 00000000..c1991f7a --- /dev/null +++ b/src/main/java/course_project/Main.java @@ -0,0 +1,9 @@ +package course_project; + +public class Main { + + public static void main(String[] args) { + new Game().run(); + } + +} diff --git a/src/main/java/course_project/MapPointType.java b/src/main/java/course_project/MapPointType.java new file mode 100644 index 00000000..e7e8885d --- /dev/null +++ b/src/main/java/course_project/MapPointType.java @@ -0,0 +1,9 @@ +package course_project; + +enum MapPointType { + + Ship, + FiredShip, + Emty, + Fired +} diff --git a/src/main/java/course_project/Point.java b/src/main/java/course_project/Point.java new file mode 100644 index 00000000..382da1d2 --- /dev/null +++ b/src/main/java/course_project/Point.java @@ -0,0 +1,83 @@ +package course_project; + +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +class Point { + + private final int x; + private final int y; + private MapPointType type; + + Point(String consoleInput) { + + int y = IntStream.iterate(65, i -> i+1) + .limit(10) + .mapToObj(i -> String.valueOf((char) i)) + .collect(Collectors.toList()) + .indexOf(consoleInput.substring(0,1)); + this.x = Integer.parseInt(consoleInput.substring(1))-1; + this.y = y; + } + + Point(int x, int y, MapPointType type) { + this.x = x; + this.y = y; + this.type = type; + } + + int getX() { + return x; + } + + int getY() { + return y; + } + + void setType(MapPointType type) { + this.type = type; + } + + MapPointType getType() { + return type; + } + + String getView(GameStatus status) { + if (status == GameStatus.Battle) { + return getBattleView(); + } + else { + return getSettingShipsView(); + } + } + + private String getSettingShipsView() { + if (getType() == MapPointType.Ship) { + return "\u25B2" + " "; + } + return " "; + } + + private String getBattleView() { + switch (getType() + ) { + case FiredShip: return "\u2713" + " "; + case Fired: return "\u00D7" + " "; + default: return " "; + } + } + + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + Point point = (Point) o; + return x == point.x && y == point.y; + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } +} diff --git a/src/main/java/course_project/SeaBattleMap.java b/src/main/java/course_project/SeaBattleMap.java new file mode 100644 index 00000000..11367354 --- /dev/null +++ b/src/main/java/course_project/SeaBattleMap.java @@ -0,0 +1,164 @@ +package course_project; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class SeaBattleMap { + + private static final String ANSI_RED = "\u001B[31m"; + private static final String ANSI_GREEN = "\u001B[32m"; + private static final String ANSI_BLACK = "\u001B[0m"; + + private final Point[][] field; + private final int size; + + String getPlayerName() { + return playerName; + } + + private final String playerName; + private final List ships = new ArrayList<>(); + + SeaBattleMap(int size, String playerName) { + + this.size = size; + this.playerName = playerName; + + field = new Point[size][size]; + for (int i = 0, offsetX = 0; i < size; i++, offsetX++) { + for (int j = 0, offsetY = 0; j < size; j++, offsetY++) { + field[i][j] = new Point(offsetX, offsetY, MapPointType.Emty); + } + } + } + + void addShip(Point entry, int size, ShipLocationType type) throws IllegalArgumentException { + Ship ship = new Ship(field, entry, size, type); + ships.add(ship); + } + + int getNSizedShipsCount(int size) { + return ((Long) ships.stream() + .filter(s -> s.getSize() == size).count()).intValue(); + + } + + boolean shoot(Point point) { + Point fieldPoint = field[point.getX()][point.getY()]; + if (fieldPoint.getType() == MapPointType.Ship) { + fieldPoint.setType(MapPointType.FiredShip); + ships.removeIf(Ship::IsDestroyed); + System.out.println("Well done!"); + return true; + } else if (fieldPoint.getType() == MapPointType.FiredShip) { + System.out.println("It's already fired target, take a new one!"); + return true; + } + else { + fieldPoint.setType(MapPointType.Fired); + System.out.println("Bad luck! Move goes to another player"); + return false; + } + } + + List getShips() { + return ships; + } + + private int getX_Offset() { + return field[size - 1][size - 1].getX() + 1; + } + + private int getY_Offset() { + return field[size - 1][size - 1].getY() + 1; + } + + ArrayList getView(GameStatus status) { + + ArrayListImpl battleMapView = new ArrayListImpl(); + + battleMapView.add(playerName); + + String headerNumsEnumeration = Stream.iterate(1, i -> i + 1) + .limit(getX_Offset()) + .map(String::valueOf) + .collect(Collectors.joining(" ")); + + battleMapView.add(headerNumsEnumeration); + battleMapView.add( + getLineString(headerNumsEnumeration) + ); + + for (int y = 0, charIndex = 65; y < getY_Offset(); y++, charIndex++) { + StringBuilder sb = new StringBuilder(); + sb.append((char) charIndex); + sb.append("|"); + for (int x = 0; x < getX_Offset(); x++) { + sb.append( + field[x][y].getView(status) + ); + } + sb.append("|"); + battleMapView.add(sb.toString()); + } + + battleMapView.add( + getLineString(headerNumsEnumeration) + ); + + //center align + for (int i = 0; i < battleMapView.size(); i++) { + String s = battleMapView.get(i); + int maxStringLength = battleMapView.getMaxStringLength(); + int minLength = (int) Math.ceil((double) (maxStringLength - s.length()) / 2 + s.length()); + String fString = String.format("%%%ds", minLength); + if (minLength < maxStringLength) { + fString = String.format("%%%ds%%%ds", minLength, maxStringLength - minLength); + } + battleMapView.set(i, String.format(fString, s, " ")); + } + + //color ships marks after Formatter usage as Java's APIs don't natively understand ANSI color escape codes + for (int i = 0; i < battleMapView.size(); i++) { + String s = battleMapView.get(i); + if (s.contains("\u2713") || s.contains("\u00D7")) { + String coloredString = Arrays.stream(s.split("")) + .map(ss -> { + if (ss.contains("\u2713")) { + ss = ANSI_GREEN + ss + ANSI_BLACK; + } else if (ss.contains("\u00D7")) { + ss = ANSI_RED + ss + ANSI_BLACK; + } + return ss; + }) + .collect(Collectors.joining()); + + battleMapView.set(i, String.format(coloredString, s, " ")); + } + } + + return battleMapView; + } + + private String getLineString(String headerNumsEnumeration) { + return "+" + String.join("", Collections.nCopies(headerNumsEnumeration.length(), "-")) + "+"; + } + + private class ArrayListImpl extends ArrayList { + private int maxStringLength = 0; + + @Override + public boolean add(String s) { + maxStringLength = Math.max(maxStringLength, s.length()); + return super.add(s); + } + + public int getMaxStringLength() { + return maxStringLength; + } + } +} diff --git a/src/main/java/course_project/Ship.java b/src/main/java/course_project/Ship.java new file mode 100644 index 00000000..02d8cbdd --- /dev/null +++ b/src/main/java/course_project/Ship.java @@ -0,0 +1,92 @@ +package course_project; + +import java.util.Arrays; + +class Ship { + + private final Point[] points; + private final int size; + private final String errorMessage = "Wrong ship location!"; + + Ship(Point[][] field, Point entry, int size, ShipLocationType type) throws IllegalArgumentException { + points = new Point[size]; + this.size = size; + + + for (int i = 0, x = entry.getX(), y = entry.getY(); i < size; i++) { + Point point; + try { + point = field[x][y]; + } catch (IndexOutOfBoundsException e) { + throw new IllegalArgumentException(errorMessage); + } + if (point.getType() == MapPointType.Ship) { + throw new IllegalArgumentException(errorMessage); + } + checkNearestPoints(field, point); + points[i] = point; + switch (type) { + case TO_DOWN: + y++; + break; + case TO_RIGHT: + x++; + break; + default: + throw new UnsupportedOperationException(); + } + } + + for (Point point : points) { + point.setType(MapPointType.Ship); + } + + } + + private boolean IsShipPoint(Point point) { + return Arrays.asList(points).contains(point); + } + + boolean IsDestroyed () { + return Arrays.stream(points).allMatch(e -> e.getType() == MapPointType.FiredShip); + } + + private void checkNearestPoints(Point[][] field, Point entry) throws IllegalArgumentException { + + try { + if (field[entry.getX() - 1][entry.getY()].getType() == MapPointType.Ship && !IsShipPoint(entry)) { + throw new IllegalArgumentException(errorMessage); + } + } catch (IndexOutOfBoundsException e) { + + } + + try { + if (field[entry.getX() + 1][entry.getY()].getType() == MapPointType.Ship && !IsShipPoint(entry)) { + throw new IllegalArgumentException(errorMessage); + } + } catch (IndexOutOfBoundsException e) { + + } + + try { + if (field[entry.getX()][entry.getY() - 1].getType() == MapPointType.Ship && !IsShipPoint(entry)) { + throw new IllegalArgumentException(errorMessage); + } + } catch (IndexOutOfBoundsException e) { + + } + + try { + if (field[entry.getX()][entry.getY() + 1].getType() == MapPointType.Ship && !IsShipPoint(entry)) { + throw new IllegalArgumentException(errorMessage); + } + } catch (IndexOutOfBoundsException e) { + + } + } + + int getSize() { + return size; + } +} diff --git a/src/main/java/course_project/ShipLocationType.java b/src/main/java/course_project/ShipLocationType.java new file mode 100644 index 00000000..fcc2f3b8 --- /dev/null +++ b/src/main/java/course_project/ShipLocationType.java @@ -0,0 +1,8 @@ +package course_project; + +enum ShipLocationType { + + TO_RIGHT, + TO_DOWN + +} diff --git a/src/main/java/homework_1/Main.java b/src/main/java/homework_1/Main.java index 07c029a2..af3f7243 100644 --- a/src/main/java/homework_1/Main.java +++ b/src/main/java/homework_1/Main.java @@ -1,9 +1,23 @@ package homework_1; -public class Main { - - public static void main(String[] args) { - System.out.println("Hello homework!"); - } +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; -} +public class Main { + public static void main(String[] args) { + if (Charset.defaultCharset() != StandardCharsets.UTF_8) { + System.out.println("For correct display cyrillic args need to run with \"-Dfile.encoding=\"UTF-8\"\""); + } + if (args.length == 0) { + System.out.println("No arguments provided!"); + } else { + for (String arg : args) { + if (arg.matches("error")) { + System.out.println("\u001B[31m" + "Alarm!" + "\u001B[0m"); + break; + } + System.out.printf("%s: %s letter(s)\n", arg, arg.length()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/homework_2/pyramid_printer/Main.java b/src/main/java/homework_2/pyramid_printer/Main.java new file mode 100644 index 00000000..71e33035 --- /dev/null +++ b/src/main/java/homework_2/pyramid_printer/Main.java @@ -0,0 +1,8 @@ +package homework_2.pyramid_printer; + +public class Main { + + public static void main(String[] args) { + new PyramidPrinter().run(); + } +} diff --git a/src/main/java/homework_2/pyramid_printer/PyramidPrinter.java b/src/main/java/homework_2/pyramid_printer/PyramidPrinter.java new file mode 100644 index 00000000..7998f254 --- /dev/null +++ b/src/main/java/homework_2/pyramid_printer/PyramidPrinter.java @@ -0,0 +1,45 @@ +package homework_2.pyramid_printer; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.StringJoiner; + +public final class PyramidPrinter { + + private int inputInt; + + public void run() { + try { + readFromConsole(); + printPyramid(); + } catch (Exception e) { + System.out.println("\u001B[31m" + "Only 1 non-negative integer is allowed as passed parameter" + "\u001B[0m"); + } + } + + private void readFromConsole() throws Exception { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { + System.out.printf("Enter int value from 0 - %s: ", Integer.MAX_VALUE); + String inputString = reader.readLine(); + inputInt = validateInput(inputString); + } + } + + private int validateInput(String inputString) throws IllegalArgumentException { + if (!inputString.matches("^\\d+$") || inputString.matches("0")) { + throw new IllegalArgumentException(); + } + return Integer.parseInt(inputString); + } + + private void printPyramid() { + StringJoiner joiner = new StringJoiner("\r\n"); + String outputString = "x"; + for (int i = 0; i < inputInt; i++) { + joiner.add(outputString); + outputString = outputString + "x"; + } + System.out.println(joiner); + } + +} \ No newline at end of file diff --git a/src/main/java/homework_2/random_chars_table/Main.java b/src/main/java/homework_2/random_chars_table/Main.java new file mode 100644 index 00000000..be586c4b --- /dev/null +++ b/src/main/java/homework_2/random_chars_table/Main.java @@ -0,0 +1,8 @@ +package homework_2.random_chars_table; + +public class Main { + + public static void main(String[] args) { + new RandomCharsTable().run(); + } +} diff --git a/src/main/java/homework_2/random_chars_table/RandomCharsTable.java b/src/main/java/homework_2/random_chars_table/RandomCharsTable.java new file mode 100644 index 00000000..d7be4196 --- /dev/null +++ b/src/main/java/homework_2/random_chars_table/RandomCharsTable.java @@ -0,0 +1,73 @@ +package homework_2.random_chars_table; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.Random; +import java.util.StringJoiner; + +public final class RandomCharsTable { + + private int length; + private int width; + private String strategy; + private static final String ERROR_MESSAGE = "\u001B[31m" + "Passed parameters should match the format [positive integer] [positive integer] [even|odd]" + "\u001B[0m"; + + public void run() { + try { + if (readFromConsole()) { + printArray(); + } + } catch (Exception e) { + System.out.println(ERROR_MESSAGE); + } + } + + private boolean readFromConsole() throws Exception { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { + System.out.print("Enter value in format [positive integer] [positive integer] [even|odd]: "); + return validateInput(reader.readLine()); + } + } + + private boolean validateInput(String inputString) throws IllegalArgumentException { + + if (inputString.matches("\\s*[1-9]\\s+[1-9]\\s+(even|odd){1}$")) { + String[] paramArray = inputString.split("\\s+"); + length = Integer.parseInt(paramArray[0]); + width = Integer.parseInt(paramArray[1]); + strategy = paramArray[2]; + return true; + } else { + System.out.println(ERROR_MESSAGE); + return false; + } + } + + private void printArray() { + + StringJoiner joiner = new StringJoiner(","); + StringBuilder tableOutput = new StringBuilder(); + + Random rand = new Random(); + char[] alphabetLetters = "abcdefghijklmnopqrstuvwxyz".toUpperCase().toCharArray(); + + for (int i = 0; i < length; i++) { + for (int j = 0; j < width; j++) { + int randomIndex = rand.nextInt(alphabetLetters.length); + char letter = alphabetLetters[randomIndex]; + if (strategyMatch(letter)) { + joiner.add("" + letter); + } + tableOutput.append("|").append(letter); + } + tableOutput.append("|").append("\n\r"); + } + String lastRow = String.format("%s%s letters - %s", strategy.substring(0,1).toUpperCase(), strategy.substring(1), joiner); + System.out.println(tableOutput + lastRow); + } + + private boolean strategyMatch(char charItem) { + return (strategy.equals("even") && charItem % 2 == 0) || (strategy.equals("odd") && charItem % 2 != 0); + } + +} diff --git a/src/main/java/homework_2/traffic_light/Main.java b/src/main/java/homework_2/traffic_light/Main.java new file mode 100644 index 00000000..3ff7f428 --- /dev/null +++ b/src/main/java/homework_2/traffic_light/Main.java @@ -0,0 +1,8 @@ +package homework_2.traffic_light; + +public class Main { + + public static void main(String[] args) { + new TrafficLight().run(); + } +} diff --git a/src/main/java/homework_2/traffic_light/TrafficLight.java b/src/main/java/homework_2/traffic_light/TrafficLight.java new file mode 100644 index 00000000..9ecd9979 --- /dev/null +++ b/src/main/java/homework_2/traffic_light/TrafficLight.java @@ -0,0 +1,70 @@ +package homework_2.traffic_light; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +public final class TrafficLight { + + private static final String ANSI_RED = "\u001B[31m"; + private static final String ANSI_GREEN = "\u001B[32m"; + private static final String ANSI_YELLOW = "\u001B[33m"; + private static final String ANSI_BLACK = "\u001B[0m"; + + private int inputInt; + + public void run() { + try { + if (readFromConsole()) { + printTrafficLight(); + } + } catch (Exception e) { + printError("Only 1 non-negative integer is allowed as passed parameter"); + } + } + + private void printTrafficLight() { + int SecondsInLastMinute = inputInt % 60; + String currentColor, currentColorText; + if (SecondsInLastMinute < 35) { + currentColorText = "green"; + currentColor = ANSI_GREEN; + } else if (SecondsInLastMinute < 40) { + currentColorText = "yellow"; + currentColor = ANSI_YELLOW; + } else if (SecondsInLastMinute < 55) { + currentColorText = "red"; + currentColor = ANSI_RED; + } else { + currentColorText = "yellow"; + currentColor = ANSI_YELLOW; + } + System.out.println(currentColor + currentColorText.toUpperCase() + ANSI_BLACK); + } + + public static void printError(String Message) { + System.out.println(ANSI_RED + "Error! " + Message + ANSI_BLACK); + } + + boolean readFromConsole() throws Exception { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { + System.out.print("Enter seconds value (int) from 0 - 86399: "); + String inputString = reader.readLine(); + return validateInput(inputString); + } + } + + private boolean validateInput(String inputString) throws NumberFormatException { + boolean result = false; + int newInt = Integer.parseInt(inputString); + if (newInt < 0) { + printError("Only 1 non-negative integer is allowed as passed parameter"); + } else if (newInt > 86399) { + printError("Day is over!"); + } else { + inputInt = newInt; + result = true; + } + return result; + } + +} \ No newline at end of file diff --git a/src/main/java/homework_3/ImmutableTask.java b/src/main/java/homework_3/ImmutableTask.java new file mode 100644 index 00000000..19d8f1a7 --- /dev/null +++ b/src/main/java/homework_3/ImmutableTask.java @@ -0,0 +1,96 @@ +package homework_3; + +import java.util.Arrays; + +public final class ImmutableTask { + +// Requirements for immutable class: +// The class must be declared as final (So that child classes can’t be created) +// Data members in the class must be declared as private (So that direct access is not allowed) +// Data members in the class must be declared as final (So that we can’t change the value of it after object creation) +// A parameterized constructor should initialize all the fields performing a deep copy (So that data members can’t be modified with object reference) +// Deep Copy of objects should be performed in the getter methods (To return a copy rather than returning the actual object reference) +// No setters (To not have the option to change the value of the instance variable) +// To change class properties, class should have methods which return a new instance of a class with new properties + + private final String name; + private final String description; + private final int estimation; + private final String[] additionalInfo; + + public ImmutableTask(String name) { + this.name = name; + this.description = ""; + this.estimation = 0; + this.additionalInfo = new String[]{}; + } + + public ImmutableTask(String name, String description) { + this.name = name; + this.description = description; + this.estimation = 0; + this.additionalInfo = new String[]{}; + } + + public ImmutableTask(String name, String description, int estimation) { + this.name = name; + this.description = description; + this.estimation = estimation; + this.additionalInfo = new String[]{}; + } + + public ImmutableTask(String name, String description, int estimation, String[] additionalInfo) { + this.name = name; + this.description = description; + this.estimation = estimation; + //since array contains immutable values, shallow copy is OK + this.additionalInfo = additionalInfo.clone(); + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public int getEstimation() { + return estimation; + } + + public String[] getAdditionalInfo() { + //since array contains immutable values, shallow copy is OK + return additionalInfo.clone(); + } + + public ImmutableTask changeName (String newName){ + //since class is immutable return a new instance with changed property + return new ImmutableTask(newName, getDescription(), getEstimation(), getAdditionalInfo()); + } + + public ImmutableTask changeDescription (String newDescription){ + //since class is immutable return a new instance with changed property + return new ImmutableTask(getName(), newDescription, getEstimation(), getAdditionalInfo()); + } + + public ImmutableTask changeAdditionalInfo(int index, String value){ + if (index + 1 > additionalInfo.length){ + throw new RuntimeException("Index of AdditionalInfo is out of bounds"); + } + String[] newArray = getAdditionalInfo(); + newArray[index] = value; + //since class is immutable return a new instance with changed property + return new ImmutableTask(getName(), getDescription(), getEstimation(), newArray); + } + + @Override + public String toString() { + return String.format("name: %s\ndescription: %s\nestimation: %s\nadditionalInfo: %s", + getName(), + getDescription(), + getEstimation(), + Arrays.deepToString(getAdditionalInfo())); + } +} + diff --git a/src/main/java/homework_4/custom_annotation/ChangeOutputName.java b/src/main/java/homework_4/custom_annotation/ChangeOutputName.java new file mode 100644 index 00000000..d1599243 --- /dev/null +++ b/src/main/java/homework_4/custom_annotation/ChangeOutputName.java @@ -0,0 +1,12 @@ +package homework_4.custom_annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ChangeOutputName { + String value(); +} diff --git a/src/main/java/homework_4/custom_annotation/Customer.java b/src/main/java/homework_4/custom_annotation/Customer.java new file mode 100644 index 00000000..43748ba6 --- /dev/null +++ b/src/main/java/homework_4/custom_annotation/Customer.java @@ -0,0 +1,65 @@ +package homework_4.custom_annotation; + +import java.lang.reflect.Field; + +public class Customer { + + @ChangeOutputName("Наименование") + private String name; + @ChangeOutputName("Полное имя") + private String fullName; + private String address; + @ChangeOutputName("Номер телефона") + private String phoneNumber; + + public Customer() { + } + + public Customer(String name, String fullName) { + this.name = name; + this.fullName = fullName; + } + + public void setName(String name) { + this.name = name; + } + + public void setFullName(String fullName) { + this.fullName = fullName; + } + + @Override + public String toString() { + + String result = "Customer{" + + "%s='" + name + '\'' + + ", %s='" + fullName + '\'' + + ", %s='" + address + '\'' + + ", %s='" + phoneNumber + '\'' + + '}'; + + return getMappedString(result); + } + + private String getMappedString(String s) { + + Class customAnnotationClass = ChangeOutputName.class; + + Field[] declaredFields = this.getClass().getDeclaredFields(); + + String[] fieldNames = new String[declaredFields.length]; + + for (int i = 0; i < declaredFields.length; i++) { + Field field = declaredFields[i]; + field.setAccessible(true); + if (field.isAnnotationPresent(customAnnotationClass)) { + fieldNames[i] = field.getAnnotation(customAnnotationClass).value(); + } else { + fieldNames[i] = field.getName(); + } + } + + return String.format(s, (Object[]) fieldNames); + + } +} diff --git a/src/main/java/homework_4/custom_annotation/Main.java b/src/main/java/homework_4/custom_annotation/Main.java new file mode 100644 index 00000000..a4a8c3cd --- /dev/null +++ b/src/main/java/homework_4/custom_annotation/Main.java @@ -0,0 +1,14 @@ +package homework_4.custom_annotation; + +public class Main { + + public static void main(String[] args) { + + Customer customer = new Customer("ООО \"Ромашка\"", + "Общество с ограниченной ответственностью \"Ромашка\""); + + System.out.println(customer); + + } + +} diff --git a/src/main/java/homework_4/custom_file_reader/CustomFileReader.java b/src/main/java/homework_4/custom_file_reader/CustomFileReader.java new file mode 100644 index 00000000..941aa540 --- /dev/null +++ b/src/main/java/homework_4/custom_file_reader/CustomFileReader.java @@ -0,0 +1,61 @@ +package homework_4.custom_file_reader; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Scanner; +import java.util.stream.Collectors; + +public class CustomFileReader { + + private final Path path = Paths.get("src/main/resources/file.txt"); + private final String lineSeparator = System.lineSeparator(); + private String resultString = ""; + + public final void run1() { + try { + //using nio's File class wrapper + resultString = String.join(lineSeparator, Files.readAllLines(path)); + } catch (IOException e) { + e.printStackTrace(); + } + EditAndPrintResult(); + } + + public final void run2() { + //using core IO + streams + try (BufferedReader reader = new BufferedReader(new FileReader(path.toAbsolutePath().toString()))) { + resultString = reader.lines().collect(Collectors.joining(lineSeparator)); + EditAndPrintResult(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public final void run3() { + //using core IO + Scanner + try (FileReader reader = new FileReader(path.toAbsolutePath().toString())) { + Scanner scanner = new Scanner(reader); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.isEmpty()) { + break; + } + resultString += line + lineSeparator; + } + EditAndPrintResult(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void EditAndPrintResult() { + resultString = resultString.replaceAll("[.,]", ""); //not the fastest way but readable + System.out.println(resultString); + } + +} diff --git a/src/main/java/homework_4/custom_file_reader/Main.java b/src/main/java/homework_4/custom_file_reader/Main.java new file mode 100644 index 00000000..264dc882 --- /dev/null +++ b/src/main/java/homework_4/custom_file_reader/Main.java @@ -0,0 +1,11 @@ +package homework_4.custom_file_reader; + +public class Main { + + public static void main(String[] args) { + + new CustomFileReader().run1(); + new CustomFileReader().run2(); + new CustomFileReader().run3(); + } +} diff --git a/src/main/java/homework_4/singleton/DatabaseConnection.java b/src/main/java/homework_4/singleton/DatabaseConnection.java new file mode 100644 index 00000000..4f77f711 --- /dev/null +++ b/src/main/java/homework_4/singleton/DatabaseConnection.java @@ -0,0 +1,32 @@ +package homework_4.singleton; + +import java.util.UUID; + +public class DatabaseConnection { + + private String userName; + private UUID sessionID; + + private static DatabaseConnection instance; + + //Private constructor to avoid instantiation + private DatabaseConnection(String userName) { + this.userName = userName; + this.sessionID = UUID.randomUUID(); //should be received from db + String message = String.format("Database connection instantiated for user %s with uuid %s", userName, sessionID); + System.out.println(message); + } + + //Double-checked locking design pattern to avoid several instantiations in multithreading + public static DatabaseConnection getInstance(String userName) { + if (instance == null) { + synchronized (DatabaseConnection.class) { + if (instance == null) { + instance = new DatabaseConnection(userName); + } + } + } + return instance; + } + +} diff --git a/src/main/java/homework_4/singleton/EnumDatabaseConnection.java b/src/main/java/homework_4/singleton/EnumDatabaseConnection.java new file mode 100644 index 00000000..2fa19593 --- /dev/null +++ b/src/main/java/homework_4/singleton/EnumDatabaseConnection.java @@ -0,0 +1,25 @@ +package homework_4.singleton; + +import java.util.UUID; + +//has serialization and thread-safety guaranteed by the enum implementation itself +public enum EnumDatabaseConnection { + + INSTANCE; + + private UUID sessionID; + + EnumDatabaseConnection() { + this.sessionID = UUID.randomUUID(); //should be received from db + String message = String.format("Database connection instantiated with uuid %s", sessionID); + System.out.println(message); + } + + //Double-checked locking design pattern to avoid several instantiations in multithreading + public EnumDatabaseConnection getInstance() { + return INSTANCE; + } + + + +} diff --git a/src/main/java/homework_4/singleton/Main.java b/src/main/java/homework_4/singleton/Main.java new file mode 100644 index 00000000..0ebe3a42 --- /dev/null +++ b/src/main/java/homework_4/singleton/Main.java @@ -0,0 +1,30 @@ +package homework_4.singleton; + +public class Main { + + public static void main(String[] args) { + + //Class singleton + + String userName1 = "admin"; + DatabaseConnection classSingleton1 = DatabaseConnection.getInstance(userName1); +// DatabaseConnection object1 = new DatabaseConnection(); // The constructor DatabaseConnection() is not visible + + String userName2 = "superAdmin"; + DatabaseConnection classSingleton2 = DatabaseConnection.getInstance(userName2); + + System.out.println(classSingleton1); + System.out.println(classSingleton2); + + //Enum singleton + + EnumDatabaseConnection enumSingleton1 = EnumDatabaseConnection.INSTANCE.getInstance(); + + EnumDatabaseConnection enumSingleton2 = EnumDatabaseConnection.INSTANCE.getInstance(); + + System.out.println(enumSingleton1); + System.out.println(enumSingleton2); + + + } +} diff --git a/src/main/java/homework_5/custom_regex_matcher/CustomRegexMatcher.java b/src/main/java/homework_5/custom_regex_matcher/CustomRegexMatcher.java new file mode 100644 index 00000000..7fbd2e7f --- /dev/null +++ b/src/main/java/homework_5/custom_regex_matcher/CustomRegexMatcher.java @@ -0,0 +1,25 @@ +package homework_5.custom_regex_matcher; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class CustomRegexMatcher { + + final private String regex_email = "^[^0-9]\\w+@[^0-9]\\w+(\\.[a-z]{2,3}){1,2}$"; + //regex issues: + //username doesn't start with digit + //domain name doesn't start with digit + //domain zone length 2 or 3 chars + //accepts one or double domain zone + + final void readFromConsole(){ + try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { + System.out.print("Enter your email: "); + String inputString = reader.readLine(); + System.out.println(inputString.matches(regex_email)); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } +} diff --git a/src/main/java/homework_5/custom_regex_matcher/Main.java b/src/main/java/homework_5/custom_regex_matcher/Main.java new file mode 100644 index 00000000..6c809ffb --- /dev/null +++ b/src/main/java/homework_5/custom_regex_matcher/Main.java @@ -0,0 +1,8 @@ +package homework_5.custom_regex_matcher; + +public class Main { + + public static void main(String[] args) { + new CustomRegexMatcher().readFromConsole(); + } +} diff --git a/src/main/java/homework_5/power_of_number/Main.java b/src/main/java/homework_5/power_of_number/Main.java new file mode 100644 index 00000000..89300565 --- /dev/null +++ b/src/main/java/homework_5/power_of_number/Main.java @@ -0,0 +1,8 @@ +package homework_5.power_of_number; + +public class Main { + + public static void main(String[] args) { + new PowerOfNumber().run(); + } +} diff --git a/src/main/java/homework_5/power_of_number/PowerOfNumber.java b/src/main/java/homework_5/power_of_number/PowerOfNumber.java new file mode 100644 index 00000000..72703ee0 --- /dev/null +++ b/src/main/java/homework_5/power_of_number/PowerOfNumber.java @@ -0,0 +1,54 @@ +package homework_5.power_of_number; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.math.BigInteger; + +public class PowerOfNumber { + + private int number; + private int power; + private BigInteger powerOfNumber; + + public void run() { + try { + readFromConsole(); + if (power == 0) { + powerOfNumber = BigInteger.ONE; + } else if (number == 0) { + powerOfNumber = BigInteger.ZERO; + } else { + powerOfNumber = BigInteger.valueOf(number); + countPowerOfNumber(power); + } + System.out.printf("Power %s of number %s is: %s", power, number, powerOfNumber); + } catch (IOException | NullPointerException e) { + System.out.println("Only 2 non-negative integers are allowed"); + } + + } + + private void countPowerOfNumber(int power) { + if (power != 1) { + powerOfNumber = powerOfNumber.multiply(BigInteger.valueOf(number)); + power--; + countPowerOfNumber(power); + } + } + + private void readFromConsole() throws IOException, NullPointerException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { + System.out.print("Enter 2 positive integer numbers: "); + String inputString = reader.readLine(); + if (inputString.matches("^\\d+\\s\\d+$")) { + String[] paramArray = inputString.split("\\s+"); + number = Integer.parseInt(paramArray[0]); + power = Integer.parseInt(paramArray[1]); + } else { + throw new IOException(); + } + } + } + +} diff --git a/src/main/java/homework_6/map_problems_generator/MapProblemsCollisionGenerator.java b/src/main/java/homework_6/map_problems_generator/MapProblemsCollisionGenerator.java new file mode 100644 index 00000000..a389e226 --- /dev/null +++ b/src/main/java/homework_6/map_problems_generator/MapProblemsCollisionGenerator.java @@ -0,0 +1,31 @@ +package homework_6.map_problems_generator; + +import java.util.HashMap; + +public class MapProblemsCollisionGenerator { + + public static void main(String[] args) { + + HashMap myHashMap = new HashMap<>(); + + MapProblemsMutableGenerator bugger1 = new MapProblemsMutableGenerator("Sasha", "bugger", 40); + MapProblemsMutableGenerator bugger2 = new MapProblemsMutableGenerator("Pasha", "troubleMaker", 30); + MapProblemsMutableGenerator bugger3 = new MapProblemsMutableGenerator("Yura", "juniorForever", 35); + + System.out.println("Put bugger 1"); + myHashMap.put(bugger1, 1); + System.out.println("Put bugger 2"); + myHashMap.put(bugger2, 2); + System.out.println("Put bugger 3"); + myHashMap.put(bugger3, 3); + + System.out.println("Change bugger2 nick"); + bugger2.setNickName("bigBug"); + + System.out.println("We can't get the value by key, since key HashCode() differs. Extracted value for bugger2 is: " + + myHashMap.get(bugger2)); + + System.out.println("HashMap keys: " + myHashMap.keySet()); + + } +} diff --git a/src/main/java/homework_6/map_problems_generator/MapProblemsMutableGenerator.java b/src/main/java/homework_6/map_problems_generator/MapProblemsMutableGenerator.java new file mode 100644 index 00000000..9ac32df6 --- /dev/null +++ b/src/main/java/homework_6/map_problems_generator/MapProblemsMutableGenerator.java @@ -0,0 +1,47 @@ +package homework_6.map_problems_generator; + +import java.util.Objects; + +public class MapProblemsMutableGenerator { + + private String Name; + private String nickName; + private int age; + + public void setName(String name) { + Name = name; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public void setAge(int age) { + this.age = age; + } + + public MapProblemsMutableGenerator(String name, String nickName, int age) { + Name = name; + this.nickName = nickName; + this.age = age; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MapProblemsMutableGenerator that = (MapProblemsMutableGenerator) o; + return age == that.age && Objects.equals(Name, that.Name) && Objects.equals(nickName, that.nickName); + } + + @Override + public int hashCode() { + //hashCode doesn't keep general contract + + //Whenever it is invoked on the same object more than once during an execution of a Java application, + //the hashCode method must consistently return the same integer. + // In other words for the same reference if MapProblemsMutableGenerator.equals() = true, hashCode() differs. + + return Objects.hash(Name, nickName, age); + } +} diff --git a/src/main/java/homework_7/Cat.java b/src/main/java/homework_7/Cat.java new file mode 100644 index 00000000..990835c3 --- /dev/null +++ b/src/main/java/homework_7/Cat.java @@ -0,0 +1,38 @@ +package homework_7; + +public class Cat { + private String name; + private int age; + private String color; + + @Override + public String toString() { + return "Cat{" + + "name='" + name + '\'' + + ", age=" + age + + ", color='" + color + '\'' + + '}'; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + public Cat(String name, int age, String color) { + this.name = name; + this.age = age; + this.color = color; + } +} diff --git a/src/main/java/homework_7/ChildKitten.java b/src/main/java/homework_7/ChildKitten.java new file mode 100644 index 00000000..cd54cd9b --- /dev/null +++ b/src/main/java/homework_7/ChildKitten.java @@ -0,0 +1,24 @@ +package homework_7; + +public class ChildKitten extends Kitten{ + + String color; + + public ChildKitten(String name, int age, String color) { + super(name, age); + this.color = color; + } + + public String getColor() { + return color; + } + + @Override + public String toString() { + return "ChildKitten{" + + "color='" + color + '\'' + + ", name='" + name + '\'' + + ", age=" + age + + '}'; + } +} diff --git a/src/main/java/homework_7/Kitten.java b/src/main/java/homework_7/Kitten.java new file mode 100644 index 00000000..3c5c0540 --- /dev/null +++ b/src/main/java/homework_7/Kitten.java @@ -0,0 +1,28 @@ +package homework_7; + +public class Kitten { + String name; + int age; + + public Kitten(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + +} diff --git a/src/main/java/homework_7/KittenToCatFunction.java b/src/main/java/homework_7/KittenToCatFunction.java new file mode 100644 index 00000000..b71700a1 --- /dev/null +++ b/src/main/java/homework_7/KittenToCatFunction.java @@ -0,0 +1,6 @@ +package homework_7; + +@FunctionalInterface +public interface KittenToCatFunction { + C grow(K kitten); +} diff --git a/src/main/java/homework_7/Main.java b/src/main/java/homework_7/Main.java new file mode 100644 index 00000000..24304f2f --- /dev/null +++ b/src/main/java/homework_7/Main.java @@ -0,0 +1,18 @@ +package homework_7; + +public class Main { + + public static void main(String[] args) { + + ChildKitten childKitten = new ChildKitten("Vasilisa", 0, "black"); + System.out.println("Kitten :" + childKitten); + + Cat grownKitten = ((KittenToCatFunction) kitten1 -> { + return new Cat(kitten1.getName(), kitten1.getAge() + 2, "black&white"); + }).grow(childKitten); + + System.out.println("Grown kitten :" + grownKitten); + + + } +} diff --git a/src/main/resources/file.txt b/src/main/resources/file.txt new file mode 100644 index 00000000..e5212bfb --- /dev/null +++ b/src/main/resources/file.txt @@ -0,0 +1,14 @@ +test; 564564; +0.0 +-0.0 +-0.3333333333333333 +0.3333333333333333 +-0.9166666666666665 +0.4166666666666667 +-0.7037037037037036 +0.962962962962963 +-0.3333333333333333 +-0.3333333333333333 +-0.6666666666666666 +0.0 +-1.25 diff --git a/src/test/java/homework_2/pyramid_printer/PyramidPrinterTest.java b/src/test/java/homework_2/pyramid_printer/PyramidPrinterTest.java new file mode 100644 index 00000000..0e8b72e5 --- /dev/null +++ b/src/test/java/homework_2/pyramid_printer/PyramidPrinterTest.java @@ -0,0 +1,78 @@ +package homework_2.pyramid_printer; + +import base.UnitBase; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.StringJoiner; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class PyramidPrinterTest extends UnitBase { + + private static String welcomeMessage = String.format("Enter int value from 0 - %s: ", Integer.MAX_VALUE); + private static String errorMessage = "Only 1 non-negative integer is allowed as passed parameter"; + + @ParameterizedTest + @MethodSource("testCases") + void test_MainCases(final String input, final String expected) { + setInput(input); + new PyramidPrinter().run(); + printOut(); + removeFromOutput(welcomeMessage); + String actual = getOutput(); + assertEquals(expected, actual); + } + + static Stream testCases() { + return Stream.of( + Arguments.of("1", getOutput(1)), + //Arguments.of("2147483647", getOutput(2147483647)), //OutOfMemoryError, Java heap space + Arguments.of("3", getOutput(3)), + Arguments.of("5", getOutput(5)), + Arguments.of("133", getOutput(133)), + Arguments.of("255", getOutput(255)), + Arguments.of("0005", getOutput(5)), + Arguments.of("50", getOutput(50)) + ); + } + + @ParameterizedTest + @MethodSource("zero_Negative_NonDigit_Values") + void test_Zero_Negative_NonDigit_Values(final String input, final String expected) { + setInput(input); + new PyramidPrinter().run(); + printOut(); + removeFromOutput(welcomeMessage); + String actual = getOutput(); + assertTrue(actual.contains(expected)); + } + + static Stream zero_Negative_NonDigit_Values() { + return Stream.of( + Arguments.of("test", errorMessage), + Arguments.of("5878 545454 464", errorMessage), + Arguments.of("hello", errorMessage), + Arguments.of("0", errorMessage), + Arguments.of("-5", errorMessage), + Arguments.of("-100000000", errorMessage), + Arguments.of("", errorMessage), + Arguments.of(" ", errorMessage), + Arguments.of("2147483648", errorMessage) + ); + } + + private static String getOutput(int inputInt) { + StringJoiner joiner = new StringJoiner("\r\n"); + String outputString = "x"; + for (int i = 0; i < inputInt; i++) { + joiner.add(outputString); + outputString = outputString + "x"; + } + return joiner.toString(); + } + +} \ No newline at end of file diff --git a/src/test/java/homework_2/random_chars_table/RandomCharsTableTest.java b/src/test/java/homework_2/random_chars_table/RandomCharsTableTest.java new file mode 100644 index 00000000..bde6b13e --- /dev/null +++ b/src/test/java/homework_2/random_chars_table/RandomCharsTableTest.java @@ -0,0 +1,145 @@ +package homework_2.random_chars_table; + +import base.UnitBase; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.StringJoiner; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class RandomCharsTableTest extends UnitBase { + + private static final String welcomeMessage = "Enter value in format [positive integer] [positive integer] [even|odd]: "; + private static final String errorMessage = "Passed parameters should match the format [positive integer] [positive integer] [even|odd]"; + + @ParameterizedTest + @MethodSource("testCases") + void test_MainCases(final String input, final int length, final int width, final String strategy) { + + setInput(input); + new RandomCharsTable().run(); + printOut(); + removeFromOutput(welcomeMessage); + String actual = getOutput(); + + //check width + String widthCheckResult = checkWidth(actual, width); + assertTrue(widthCheckResult.isEmpty(), widthCheckResult); + + String[][] outputTable = parseOutput(actual, length, width); + + //check chars + String charsCheckResult = checkCharsInTable(outputTable); + assertTrue(charsCheckResult.isEmpty(), charsCheckResult); + + //check strategy + String strategyCheckResult = checkStrategy(actual, outputTable, strategy); + assertTrue(strategyCheckResult.isEmpty(), strategyCheckResult); + + //check length + String lengthNotCheckedMessage = String.format("Length of the table is not correct, expected %s.", length); + assertEquals(length, actual.split("\n\r").length - 1, lengthNotCheckedMessage); + + } + + static Stream testCases() { + return Stream.of( + Arguments.of("2 5 odd", 2, 5, "odd"), + Arguments.of("3 5 even", 3, 5, "even") + ); + } + + @ParameterizedTest + @MethodSource("garbageInput") + void test_garbageInput(final String input, final String expected) { + setInput(input); + new RandomCharsTable().run(); + printOut(); + removeFromOutput(welcomeMessage); + String actual = getOutput(); + assertTrue(actual.contains(expected)); + } + + static Stream garbageInput() { + return Stream.of( + Arguments.of("test", errorMessage), + Arguments.of("5 6 odd ", errorMessage), + Arguments.of("0 0 odd", errorMessage), + Arguments.of("0 0 even", errorMessage), + Arguments.of("5 6 Even", errorMessage), + Arguments.of("2 2 oddeven", errorMessage), + Arguments.of("0", errorMessage), + Arguments.of("-5", errorMessage), + Arguments.of("-100000000", errorMessage), + Arguments.of("", errorMessage), + Arguments.of(" ", errorMessage) + ); + } + + private String checkStrategy(String actual, String[][] outputTable, String strategy) { + String result = ""; + StringJoiner joiner = new StringJoiner(","); + for (String[] strings : outputTable) { + for (String string : strings) { + char letter = string.charAt(0); + if (strategyMatch(letter, strategy)) { + joiner.add("" + letter); + } + } + } + String strategyString = String.format("%s%s letters - %s", strategy.substring(0, 1).toUpperCase(), strategy.substring(1), joiner); + String[] rows = actual.split("\n\r"); + String lastRow = rows[rows.length - 1]; + if (!lastRow.matches(strategyString)) { + result = result + String.format("The last row in output is incorrect. Expected: %s.", strategyString); + } + return result; + } + + private String[][] parseOutput(String actual, int length, int width) { + String[][] result = new String[length][width]; + String[] rows = actual.split("\n\r"); + for (int i = 0; i < length; i++) { + String[] charSeqInRow = rows[i].replace("|", "").split(""); + for (int j = 0; j < width; j++) { + result[i][j] = charSeqInRow[j]; + } + } + return result; + } + + private String checkCharsInTable(String[][] outputTable) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < outputTable.length; i++) { + for (int j = 0; j < outputTable[i].length; j++) { + if (!outputTable[i][j].matches("[A-Z]")) { + result.append(String.format("In row %s char is not in [A-Z] sequence\n\r", i + 1)); + } + } + } + return result.toString(); + } + + private String checkWidth(String actual, int width) { + StringBuilder result = new StringBuilder(); + String[] rows = actual.split("\n\r"); + for (int i = 0; i < rows.length - 1; i++) { + int actualWidth = rows[i].replace("|", "").split("").length; + if (actualWidth != width) { + result.append(String.format("In row %s width is %s, but %s is expected\n\r", + i + 1, + actualWidth, + width)); + } + } + return result.toString(); + } + + private static boolean strategyMatch(char charItem, String strategy) { + return (strategy.equals("even") && charItem % 2 == 0) || (strategy.equals("odd") && charItem % 2 != 0); + } +} \ No newline at end of file diff --git a/src/test/java/homework_2/traffic_light/TrafficLightTest.java b/src/test/java/homework_2/traffic_light/TrafficLightTest.java new file mode 100644 index 00000000..03e74d3e --- /dev/null +++ b/src/test/java/homework_2/traffic_light/TrafficLightTest.java @@ -0,0 +1,80 @@ +package homework_2.traffic_light; + +import base.UnitBase; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class TrafficLightTest extends UnitBase{ + + private static String welcomeMessage = "Enter seconds value (int) from 0 - 86399: "; + private static String errorMessage1 = "Only 1 non-negative integer is allowed as passed parameter"; + private static String errorMessage2 = "Day is over!"; + + @ParameterizedTest + @MethodSource("testCases") + void test_MainCases(final String input, final String expected) { + setInput(input); + new TrafficLight().run(); + printOut(); + removeFromOutput(welcomeMessage); + String actual = getOutput(); + assertTrue(actual.contains(expected)); + } + + static Stream testCases() { + return Stream.of( + Arguments.of("22", getTrafficLightOutput(22)), + Arguments.of("40", getTrafficLightOutput(40)), + Arguments.of("0", getTrafficLightOutput(0)), + Arguments.of("60", getTrafficLightOutput(60)), + Arguments.of("41", getTrafficLightOutput(41)), + Arguments.of("86399", getTrafficLightOutput(86399)), + Arguments.of("005", getTrafficLightOutput(5)) + ); + } + + @ParameterizedTest + @MethodSource("Negative_NonDigit_Values") + void test_Negative_NonDigit_Values(final String input, final String expected) { + setInput(input); + new TrafficLight().run(); + printOut(); + removeFromOutput(welcomeMessage); + String actual = getOutput(); + assertTrue(actual.contains(expected)); + } + + static Stream Negative_NonDigit_Values() { + return Stream.of( + Arguments.of("test", errorMessage1), + Arguments.of("5878 545454 464", errorMessage1), + Arguments.of("hello", errorMessage1), + Arguments.of("-5", errorMessage1), + Arguments.of("-100000000", errorMessage1), + Arguments.of("", errorMessage1), + Arguments.of(" ", errorMessage1), + Arguments.of("2147483648", errorMessage1), + Arguments.of("87399", errorMessage2) + ); + } + + private static String getTrafficLightOutput(int inputInt) { + int SecondsInLastMinute = inputInt % 60; + String currentColorText; + if (SecondsInLastMinute < 35) { + currentColorText = "green"; + } else if (SecondsInLastMinute < 40) { + currentColorText = "yellow"; + } else if (SecondsInLastMinute < 55) { + currentColorText = "red"; + } else { + currentColorText = "yellow"; + } + return currentColorText.toUpperCase(); + } +} \ No newline at end of file diff --git a/src/test/java/homework_3/ImmutableTaskTest.java b/src/test/java/homework_3/ImmutableTaskTest.java new file mode 100644 index 00000000..6e610d12 --- /dev/null +++ b/src/test/java/homework_3/ImmutableTaskTest.java @@ -0,0 +1,42 @@ +package homework_3; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class ImmutableTaskTest { + + @Test + void test_NameIsChanged() { + + ImmutableTask task = new ImmutableTask("Immutable class"); + + ImmutableTask taskAfterChangeName = task.changeName("new name here!!!"); + assertEquals(taskAfterChangeName.getName(), "new name here!!!"); + + } + + @Test + void test_ReturnsNewObjectAfterChangeName() { + + ImmutableTask task = new ImmutableTask("Immutable class"); + + ImmutableTask taskAfterChangeName = task.changeName("new name here!!!"); + assertNotEquals(task, taskAfterChangeName); + + } + + @Test + void test_changeAdditionalInfoField() { + + String[] info = {"homework_3", "EPAM june 2021"}; + ImmutableTask task = new ImmutableTask("Immutable class", + "Implement immutable class", + 50, + info); + + String[] newArray = task.getAdditionalInfo(); + newArray[1] = "EPAM Java core 06/2021"; + assertEquals(task.getAdditionalInfo()[1], info[1]); + + } +} \ No newline at end of file diff --git a/src/test/java/homework_4/custom_annotation/CustomAnnotationTest.java b/src/test/java/homework_4/custom_annotation/CustomAnnotationTest.java new file mode 100644 index 00000000..aad2ec33 --- /dev/null +++ b/src/test/java/homework_4/custom_annotation/CustomAnnotationTest.java @@ -0,0 +1,31 @@ +package homework_4.custom_annotation; + +import base.UnitBase; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CustomAnnotationTest extends UnitBase { + + private final Customer customer = new Customer(); + + @Test + void test_ToStringReturnsNewFieldsName() { + + String name = "ООО \"Ромашка\""; + String fullName = "Общество с ограниченной ответственностью \"Ромашка\""; + + customer.setName(name); + customer.setFullName(fullName); + + System.out.println(customer); + + String expected = String.format("Customer{Наименование='%s', Полное имя='%s', address='null', Номер телефона='null'}", + name, + fullName); + + String actual = getOutput(); + + assertEquals(actual, expected); + } +} diff --git a/src/test/java/homework_4/custom_file_reader/CustomFileReaderTest.java b/src/test/java/homework_4/custom_file_reader/CustomFileReaderTest.java new file mode 100644 index 00000000..875651e4 --- /dev/null +++ b/src/test/java/homework_4/custom_file_reader/CustomFileReaderTest.java @@ -0,0 +1,55 @@ +package homework_4.custom_file_reader; + +import base.UnitBase; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class CustomFileReaderTest extends UnitBase { + + private final CustomFileReader reader = new CustomFileReader(); + + @Test + void test_method1() { + new MethodTestTemplate() { + @Override + protected void run() { + reader.run1(); + } + }.process(); + } + + @Test + void test_method2() { + new MethodTestTemplate() { + @Override + protected void run() { + reader.run2(); + } + }.process(); + } + + @Test + void test_method3() { + new MethodTestTemplate() { + @Override + protected void run() { + reader.run3(); + } + }.process(); + } + + public abstract class MethodTestTemplate { + + protected abstract void run(); + + protected void process() { + run(); + String resultString = getOutput(); + assertTrue(!resultString.contains(".") && !resultString.contains(","), + "Result contains \".\" or \",\" or both:" + System.lineSeparator() + resultString); + } + + } + +} diff --git a/src/test/java/homework_4/singleton/SingletonTest.java b/src/test/java/homework_4/singleton/SingletonTest.java new file mode 100644 index 00000000..84d299ae --- /dev/null +++ b/src/test/java/homework_4/singleton/SingletonTest.java @@ -0,0 +1,17 @@ +package homework_4.singleton; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +public class SingletonTest{ + + @Test + void test_OnlyOneInstance() { + //Class singleton + assertEquals(DatabaseConnection.getInstance("superAdmin"), DatabaseConnection.getInstance("admin")); + //Enum singleton + assertEquals(EnumDatabaseConnection.INSTANCE.getInstance(), EnumDatabaseConnection.INSTANCE.getInstance()); + } +} diff --git a/src/test/java/homework_5/custom_regex_matcher/CustomRegexMatcherTest.java b/src/test/java/homework_5/custom_regex_matcher/CustomRegexMatcherTest.java new file mode 100644 index 00000000..fa7dd0cd --- /dev/null +++ b/src/test/java/homework_5/custom_regex_matcher/CustomRegexMatcherTest.java @@ -0,0 +1,41 @@ +package homework_5.custom_regex_matcher; + +import base.UnitBase; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class PowerOfNumberTest extends UnitBase { + + private static String welcomeMessage = "Enter your email: "; + + @ParameterizedTest + @MethodSource("testCases") + void test_MainCases(final String input, final String expected) { + setInput(input); + new CustomRegexMatcher().readFromConsole(); + removeFromOutput(welcomeMessage); + printOut(); + String actual = getOutput(); + assertEquals(expected, actual); + } + + static Stream testCases() { + return Stream.of( + Arguments.of("abelyaevskov@gmail.com", "true"), + Arguments.of("abelyaevskov@narod.biz.ru", "true"), + Arguments.of("abelyaevskov", "false"), + Arguments.of("abelyaevskov@", "false"), + Arguments.of("0", "false"), + Arguments.of(" ", "false"), + Arguments.of("123abelyaevskov@gmail.com", "false"), + Arguments.of("abelyaevskov@123gmail.com", "false") + ); + } + + +} \ No newline at end of file diff --git a/src/test/java/homework_5/power_of_number/PowerOfNumberTest.java b/src/test/java/homework_5/power_of_number/PowerOfNumberTest.java new file mode 100644 index 00000000..1454e5eb --- /dev/null +++ b/src/test/java/homework_5/power_of_number/PowerOfNumberTest.java @@ -0,0 +1,82 @@ +package homework_5.power_of_number; + +import base.UnitBase; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.math.BigInteger; +import java.util.Random; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class PowerOfNumberTest extends UnitBase { + + private static String welcomeMessage = "Enter 2 positive integer numbers: "; + private static String errorMessage = "Only 2 non-negative integers are allowed"; + + @ParameterizedTest + @MethodSource("testCases") + void test_MainCases(final String input, final String expected) { + setInput(input); + new PowerOfNumber().run(); + removeFromOutput(welcomeMessage); + printOut(); + String actual = getOutput(); + assertEquals(expected, actual); + } + + static Stream testCases() { + final Stream.Builder testCases = Stream.builder(); + + Random randomNumber = new Random(); + Random randomPower = new Random(); + + int numberDistribution = 150; + int powerDistribution = 101; + + for (int i = 0; i < 100; i++) { + int number = randomNumber.nextInt(numberDistribution); + int power = randomPower.nextInt(powerDistribution); + BigInteger powerOfNumber = BigInteger.valueOf(number).pow(power); + String input = String.format("%s %s", number, power); + String expectedOutput = String.format("Power %s of number %s is: %s", power, number, powerOfNumber); + testCases.add(Arguments.of(input, expectedOutput)); + } + + String input_power0 = String.format("%s %s", 15, 0); + String expectedOutput_power0 = String.format("Power %s of number %s is: %s", 0, 15, 1); + testCases.add(Arguments.of(input_power0, expectedOutput_power0)); + + String input_number0 = String.format("%s %s", 0, 99); + String expectedOutput_number0 = String.format("Power %s of number %s is: %s", 99, 0, 0); + testCases.add(Arguments.of(input_number0, expectedOutput_number0)); + + return testCases.build(); + } + + @ParameterizedTest + @MethodSource("wrongInput") + void test_wrongInput(final String input, final String expected) { + setInput(input); + new PowerOfNumber().run(); + removeFromOutput(welcomeMessage); + printOut(); + String actual = getOutput(); + assertTrue(actual.contains(expected)); + } + + static Stream wrongInput() { + return Stream.of( + Arguments.of("test", errorMessage), + Arguments.of("-5 0", errorMessage), + Arguments.of("5 -99", errorMessage), + Arguments.of("", errorMessage), + Arguments.of("0", errorMessage), + Arguments.of(" ", errorMessage) + ); + } + +} \ No newline at end of file