diff --git a/README.md b/README.md index 5d686e9f..6b62de1b 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,25 @@ # Java Core June 2021 -## *Nikolaev Artem* +### Andropov Vsevolod | 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](./src/main/java/homework_1/Main.java)
[Tests](./src/test/java/homework_1/MainTest.java) | The app that reads input arguments and prints them, until "error" argument | +HW2.1 | [Traffic Light](./src/main/java/homework_2/traffic_light/)
[Tests](./src/test/java/homework_2/traffic_light/TrafficLightTest.java) | The app that switching colors on different number value (input from keyboard) | +HW2.2 | [Pyramid Printer](./src/main/java/homework_2/pyramid_printer/)
[Tests](./src/test/java/homework_2/pyramid_printer/PyramidPrinterTest.java) | Printing 'x' Pyramid with the input parameter as Pyramid height | +HW2.3 | [Random Chars Table](./src/main/java/homework_2/random_chars_table/)
[Tests](./src/test/java/homework_2/random_chars_table/RandomCharsTableTest.java) | The app that creates 2-dimensional array/matrix made of random Character values (from A=65 to Z=90), dimensions set by input from keyboard. Then generating resulting string with even/odd parameter depends on input | +HW3 | [Immutable Class](./src/main/java/homework_3/ImmutableClass.java) | Create Immutable class: several fields, including reference type; several constructors; method returning a new object. | +HW4.1 | [Custom File Reader](./src/main/java/homework_4/custom_file_reader/)
[Tests](./src/test/java/homework_4/custom_file_reader/CustomFileReaderTest.java) | App reading data from file and prints to console. Text file path: main/resources/custom_file_reader/. Reading file in 4 different ways (one of them using NIO) executable with methods: run1(), run2(), run3(), run4() | +HW4.2 | [Singleton](./src/main/java/homework_4/singleton/)
[Tests](./src/test/java/homework_4/singleton/SingletonMenuTest.java) | Singleton App: private constructor and public method getInstance() | +HW4.3 | [Custom Annotation](./src/main/java/homework_4/custom_annotation/)
[Tests](./src/test/java/homework_4/custom_annotation/ResourcesPathTest.java) | Custom annotation class. | +HW5.1 | [Power Of Number](./src/main/java/homework_5/power_of_number/)
[Tests](./src/test/java/homework_5/power_of_number/PowerOfNumberTest.java) | Power of number recursion using App. Reads 2 non-negative integer numbers from console and prints out the result of exponentiation. Only for positive integer numbers. On any problem output message will be gotten: "Only 2 non-negative integers are allowed" | +HW5.2 | [Custom Regex Matcher](./src/main/java/homework_5/custom_regex_matcher/)
[Tests](./src/test/java/homework_5/custom_regex_matcher/CustomRegexMatcherTest.java) | App reads input from keyboard and print true or false for the input matching to the hardcoded regex format. | +HW6 | [MapProblemsGenerator](./src/main/java/homework_6/map_problems_collision_generator/) | App which has:
1) Class creating 100% HashMap collisions
2) Mutable class with overridden HashCode/Equals. When put MutableClass object into HashMap as key - can't retrieve it (equals works correctly) | +HW7 | [Kitten to Cat](./src/main/java/homework_7/kitten_to_cat/)
[Tests](./src/test/java/homework_7/kitten_to_cat/KittenToCatTest.java) | App using Functional Interface KittenToCatFunction with abstract method grow(). Realization in Main class through lambda function | +Course project | [Sea Battle](./src/main/java/course_project/) | Sea Battle console game | -[Link to markdown giude](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) +
+ +___ + +[codingbat profile](https://codingbat.com/done?user=devngrow@gmail.com&tag=1205090974) `done` diff --git a/build.gradle b/build.gradle index b91dc843..bbc25319 100644 --- a/build.gradle +++ b/build.gradle @@ -10,8 +10,16 @@ repositories { } dependencies { - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' + implementation 'org.junit.jupiter:junit-jupiter:5.7.2' + implementation 'org.jetbrains:annotations:22.0.0' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2' + + // lombok + compileOnly 'org.projectlombok:lombok:1.18.20' + annotationProcessor 'org.projectlombok:lombok:1.18.20' + testCompileOnly 'org.projectlombok:lombok:1.18.20' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.20' } test { diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/course_project/Main.java b/src/main/java/course_project/Main.java new file mode 100644 index 00000000..f96f25cb --- /dev/null +++ b/src/main/java/course_project/Main.java @@ -0,0 +1,11 @@ +package course_project; + +import course_project.services.SeaBattle; + +public class Main { + + public static void main(String[] args) { + SeaBattle.getInstance().run(); + } + +} diff --git a/src/main/java/course_project/gamestuff/field/Battlefield.java b/src/main/java/course_project/gamestuff/field/Battlefield.java new file mode 100644 index 00000000..58e73316 --- /dev/null +++ b/src/main/java/course_project/gamestuff/field/Battlefield.java @@ -0,0 +1,112 @@ +package course_project.gamestuff.field; + +import course_project.gamestuff.player.Player; +import course_project.gamestuff.ships.*; + +import java.util.Collection; +import java.util.LinkedList; + +import static course_project.services.conversation.DialogueMenu.*; +import static course_project.utils.AroundDestroyedShipMarker.*; +import static course_project.utils.RandomCellPositionGenerator.generateRandomForCell; +import static course_project.utils.RandomShipDirectionGenerator.generateRandomDirection; +import static course_project.utils.ShipOnBattlefieldPlacer.*; + +/** + * Battlefield is Field for the Player(owner) of this object. + */ +public class Battlefield extends Field { + + private final Collection availableShips; + + public Battlefield() { + super(); + this.availableShips = new LinkedList<>(); + initAvailableShips(); + } + + private void initAvailableShips() { + availableShips.add(new ExtraLargeShip()); + availableShips.add(new LargeShip()); + availableShips.add(new LargeShip()); + availableShips.add(new MiddleShip()); + availableShips.add(new MiddleShip()); + availableShips.add(new MiddleShip()); + availableShips.add(new SmallShip()); + availableShips.add(new SmallShip()); + availableShips.add(new SmallShip()); + availableShips.add(new SmallShip()); + } + + public Collection getAvailableShips() { + return this.availableShips; + } + + public boolean addShipOnBattlefield(Ship ship, Cell toCell, boolean isHorizontal) { + if (isEnoughSpaceToPlaceShip(toCell, ship.getSize(), isHorizontal)) { + return isHorizontal ? + addRowOfCells(this, toCell, ship) : + addColumnOfCells(this, toCell, ship); + } + return false; + } + + // onDestroy + public void availableShipsDecrease(Ship ship) { + this.availableShips.remove(ship); + } + + public boolean hasAvailableShips() { + return countOfAvailableShips() > 0; + } + + public int countOfAvailableShips() { + return this.availableShips.size(); + } + + public static void addShipsManually(Player currentPlayer) { + printPlayerShipPlacingHelp(); + currentPlayer.getField().getAvailableShips().forEach(ship -> { + currentPlayer.getField().printField(); + Cell toPos; + boolean isHorizontal = true; + do { + printSetPositionMessage(ship.getName(), ship.getSize()); + String[] pos = getShipPlacingInput().split(" "); + int x = Integer.parseInt(pos[0].substring(1)) - 1; + int y = Integer.parseInt(String.valueOf(pos[0].charAt(0) - LOWERCASE_A)); + toPos = currentPlayer.getField().getCellByPosition(x, y); + if (pos.length == 2) { + isHorizontal = "h".equals(pos[1]); + } + } while (!currentPlayer.getField().addShipOnBattlefield(ship, toPos, isHorizontal)); + } + ); + } + + public static void addShipsAuto(Player currentPlayer) { + currentPlayer.getField().getAvailableShips().forEach(ship -> { + Cell toPos; + boolean isHorizontal; + do { + toPos = currentPlayer.getField().getCellByPosition(generateRandomForCell(), + generateRandomForCell()); + isHorizontal = generateRandomDirection(); + } while (!currentPlayer.getField().addShipOnBattlefield(ship, toPos, isHorizontal)); + } + ); + } + + public void setAroundShipCellsAsHit(Player currentPlayer, Ship ship) { + if (ship.getSize() == 1) { + fillAroundSmallShip(currentPlayer, ship); + } else { + if (ship.isHorizontal()) { + fillAroundHorizontalShip(currentPlayer, ship); + } else { + fillAroundVerticalShip(currentPlayer, ship); + } + } + } + +} diff --git a/src/main/java/course_project/gamestuff/field/Cell.java b/src/main/java/course_project/gamestuff/field/Cell.java new file mode 100644 index 00000000..31012973 --- /dev/null +++ b/src/main/java/course_project/gamestuff/field/Cell.java @@ -0,0 +1,47 @@ +package course_project.gamestuff.field; + +import course_project.gamestuff.ships.Ship; + +public class Cell { + + private final int x; + private final int y; + private Ship ref; + private boolean hit; // stores state of cell: if motion to this cell was made + + public Cell(int x, int y) { + this.x = x; + this.y = y; + this.ref = null; + this.hit = false; + } + + public boolean isHit() { + return this.hit; + } + + public void setHit(boolean hit) { + this.hit = hit; + } + + public Ship isShipPlacedAtCell() { + return this.ref == null ? null : ref; + } + + public void placeShipOnCell(Ship ship) { + this.ref = ship; + } + + public int getX() { + return this.x; + } + + public int getY() { + return this.y; + } + + public Ship getRef() { + return this.ref; + } + +} diff --git a/src/main/java/course_project/gamestuff/field/Field.java b/src/main/java/course_project/gamestuff/field/Field.java new file mode 100644 index 00000000..4b5384a5 --- /dev/null +++ b/src/main/java/course_project/gamestuff/field/Field.java @@ -0,0 +1,140 @@ +package course_project.gamestuff.field; + +import course_project.gamestuff.player.Player; + +import static homework_2.Colors.*; + +public abstract class Field { + + public static final int FIELD_SIZE = 10; + public static final int LOWERCASE_A = 'a'; + private static final String WATER = BLUE_BG + " " + ANSI_RESET; + private static final String DESTROYED = ANSI_RED + "†" + ANSI_RESET; + private static final String HIT = ANSI_RED + "X" + ANSI_RESET; + private static final String MISS = ANSI_YELLOW + "O" + ANSI_RESET; + private static final String SHIP = ANSI_GREEN + "¤" + ANSI_RESET; + private static final char FIRST_SYMBOL_TOP_LINE = 'A'; + private static final String TOP_LINE; + private static final String CELL_FORMAT = "%s "; + private static final String ROW_NUMBER_FORMAT = "[%-2d]"; + + private final Cell[][] cells; + + protected Field() { + this.cells = new Cell[FIELD_SIZE][FIELD_SIZE]; + fillCellsWithIndexes(); + } + + static { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = FIRST_SYMBOL_TOP_LINE; i < FIRST_SYMBOL_TOP_LINE + FIELD_SIZE; i++) { + stringBuilder + .append((char) i) + .append(" "); + } + TOP_LINE = stringBuilder.toString().trim(); + } + + private void fillCellsWithIndexes() { + for (int i = 0; i < FIELD_SIZE; i++) { + for (int j = 0; j < FIELD_SIZE; j++) { + cells[i][j] = new Cell(i, j); + } + } + } + + public void printField() { + StringBuilder oneField = new StringBuilder(); + oneField + .append("\t") + .append(TOP_LINE) + .append("\n"); + for (int i = 0; i < FIELD_SIZE; i++) { + oneField.append(String.format(ROW_NUMBER_FORMAT, i + 1)); + for (int j = 0; j < FIELD_SIZE; j++) { + Cell currentCell = getCellByPosition(i, j); + String toPrint = WATER; + if (!isCellEmpty(currentCell)) { + toPrint = SHIP; + } + oneField.append(String.format(CELL_FORMAT, toPrint)); + } + oneField.append("\n"); + } + System.out.println(oneField); + } + + public void printBothFields(Player currentPlayer, Player enemy) { + StringBuilder bothFields = new StringBuilder(); + bothFields + .append("\t") + .append(TOP_LINE) + .append("\t\t\t\t") + .append(TOP_LINE) + .append("\n"); + for (int i = 0; i < FIELD_SIZE; i++) { + bothFields.append(String.format(ROW_NUMBER_FORMAT, i + 1)); + for (int j = 0; j < FIELD_SIZE; j++) { + Cell currentPlayerCell = currentPlayer.getField().getCellByPosition(i, j); + if (currentPlayerCell.isHit()) { + bothFields + .append(getCellStateAsString(currentPlayer, currentPlayerCell)); + } else { + if (currentPlayer.getField().isCellEmpty(currentPlayerCell)) { + bothFields + .append(String.format(CELL_FORMAT, WATER)); + } else { + bothFields + .append(String.format(CELL_FORMAT, SHIP)); + } + } + } + bothFields + .append("\t\t") + .append(String.format(ROW_NUMBER_FORMAT, i + 1)); + for (int j = 0; j < FIELD_SIZE; j++) { + Cell currentEnemyCell = enemy.getField().getCellByPosition(i, j); + if (currentEnemyCell.isHit()) { + bothFields + .append(getCellStateAsString(enemy, currentEnemyCell)); + } else { + bothFields + .append(String.format(CELL_FORMAT, WATER)); + } + } + bothFields.append("\n"); + } + System.out.println(bothFields); + } + + private String getCellStateAsString(Player currentPlayer, Cell playersCell) { + if (currentPlayer.getField().getHit(playersCell)) { + if (playersCell.getRef().isShipDestroyed()) { + return String.format(CELL_FORMAT, DESTROYED); + } else { + return String.format(CELL_FORMAT, HIT); + } + } + return String.format(CELL_FORMAT, MISS); + } + + public Cell getCellByPosition(int x, int y) { + for (Cell[] cellRow : this.cells) { + for (Cell cellCol : cellRow) { + if (cellCol.getX() == x && cellCol.getY() == y) { + return cellCol; + } + } + } + return null; + } + + public boolean isCellEmpty(Cell currentCell) { + return currentCell.isShipPlacedAtCell() == null; + } + + public boolean getHit(Cell toCell) { + return !isCellEmpty(cells[toCell.getX()][toCell.getY()]); + } + +} diff --git a/src/main/java/course_project/gamestuff/player/Player.java b/src/main/java/course_project/gamestuff/player/Player.java new file mode 100644 index 00000000..476bc089 --- /dev/null +++ b/src/main/java/course_project/gamestuff/player/Player.java @@ -0,0 +1,29 @@ +package course_project.gamestuff.player; + +import course_project.gamestuff.field.Battlefield; + +public class Player { + + private final boolean computer; + private final String name; + private final Battlefield battlefield; + + public Player(String name, boolean isComputer) { + this.computer = isComputer; + this.name = name; + this.battlefield = new Battlefield(); + } + + public boolean isComputer() { + return this.computer; + } + + public String getName() { + return this.name; + } + + public Battlefield getField() { + return this.battlefield; + } + +} diff --git a/src/main/java/course_project/gamestuff/ships/ExtraLargeShip.java b/src/main/java/course_project/gamestuff/ships/ExtraLargeShip.java new file mode 100644 index 00000000..84899159 --- /dev/null +++ b/src/main/java/course_project/gamestuff/ships/ExtraLargeShip.java @@ -0,0 +1,12 @@ +package course_project.gamestuff.ships; + +public final class ExtraLargeShip extends Ship { + + private static final int SIZE = 4; + private static final String SHIP_NAME = "Battleship"; + + public ExtraLargeShip() { + super(SIZE, SHIP_NAME); + } + +} diff --git a/src/main/java/course_project/gamestuff/ships/LargeShip.java b/src/main/java/course_project/gamestuff/ships/LargeShip.java new file mode 100644 index 00000000..9e7fe62f --- /dev/null +++ b/src/main/java/course_project/gamestuff/ships/LargeShip.java @@ -0,0 +1,12 @@ +package course_project.gamestuff.ships; + +public final class LargeShip extends Ship { + + private static final int SIZE = 3; + private static final String SHIP_NAME = "Destroyer"; + + public LargeShip() { + super(SIZE, SHIP_NAME); + } + +} \ No newline at end of file diff --git a/src/main/java/course_project/gamestuff/ships/MiddleShip.java b/src/main/java/course_project/gamestuff/ships/MiddleShip.java new file mode 100644 index 00000000..f6494ccb --- /dev/null +++ b/src/main/java/course_project/gamestuff/ships/MiddleShip.java @@ -0,0 +1,12 @@ +package course_project.gamestuff.ships; + +public final class MiddleShip extends Ship { + + private static final int SIZE = 2; + private static final String SHIP_NAME = "Submarine"; + + public MiddleShip() { + super(SIZE, SHIP_NAME); + } + +} diff --git a/src/main/java/course_project/gamestuff/ships/Ship.java b/src/main/java/course_project/gamestuff/ships/Ship.java new file mode 100644 index 00000000..89ab0948 --- /dev/null +++ b/src/main/java/course_project/gamestuff/ships/Ship.java @@ -0,0 +1,52 @@ +package course_project.gamestuff.ships; + +import course_project.gamestuff.field.Cell; + +public abstract class Ship { + + private final int size; + private final String name; + private int hitCount; + private Cell startCell; + private boolean direction = true; // true - horizontal, false - vertical + + protected Ship(int size, String shipName) { + this.size = size; + this.name = shipName; + this.hitCount = 0; + this.startCell = null; + } + + public boolean isHorizontal() { + return this.direction; + } + + public void setVertical() { + this.direction = false; + } + + public Cell getStartCell() { + return this.startCell; + } + + public void setStartCell(Cell cell) { + this.startCell = cell; + } + + public int getSize() { + return this.size; + } + + public String getName() { + return this.name; + } + + public boolean isShipDestroyed() { + return this.hitCount == this.size; + } + + public void hitCountIncrease() { + this.hitCount++; + } + +} diff --git a/src/main/java/course_project/gamestuff/ships/SmallShip.java b/src/main/java/course_project/gamestuff/ships/SmallShip.java new file mode 100644 index 00000000..8d34bd1c --- /dev/null +++ b/src/main/java/course_project/gamestuff/ships/SmallShip.java @@ -0,0 +1,12 @@ +package course_project.gamestuff.ships; + +public final class SmallShip extends Ship { + + private static final int SIZE = 1; + private static final String SHIP_NAME = "Patrol Boat"; + + public SmallShip() { + super(SIZE, SHIP_NAME); + } + +} diff --git a/src/main/java/course_project/services/SeaBattle.java b/src/main/java/course_project/services/SeaBattle.java new file mode 100644 index 00000000..3718b98d --- /dev/null +++ b/src/main/java/course_project/services/SeaBattle.java @@ -0,0 +1,26 @@ +package course_project.services; + +import course_project.services.conversation.DialogueMenu; + +/** + * Start of SeaBattle game; + */ +public final class SeaBattle { + + private SeaBattle() { + } + + private static class SeaBattleHelper { + private static final SeaBattle INSTANCE = new SeaBattle(); + } + + public static SeaBattle getInstance() { + return SeaBattleHelper.INSTANCE; + } + + public void run() { + DialogueMenu.printGreetings(); + DialogueMenu.printMainMenu(); + } + +} diff --git a/src/main/java/course_project/services/conversation/DialogueMenu.java b/src/main/java/course_project/services/conversation/DialogueMenu.java new file mode 100644 index 00000000..c37cdae2 --- /dev/null +++ b/src/main/java/course_project/services/conversation/DialogueMenu.java @@ -0,0 +1,258 @@ +package course_project.services.conversation; + +import course_project.gamestuff.field.Field; +import course_project.gamestuff.player.Player; +import course_project.gamestuff.ships.Ship; +import course_project.services.logic.Game; +import homework_4.custom_file_reader.CustomFileReader; + +import java.io.PrintStream; +import java.util.Scanner; + +import static course_project.gamestuff.field.Battlefield.addShipsAuto; +import static course_project.gamestuff.field.Battlefield.addShipsManually; +import static course_project.gamestuff.field.Field.FIELD_SIZE; +import static course_project.gamestuff.field.Field.LOWERCASE_A; + +/** + * Ultimate class for communication with user over the app; + */ +@SuppressWarnings("java:S106") // remove showing System.out warning +public class DialogueMenu { + + private static final String INCORRECT_INPUT_MESSAGE = "Please, input correct variant"; + private static final String FILLED_FIELD_MESSAGE = "Done! Battlefield is filled ;)"; + private static final String WELCOME_MESSAGE = "Welcome to Sea Battle Console v0.1!"; + private static final String QUIT = "quit"; + private static final String FIRST_SYMBOL_POSITION_REGEX; + private static final String DIRECTION_REGEX = "^[v|h]$"; + private static final String NAME_REGEX = "^[a-zA-Z]{2,}$"; + private static final Scanner scanner = new Scanner(System.in); + private static final PrintStream out = System.out; + + static { + FIRST_SYMBOL_POSITION_REGEX = "^[" + Field.LOWERCASE_A + "-" + (char) (LOWERCASE_A + FIELD_SIZE - 1) + "]$"; + } + + private static Player player; + private static Player enemy; + + private DialogueMenu() { + } + + public static void printGreetings() { + out.println(WELCOME_MESSAGE); + } + + public static void printMainMenu() { + out.print( + "[1] Start game Human vs Computer\n" + + "[2] Start game Human vs Human\n" + + "[3] Start game Computer vs Computer\n" + + "[4] Print rules\n" + + "[5] Quit the game\n" + ); + String input = getInput(); + switch (input) { + case "1": + startHumanVSComputer(); + break; + case "2": + startHumanVSHuman(); + break; + case "3": + startComputerVSComputer(); + break; + case "4": + printRules(); + printMainMenu(); + break; + case "5": + terminate(); + break; + default: + out.println(INCORRECT_INPUT_MESSAGE); + printMainMenu(); + } + } + + private static void printRules() { + new CustomFileReader("./src/main/resources/sea_battle/", "rules.txt").run2(); + } + + private static void startComputerVSComputer() { + player = new Player("CPU0", true); + enemy = new Player("CPU1", true); + addShipsAuto(player); + addShipsAuto(enemy); + new Game(player, enemy).start(); + } + + + private static void startHumanVSHuman() { + player = new Player(getInputName(), false); + enemy = new Player(getInputName(), false); + printPlayerMenu(player); + waitForSeconds(2); + printEmptyLines(); + printInvitePlayerMessage(enemy); + waitForSeconds(1); + printPlayerMenu(enemy); + waitForSeconds(1); + new Game(player, enemy).start(); + } + + @SuppressWarnings("java:S2142") + public static void waitForSeconds(int seconds) { + try { + Thread.sleep(seconds * 1000L); + } catch (InterruptedException ex) { + ex.printStackTrace(); + } + } + + private static void startHumanVSComputer() { + player = new Player(getInputName(), false); + enemy = new Player("Mozilla", true); + printPlayerMenu(player); + addShipsAuto(enemy); + new Game(player, enemy).start(); + } + + private static String getInputName() { + out.println("My name is SeaBattle, and yours?"); + while (true) { + String name = scanner.nextLine().trim(); + if (name.matches(NAME_REGEX)) { + return name; + } else { + out.println("Ha-ha, it's impossible to have such name!\n" + + "It should consists of at least 2 latin symbols(only), ok?"); + } + } + } + + public static void printInvitePlayerMessage(Player player) { + out.println(player.getName() + "'s turn!"); + } + + private static void printPlayerMenu(Player currentPlayer) { + out.print("Menu for " + currentPlayer.getName() + ":" + "\n" + + "[1] Add ships on the field manually\n" + + "[2] Auto adding ships\n"); + String input = getInput(); + switch (input) { + case "1": + addShipsManually(currentPlayer); + currentPlayer.getField().printField(); + out.println(FILLED_FIELD_MESSAGE + "\n"); + break; + case "2": + addShipsAuto(currentPlayer); + currentPlayer.getField().printField(); + out.println(FILLED_FIELD_MESSAGE + "\n"); + break; + default: + out.println(INCORRECT_INPUT_MESSAGE); + printPlayerMenu(currentPlayer); + } + } + + public static String getPlayerMotionInput() { + while (true) { + String input = getInput(); + if (QUIT.equals(input)) { + terminate(); + } else if (isPositionValid(input)) { + return input; + } else { + out.println(INCORRECT_INPUT_MESSAGE); + } + } + } + + public static void printPlayerMotionHelp() { + out.println("Input position you want to attack in format: 'a1' or 'b9'\n" + + "you can input 'quit' to exit the app anytime you want"); + } + + public static void printPlayerShipPlacingHelp() { + out.println("To place ship just input position from" + "'a1' to " + + ((char) (LOWERCASE_A + FIELD_SIZE - 1)) + FIELD_SIZE + + "(horizontal direction is default)" + + "\nIf you want to set ship vertically type e.g. 'a1 v' or horizontal 'b2 h'" + + "\nInput 'quit' to exit the game."); + } + + public static String getShipPlacingInput() { + while (true) { + String input = getInput(); + if (QUIT.equals(input)) { + terminate(); + } else { + String[] strings = input.split(" "); + if ((strings.length == 1 && isPositionValid(input)) || + (strings.length == 2 && isPositionValid(strings[0]) && strings[1].matches(DIRECTION_REGEX))) { + return input; + } else { + out.println(INCORRECT_INPUT_MESSAGE); + } + } + } + } + + private static boolean isPositionValid(String str) { + return String.valueOf(str.charAt(0)).matches(FIRST_SYMBOL_POSITION_REGEX) && + str.substring(1).matches("\\d+") && + Integer.parseInt(str.substring(1)) >= 1 && + Integer.parseInt(str.substring(1)) <= FIELD_SIZE; + } + + public static void printSetPositionMessage(String name, int size) { + out.print("Set position for " + name + " size of " + size + ": "); + } + + private static String getInput() { + return scanner.nextLine().trim().toLowerCase(); + } + + public static void printShipDestroyedMessage(String opponentsName, Ship ship) { + out.println("Nice! " + opponentsName + "'s " + ship.getName() + " is destroyed!"); + } + + public static void printShipHitMessage(String currentPlayerName, String opponentsName) { + out.println(currentPlayerName + " hit " + opponentsName + "'s ship!"); + } + + public static void printMiss() { + out.println("MISS!"); + } + + public static void printShipsLeftMessage(int countOfShipsLeft) { + out.println(countOfShipsLeft + " ships left"); + } + + public static void printSamePositionMessage() { + out.println("You've already hit at this position! Try another one: "); + } + + public static void printCongratulationsAndQuit(Player currentPlayer, Player opponent) { + out.println(currentPlayer.getName() + " WON THE GAME !!!" + + "\n" + opponent.getName() + " lose."); + terminate(); + } + + public static void printEmptyLines() { + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < FIELD_SIZE * 2; i++) { + stringBuilder.append("\n"); + } + out.println(stringBuilder); + } + + private static void terminate() { + scanner.close(); + Runtime.getRuntime().exit(0); // James Gosling approved! + } + +} diff --git a/src/main/java/course_project/services/logic/Game.java b/src/main/java/course_project/services/logic/Game.java new file mode 100644 index 00000000..550afb03 --- /dev/null +++ b/src/main/java/course_project/services/logic/Game.java @@ -0,0 +1,126 @@ +package course_project.services.logic; + +import course_project.gamestuff.field.Battlefield; +import course_project.gamestuff.field.Cell; +import course_project.gamestuff.player.Player; +import course_project.gamestuff.ships.Ship; + +import static course_project.services.conversation.DialogueMenu.*; +import static course_project.utils.RandomCellPositionGenerator.generateRandomForCell; + +/** + * Game logic provides control through the game process; + */ +public class Game { + + private final Player player1; + private final Player player2; + private Player currentPlayer; + + public Game(Player firstPlayer, Player secondPlayer) { + this.player1 = firstPlayer; + this.player2 = secondPlayer; + currentPlayer = getRandomPlayer(); + } + + private Player getRandomPlayer() { + return Math.random() <= 0.5 ? this.player1 : this.player2; + } + + // switch to opponents turn + private void swapPlayers() { + if (currentPlayer == player1) { + this.currentPlayer = this.player2; + } else { + this.currentPlayer = this.player1; + } + } + + private Player getEnemy() { + return currentPlayer == player1 ? player2 : player1; + } + + + public void start() { + while (currentPlayer.getField().hasAvailableShips() && getEnemy().getField().hasAvailableShips()) { + if (currentPlayer.isComputer() && getEnemy().isComputer()) { + computerMotion(currentPlayer); + } else if (!currentPlayer.isComputer() && getEnemy().isComputer()) { + humanMotion(currentPlayer); + } else if (currentPlayer.isComputer() && !getEnemy().isComputer()) { + computerMotion(currentPlayer); + } else { + waitForSeconds(2); + printEmptyLines(); + printInvitePlayerMessage(currentPlayer); + waitForSeconds(3); + printPlayerMotionHelp(); + humanMotion(currentPlayer); + } + } + } + + private void computerMotion(Player currentPlayer) { + Cell enemyCell = getEnemy().getField().getCellByPosition(generateRandomForCell(), generateRandomForCell()); + if (!enemyCell.isHit()) { + enemyCell.setHit(true); + Battlefield enemyBattlefield = getEnemy().getField(); + if (!enemyBattlefield.isCellEmpty(enemyCell)) { + Ship enemyShip = enemyCell.getRef(); + enemyShip.hitCountIncrease(); + if (enemyShip.isShipDestroyed()) { + enemyBattlefield.availableShipsDecrease(enemyShip); + enemyBattlefield.setAroundShipCellsAsHit(getEnemy(), enemyShip); + printShipDestroyedMessage(getEnemy().getName(), enemyShip); + if (!enemyBattlefield.hasAvailableShips()) { + printCongratulationsAndQuit(currentPlayer, getEnemy()); + } + } else { + printShipHitMessage(currentPlayer.getName(), getEnemy().getName()); + } + computerMotion(currentPlayer); + } else { + swapPlayers(); + } + } else { + computerMotion(currentPlayer); + } + } + + private void humanMotion(Player currentPlayer) { + currentPlayer.getField().printBothFields(currentPlayer, getEnemy()); + String pos = getPlayerMotionInput(); + Cell enemyCell = getEnemy().getField().getCellByPosition( + Integer.parseInt(pos.substring(1)) - 1, + Integer.parseInt(String.valueOf(pos.charAt(0) - 97)) + ); + if (enemyCell.isHit()) { + printSamePositionMessage(); + humanMotion(currentPlayer); + } else { + enemyCell.setHit(true); + Battlefield enemiesField = getEnemy().getField(); + if (!enemiesField.isCellEmpty(enemyCell)) { + Ship enemyShip = enemyCell.getRef(); + enemyShip.hitCountIncrease(); + if (enemyShip.isShipDestroyed()) { + enemiesField.setAroundShipCellsAsHit(getEnemy(), enemyShip); + enemiesField.availableShipsDecrease(enemyShip); + printShipDestroyedMessage(getEnemy().getName(), enemyShip); + if (!enemiesField.hasAvailableShips()) { + currentPlayer.getField().printBothFields(currentPlayer, getEnemy()); + printCongratulationsAndQuit(currentPlayer, getEnemy()); + } + printShipsLeftMessage(enemiesField.countOfAvailableShips()); + } else { + printShipHitMessage(currentPlayer.getName(), getEnemy().getName()); + } + humanMotion(currentPlayer); + } else { + printMiss(); + swapPlayers(); + } + } + } + +} diff --git a/src/main/java/course_project/utils/AroundDestroyedShipMarker.java b/src/main/java/course_project/utils/AroundDestroyedShipMarker.java new file mode 100644 index 00000000..14d36f65 --- /dev/null +++ b/src/main/java/course_project/utils/AroundDestroyedShipMarker.java @@ -0,0 +1,120 @@ +package course_project.utils; + +import course_project.gamestuff.field.Battlefield; +import course_project.gamestuff.field.Cell; +import course_project.gamestuff.field.Field; +import course_project.gamestuff.player.Player; +import course_project.gamestuff.ships.Ship; + +/** + * Functions to fill cells around the destroyed ship. + */ +public final class AroundDestroyedShipMarker { + + private AroundDestroyedShipMarker() {} + + public static void fillAroundSmallShip(Player currentPlayer, Ship ship) { + Cell shipCell = currentPlayer.getField().getCellByPosition( + ship.getStartCell().getX(), + ship.getStartCell().getY() + ); + Battlefield battlefield = currentPlayer.getField(); + markAboveAsHitCell(battlefield, shipCell); + markBelowAsHitCell(battlefield, shipCell); + markRightAsHitCell(battlefield, shipCell); + markLeftAsHitCell(battlefield, shipCell); + markDiagonalRightBelowAsHitCell(battlefield, shipCell); + markDiagonalLeftBelowAsHitCell(battlefield, shipCell); + markDiagonalRightAboveAsHitCell(battlefield, shipCell); + markDiagonalLeftAboveAsHitCell(battlefield, shipCell); + } + + public static void fillAroundVerticalShip(Player currentPlayer, Ship ship) { + int x = ship.getStartCell().getX(); + int y = ship.getStartCell().getY(); + Battlefield battlefield = currentPlayer.getField(); + for (int i = 0; i < ship.getSize(); i++) { + Cell currentCell = battlefield.getCellByPosition(x + i, y); + if (i == 0) { + markAboveAsHitCell(battlefield, currentCell); + markDiagonalLeftAboveAsHitCell(battlefield, currentCell); + markDiagonalRightAboveAsHitCell(battlefield, currentCell); + } else if (i == ship.getSize() - 1) { + markDiagonalLeftBelowAsHitCell(battlefield, currentCell); + markDiagonalRightBelowAsHitCell(battlefield, currentCell); + markBelowAsHitCell(battlefield, currentCell); + } + markLeftAsHitCell(battlefield, currentCell); + markRightAsHitCell(battlefield, currentCell); + } + } + + public static void fillAroundHorizontalShip(Player currentPlayer, Ship ship) { + int x = ship.getStartCell().getX(); + int y = ship.getStartCell().getY(); + Battlefield battlefield = currentPlayer.getField(); + for (int i = 0; i < ship.getSize(); i++) { + Cell currentCell = currentPlayer.getField().getCellByPosition(x, y + i); + if (i == 0) { + markDiagonalLeftAboveAsHitCell(battlefield, currentCell); + markLeftAsHitCell(battlefield, currentCell); + markDiagonalLeftBelowAsHitCell(battlefield, currentCell); + } else if (i == ship.getSize() - 1) { + markDiagonalRightAboveAsHitCell(battlefield, currentCell); + markRightAsHitCell(battlefield, currentCell); + markDiagonalRightBelowAsHitCell(battlefield, currentCell); + } + markAboveAsHitCell(battlefield, currentCell); + markBelowAsHitCell(battlefield, currentCell); + } + } + + private static void markAboveAsHitCell(Battlefield battlefield, Cell currentCell) { + if (currentCell.getX() != 0) { + battlefield.getCellByPosition(currentCell.getX() - 1, currentCell.getY()).setHit(true); + } + } + + private static void markBelowAsHitCell(Battlefield battlefield, Cell currentCell) { + if (currentCell.getX() != Field.FIELD_SIZE - 1) { + battlefield.getCellByPosition(currentCell.getX() + 1, currentCell.getY()).setHit(true); + } + } + + private static void markRightAsHitCell(Battlefield battlefield, Cell currentCell) { + if (currentCell.getY() != Field.FIELD_SIZE - 1) { + battlefield.getCellByPosition(currentCell.getX(), currentCell.getY() + 1).setHit(true); + } + } + + private static void markLeftAsHitCell(Battlefield battlefield, Cell currentCell) { + if (currentCell.getY() != 0) { + battlefield.getCellByPosition(currentCell.getX(), currentCell.getY() - 1).setHit(true); + } + } + + private static void markDiagonalRightBelowAsHitCell(Battlefield battlefield, Cell currentCell) { + if (currentCell.getX() != Field.FIELD_SIZE - 1 && currentCell.getY() != Field.FIELD_SIZE - 1) { + battlefield.getCellByPosition(currentCell.getX() + 1, currentCell.getY() + 1).setHit(true); + } + } + + private static void markDiagonalRightAboveAsHitCell(Battlefield battlefield, Cell currentCell) { + if (currentCell.getX() != 0 && currentCell.getY() != Field.FIELD_SIZE - 1) { + battlefield.getCellByPosition(currentCell.getX() - 1, currentCell.getY() + 1).setHit(true); + } + } + + private static void markDiagonalLeftBelowAsHitCell(Battlefield battlefield, Cell currentCell) { + if (currentCell.getX() != Field.FIELD_SIZE - 1 && currentCell.getY() != 0) { + battlefield.getCellByPosition(currentCell.getX() + 1, currentCell.getY() - 1).setHit(true); + } + } + + private static void markDiagonalLeftAboveAsHitCell(Battlefield battlefield, Cell currentCell) { + if (currentCell.getX() != 0 && currentCell.getY() != 0) { + battlefield.getCellByPosition(currentCell.getX() - 1, currentCell.getY() - 1).setHit(true); + } + } + +} diff --git a/src/main/java/course_project/utils/RandomCellPositionGenerator.java b/src/main/java/course_project/utils/RandomCellPositionGenerator.java new file mode 100644 index 00000000..0a44065d --- /dev/null +++ b/src/main/java/course_project/utils/RandomCellPositionGenerator.java @@ -0,0 +1,15 @@ +package course_project.utils; + +import java.security.SecureRandom; + +import static course_project.gamestuff.field.Field.FIELD_SIZE; + +public class RandomCellPositionGenerator { + + private RandomCellPositionGenerator() {} + + public static int generateRandomForCell() { + return new SecureRandom().nextInt(FIELD_SIZE); + } + +} diff --git a/src/main/java/course_project/utils/RandomShipDirectionGenerator.java b/src/main/java/course_project/utils/RandomShipDirectionGenerator.java new file mode 100644 index 00000000..bf03c2ff --- /dev/null +++ b/src/main/java/course_project/utils/RandomShipDirectionGenerator.java @@ -0,0 +1,11 @@ +package course_project.utils; + +public class RandomShipDirectionGenerator { + + private RandomShipDirectionGenerator() {} + + public static boolean generateRandomDirection() { + return Math.random() <= 0.5; + } + +} diff --git a/src/main/java/course_project/utils/ShipOnBattlefieldPlacer.java b/src/main/java/course_project/utils/ShipOnBattlefieldPlacer.java new file mode 100644 index 00000000..dd23070d --- /dev/null +++ b/src/main/java/course_project/utils/ShipOnBattlefieldPlacer.java @@ -0,0 +1,141 @@ +package course_project.utils; + +import course_project.gamestuff.field.Battlefield; +import course_project.gamestuff.field.Cell; +import course_project.gamestuff.ships.Ship; + +import static course_project.gamestuff.field.Field.FIELD_SIZE; + +/** + * Ship placing on owner battlefield + * checkers for availability of addition ship. + */ +public final class ShipOnBattlefieldPlacer { + + private ShipOnBattlefieldPlacer() {} + + public static boolean isEnoughSpaceToPlaceShip(Cell fromCell, int shipSize, boolean isHorizontal) { + return isHorizontal ? + fromCell.getY() >= 0 && fromCell.getY() + shipSize <= FIELD_SIZE : + fromCell.getX() >= 0 && fromCell.getX() + shipSize <= FIELD_SIZE; + } + + public static boolean addColumnOfCells(Battlefield battlefield, Cell firstCell, Ship ship) { + if (isAbleToAddColumnOfCells(battlefield, firstCell, ship.getSize())) { + int y = firstCell.getY(); + ship.setStartCell(firstCell); + ship.setVertical(); + for (int i = firstCell.getX(); i < firstCell.getX() + ship.getSize(); i++) { + battlefield.getCellByPosition(i, y).placeShipOnCell(ship); + } + return true; + } + return false; + } + + public static boolean addRowOfCells(Battlefield battlefield, Cell firstCell, Ship ship) { + if (isAbleToAddRowOfCells(battlefield, firstCell, ship.getSize())) { + int x = firstCell.getX(); + ship.setStartCell(firstCell); + for (int j = firstCell.getY(); j < firstCell.getY() + ship.getSize(); j++) { + battlefield.getCellByPosition(x, j).placeShipOnCell(ship); + } + return true; + } + return false; + } + + private static boolean isAbleToAddColumnOfCells(Battlefield battlefield, Cell firstCell, int shipSize) { + if (!(isCellAboveFromCurrentIsEmpty(battlefield, firstCell) && + isCellDiagonalLeftAboveFromCurrentIsEmpty(battlefield, firstCell) && + isCellDiagonalRightAboveFromCurrentIsEmpty(battlefield, firstCell))) { + return false; + } + int y = firstCell.getY(); + for (int i = firstCell.getX(); i < firstCell.getX() + shipSize; i++) { + Cell currentCell = battlefield.getCellByPosition(i, y); + if (!(battlefield.isCellEmpty(currentCell) && + isCellBelowFromCurrentIsEmpty(battlefield, currentCell) && + isCellLeftFromCurrentIsEmpty(battlefield, currentCell) && + isCellRightFromCurrentIsEmpty(battlefield, currentCell))) { + return false; + } + if (i == firstCell.getX() + shipSize - 1 && + !(isCellDiagonalLeftBelowFromCurrentIsEmpty(battlefield, currentCell) && + isCellDiagonalRightBelowFromCurrentIsEmpty(battlefield, currentCell)) + ) { + return false; + } + } + return true; + } + + private static boolean isAbleToAddRowOfCells(Battlefield battlefield, Cell firstCell, int shipSize) { + if (!(isCellLeftFromCurrentIsEmpty(battlefield, firstCell) && + isCellDiagonalLeftAboveFromCurrentIsEmpty(battlefield, firstCell) && + isCellDiagonalLeftBelowFromCurrentIsEmpty(battlefield, firstCell) && + isCellDiagonalRightAboveFromCurrentIsEmpty(battlefield, firstCell)) + ) { + return false; + } + int x = firstCell.getX(); + for (int j = firstCell.getY(); j < firstCell.getY() + shipSize; j++) { + Cell currentCell = battlefield.getCellByPosition(x, j); + if (!(battlefield.isCellEmpty(currentCell) && + isCellRightFromCurrentIsEmpty(battlefield, currentCell) && + isCellAboveFromCurrentIsEmpty(battlefield, currentCell) && + isCellBelowFromCurrentIsEmpty(battlefield, currentCell)) + ) { + return false; + } + if (j == firstCell.getY() + shipSize - 1 && + !(isCellDiagonalRightAboveFromCurrentIsEmpty(battlefield, currentCell) && + isCellDiagonalRightBelowFromCurrentIsEmpty(battlefield, currentCell)) + ) { + return false; + } + } + return true; + } + + private static boolean isCellRightFromCurrentIsEmpty(Battlefield battlefield, Cell currentCell) { + return currentCell.getY() == FIELD_SIZE - 1 || + battlefield.isCellEmpty(battlefield.getCellByPosition(currentCell.getX(), currentCell.getY() + 1)); + } + + private static boolean isCellLeftFromCurrentIsEmpty(Battlefield battlefield, Cell currentCell) { + return currentCell.getY() == 0 || + battlefield.isCellEmpty(battlefield.getCellByPosition(currentCell.getX(), currentCell.getY() - 1)); + } + + private static boolean isCellAboveFromCurrentIsEmpty(Battlefield battlefield, Cell currentCell) { + return currentCell.getX() == 0 || + battlefield.isCellEmpty(battlefield.getCellByPosition(currentCell.getX() - 1, currentCell.getY())); + } + + private static boolean isCellBelowFromCurrentIsEmpty(Battlefield battlefield, Cell currentCell) { + return currentCell.getX() == FIELD_SIZE - 1 || + battlefield.isCellEmpty(battlefield.getCellByPosition(currentCell.getX() + 1, currentCell.getY())); + } + + private static boolean isCellDiagonalLeftAboveFromCurrentIsEmpty(Battlefield battlefield, Cell currentCell) { + return currentCell.getX() == 0 || currentCell.getY() == 0 || + battlefield.isCellEmpty(battlefield.getCellByPosition(currentCell.getX() - 1, currentCell.getY() - 1)); + } + + private static boolean isCellDiagonalRightAboveFromCurrentIsEmpty(Battlefield battlefield, Cell currentCell) { + return currentCell.getX() == 0 || currentCell.getY() == FIELD_SIZE - 1 || + battlefield.isCellEmpty(battlefield.getCellByPosition(currentCell.getX() - 1, currentCell.getY() + 1)); + } + + private static boolean isCellDiagonalLeftBelowFromCurrentIsEmpty(Battlefield battlefield, Cell currentCell) { + return currentCell.getX() == FIELD_SIZE - 1 || currentCell.getY() == 0 || + battlefield.isCellEmpty(battlefield.getCellByPosition(currentCell.getX() + 1, currentCell.getY() - 1)); + } + + private static boolean isCellDiagonalRightBelowFromCurrentIsEmpty(Battlefield battlefield, Cell currentCell) { + return currentCell.getX() == FIELD_SIZE - 1 || currentCell.getY() == FIELD_SIZE - 1 || + battlefield.isCellEmpty(battlefield.getCellByPosition(currentCell.getX() + 1, currentCell.getY() + 1)); + } + +} diff --git a/src/main/java/homework_1/Main.java b/src/main/java/homework_1/Main.java index 07c029a2..123ea4ca 100644 --- a/src/main/java/homework_1/Main.java +++ b/src/main/java/homework_1/Main.java @@ -2,8 +2,18 @@ public class Main { - public static void main(String[] args) { - System.out.println("Hello homework!"); - } + private static final String RED = "\u001b[31m"; + private static final String RESET = "\u001b[0m"; + + public static void main(String[] args) { + for (String arg : args) { + if (arg.equalsIgnoreCase("ошибка") || arg.equalsIgnoreCase("error")) { + System.out.println(RED + "Alarm!" + RESET); + break; + } + + System.out.println(arg + ": " + arg.length() + " letters"); + } + } } diff --git a/src/main/java/homework_2/Colors.java b/src/main/java/homework_2/Colors.java new file mode 100644 index 00000000..78fecda2 --- /dev/null +++ b/src/main/java/homework_2/Colors.java @@ -0,0 +1,15 @@ +package homework_2; + +public final class Colors { + + private Colors() {} + + public static final String ANSI_RESET = "\u001B[0m"; + public static final String ANSI_RED = "\033[1;91m"; + public static final String ANSI_GREEN = "\033[1;92m"; + public static final String ANSI_YELLOW = "\033[1;93m"; + public static final String BLUE_BG = "\033[0;104m"; + public static final String PURPLE_BG = "\033[0;105m"; + public static final String CYAN_BG = "\033[0;106m"; + +} diff --git a/src/main/java/homework_2/IOMod.java b/src/main/java/homework_2/IOMod.java new file mode 100644 index 00000000..2a43845e --- /dev/null +++ b/src/main/java/homework_2/IOMod.java @@ -0,0 +1,32 @@ +package homework_2; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class IOMod { + + public static final String ERROR = "Only 1 non-negative integer is allowed as passed parameter"; + public static final String FORMAT_ERROR = "Passed parameters should match the format [positive integer] [positive integer] [even|odd]"; + + public static int bufferedReaderIntReader() { + int inp = -1; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { + inp = Integer.parseInt(reader.readLine()); + } catch (NumberFormatException | IOException e) { + return inp; + } + return inp; + } + + public static String bufferedReaderStringReader() { + String s = ""; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) { + s = reader.readLine(); + } catch (IOException e) { + System.out.println(FORMAT_ERROR); + } + return s; + } + +} 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..675fbc15 --- /dev/null +++ b/src/main/java/homework_2/pyramid_printer/Main.java @@ -0,0 +1,11 @@ +package homework_2.pyramid_printer; + +public class Main { + public static void main(String[] args) { + if (args.length == 0) { + new PyramidPrinter().run(); + } else { + new OptimizedPyramidPrinter().run(args[0]); + } + } +} diff --git a/src/main/java/homework_2/pyramid_printer/OptimizedPyramidPrinter.java b/src/main/java/homework_2/pyramid_printer/OptimizedPyramidPrinter.java new file mode 100644 index 00000000..80dfb85e --- /dev/null +++ b/src/main/java/homework_2/pyramid_printer/OptimizedPyramidPrinter.java @@ -0,0 +1,38 @@ +package homework_2.pyramid_printer; + +import static homework_2.IOMod.*; +import static homework_2.Colors.*; + +public class OptimizedPyramidPrinter { + + public void run(String arg) { + if (arg.equalsIgnoreCase("o") || arg.equalsIgnoreCase("optimized")) { + System.out.print("Please, input Pyramid height: "); + int h = bufferedReaderIntReader(); + if (h < 0) { + System.out.println(ERROR); + return; + } + printPyramid(h); + } else { + System.out.println("Incorrect argument. You can call this app as:\n" + + PURPLE_BG + "java Main -o" + ANSI_RESET + "\nor\n" + + BLUE_BG + "java Main -optimized" + ANSI_RESET); + } + } + + private void printPyramid(int height) { + for (int i = 0; i < height; i++) { + System.out.println(genPyramidRow(i + 1)); + } + } + + private String genPyramidRow(int rowLen) { + StringBuilder xRow = new StringBuilder(); + for (int i = 0; i < rowLen; i++) { + xRow.append('x'); + } + return xRow.toString(); + } + +} 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..ce2facfc --- /dev/null +++ b/src/main/java/homework_2/pyramid_printer/PyramidPrinter.java @@ -0,0 +1,27 @@ +package homework_2.pyramid_printer; + +import static homework_2.IOMod.ERROR; +import static homework_2.IOMod.bufferedReaderIntReader; + +public class PyramidPrinter { + + public void run() { + System.out.print("Please, input Pyramid height: "); + int height = bufferedReaderIntReader(); + if (height < 0) { + System.out.println(ERROR); + return; + } + printPyramid(height); + } + + private void printPyramid(int height) { + for (int i = 0; i < height; i++) { + for (int j = 1; j <= i + 1; j++) { + System.out.print("x"); + } + System.out.println(); + } + } + +} diff --git a/src/main/java/homework_2/pyramid_printer/README.md b/src/main/java/homework_2/pyramid_printer/README.md new file mode 100644 index 00000000..b4420c32 --- /dev/null +++ b/src/main/java/homework_2/pyramid_printer/README.md @@ -0,0 +1,15 @@ +### Pyramid Printer App + +__Task:__ + +- read a number from the command line once + +- print Pyramid with this number as a height + +- on any error print to command line "Only 1 non-negative integer is allowed as passed parameter" + +- if input value = 0 prints nothing + +__Extra arguments:__ +- Much faster then the regular App but uses more RAM resource; + can be called by "java Main -o" or "java Main -optimized" \ 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..e3879e1b --- /dev/null +++ b/src/main/java/homework_2/random_chars_table/Main.java @@ -0,0 +1,9 @@ +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/README.md b/src/main/java/homework_2/random_chars_table/README.md new file mode 100644 index 00000000..1014f2ba --- /dev/null +++ b/src/main/java/homework_2/random_chars_table/README.md @@ -0,0 +1,11 @@ +### Random Chars Table App + +__Task:__ + +- read in one line 2 numbers and string - length and width of the table/2d-matrix and strategy (even/odd) + +- print table filled with random chars from A to Z + +- print in a command line in one line with commas all odd or even chars from table depended on chosen strategy + +- on any error should print in a command line "Passed parameters should match the format [positive integer] [positive integer] [even|odd]" \ No newline at end of file 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..d90d61c0 --- /dev/null +++ b/src/main/java/homework_2/random_chars_table/RandomCharsTable.java @@ -0,0 +1,91 @@ +package homework_2.random_chars_table; + +import javax.xml.bind.ValidationException; +import java.util.Random; + +import static homework_2.IOMod.*; + +public class RandomCharsTable { + + private static final int RAND_MIN_VALUE = 65; // A + private static final int RAND_MAX_VALUE = 90; // Z + + public void run() { + inputData(); + } + + private void inputData() { + System.out.print("Input table length, table width, table strategy(even/odd): "); + try { + String s = bufferedReaderStringReader(); + String[] parameters = s.split(" "); + if (!isInputValid(parameters)) { + throw new ValidationException(""); + } + int tableLength = Integer.parseInt(parameters[0]); + int tableWidth = Integer.parseInt(parameters[1]); + boolean strategy = parameters[2].equalsIgnoreCase("even"); + + printRandomAndGenerateResult(tableLength, tableWidth, strategy); + } catch (NullPointerException | ValidationException e) { + System.out.println(FORMAT_ERROR); + } + } + + private boolean isInputValid(String[] parameters) { + if (parameters.length == 3) { + return parameters[0].chars().allMatch(Character::isDigit) && + !parameters[0].equals("0") && + parameters[1].chars().allMatch(Character::isDigit) && + !parameters[1].equals("0") && + (parameters[2].equalsIgnoreCase("odd") || parameters[2].equalsIgnoreCase("even")); + } + return false; + } + + private void printRandomAndGenerateResult(int length, int width, boolean strategy) { + Character[][] randAbc = new Character[length][width]; + Random random = new Random(); + StringBuilder result = new StringBuilder(); + + for (int i = 0; i < length; i++) { + System.out.print("| "); + for (int j = 0; j < width; j++) { + randAbc[i][j] = (char) (random.nextInt((RAND_MAX_VALUE - RAND_MIN_VALUE) + 1) + RAND_MIN_VALUE); + System.out.print(randAbc[i][j] + " | "); + + // result generating on-the-go + generateResult(strategy ? 0 : 1, randAbc[i][j], result); + } + System.out.println(); + } + printResult(strategy, result); + } + + private void generateResult(int strategy, char ch, StringBuilder result) { + if ((ch % 2 == strategy) && (!String.valueOf(result).contains(String.valueOf(ch)))) { + result.append(ch); + } + } + + private void printResult(boolean strategy, StringBuilder result) { + if (result.length() == 0) { + return; + } + if (strategy) { + System.out.print("Even letters - "); + } else { + System.out.print("Odd letters - "); + } + int i = 0; + while (true) { + if (i == result.length() - 1) { + System.out.print(result.charAt(i)); + break; + } + System.out.print(result.charAt(i) + ", "); + i++; + } + } + +} diff --git a/src/main/java/homework_2/traffic_light/ExtraTrafficLight.java b/src/main/java/homework_2/traffic_light/ExtraTrafficLight.java new file mode 100644 index 00000000..1c9d64d4 --- /dev/null +++ b/src/main/java/homework_2/traffic_light/ExtraTrafficLight.java @@ -0,0 +1,42 @@ +package homework_2.traffic_light; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import static homework_2.Colors.*; + +public class ExtraTrafficLight { + + public void run(String arg) { + if (arg.equalsIgnoreCase("now")) { + int seconds = getTime(); + colorPick(seconds%60); + } else { + System.out.println("Incorrect argument. You can call this app as:\n" + + PURPLE_BG + "java Main -now" + ANSI_RESET); + } + } + + private int getTime() { + LocalDateTime now = LocalDateTime.now(); + String nowStr = now.format(DateTimeFormatter.ofPattern("hh:mm:ss a")); + System.out.println("Current time is: " + nowStr); + return now.toLocalTime().toSecondOfDay(); + } + + private void colorPick(int secs) { + // 0 <= light < 35 green, 35 <= light < 40 yellow, 40 <= light < 55 red, 55 <= light < 60 yellow + if (secs >= 0 && secs < 35) { + lightPrint(ANSI_GREEN, "GREEN"); + } else if ((secs >= 35 && secs < 40) || (secs >= 55 && secs < 60)) { + lightPrint(ANSI_YELLOW, "YELLOW"); + } else { + lightPrint(ANSI_RED, "RED"); + } + } + + private void lightPrint(String consoleColor, String lightColor) { + System.out.println(consoleColor + lightColor + ANSI_RESET); + } + +} 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..4dc659df --- /dev/null +++ b/src/main/java/homework_2/traffic_light/Main.java @@ -0,0 +1,19 @@ +package homework_2.traffic_light; + +/* +Traffic Lights App + +you can use 'now' argument to get result for the current time ;) +java Main -now + + */ + +public class Main { + public static void main(String[] args) { + if (args.length == 0) { + new TrafficLight().run(); + } else { + new ExtraTrafficLight().run(args[0]); + } + } +} diff --git a/src/main/java/homework_2/traffic_light/README.md b/src/main/java/homework_2/traffic_light/README.md new file mode 100644 index 00000000..83a2c387 --- /dev/null +++ b/src/main/java/homework_2/traffic_light/README.md @@ -0,0 +1,23 @@ +### Traffic Light App + +__Task:__ + +- read input how much time gone from the day start from the command line, +parse to Integer, print to the command line traffic light color (GREEN, YELLOW, RED - with different colors) + +- traffic lights cycle: 60 seconds: + + 0 <= light < 35 - green + + 35 <= light < 40 - yellow + + 40 <= light < 55 - red + + 55 <= light < 60 - yellow + +- input limitations: + + minimal value is 0 + + maximal value is 24*60*60 - 1 = 86399 + +- if over then 86399 should print "The day is over" + +- if input value is incorrect should print "Only 1 non-negative integer is allowed as passed parameter" + +__Extra arguments:__ +- App will count the traffic lights result for the current time if call "java Main -now" \ No newline at end of file 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..46740556 --- /dev/null +++ b/src/main/java/homework_2/traffic_light/TrafficLight.java @@ -0,0 +1,45 @@ +package homework_2.traffic_light; + +import homework_2.IOMod; + +import static homework_2.IOMod.*; +import static homework_2.Colors.*; + +public class TrafficLight { + + public void run() { + inputSeconds(); + } + + private void inputSeconds() { + System.out.print("Please, input seconds gone from the day start: "); + try { + int secondsGone = IOMod.bufferedReaderIntReader(); + if (secondsGone < 0) { + System.out.println(ERROR); + } else if (secondsGone >= 86400) { + System.out.println("The day is over"); + } else { + colorPick(secondsGone % 60); + } + } catch (NumberFormatException exc) { + System.out.println(ERROR); + } + } + + private void colorPick(int secs) { + // 0 <= light < 35 green, 35 <= light < 40 yellow, 40 <= light < 55 red, 55 <= light < 60 yellow + if (secs < 35) { + lightPrint(ANSI_GREEN, "GREEN"); + } else if ((secs < 40) || (secs >= 55 && secs < 60)) { + lightPrint(ANSI_YELLOW, "YELLOW"); + } else { + lightPrint(ANSI_RED, "RED"); + } + } + + private void lightPrint(String consoleColor, String lightColor) { + System.out.println(consoleColor + lightColor + ANSI_RESET); + } + +} diff --git a/src/main/java/homework_3/ImmutableClass.java b/src/main/java/homework_3/ImmutableClass.java new file mode 100644 index 00000000..59cd2e2a --- /dev/null +++ b/src/main/java/homework_3/ImmutableClass.java @@ -0,0 +1,66 @@ +package homework_3; + +/* +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) + */ + +import java.util.LinkedList; +import java.util.List; + +public final class ImmutableClass { + + private final List allDataList; // mutable type + private final int age; // primitive type + private final double weight; // primitive type + + public ImmutableClass() { + this.age = 0; + this.weight = 0.0; + this.allDataList = new LinkedList<>(); + initAllDataList(); + } + + public ImmutableClass(int age, double weight) { + this.age = age; + this.weight = weight; + this.allDataList = new LinkedList<>(); + initAllDataList(); + } + + public ImmutableClass(List allData, int age, double weight) { + this.age = age; + this.weight = weight; + this.allDataList = new LinkedList<>(allData); + initAllDataList(); + } + + private void initAllDataList() { + this.allDataList.add(age); + this.allDataList.add(weight); + } + + public List getAllDataList() { + return new LinkedList<>(this.allDataList); + } + + public ImmutableClass getNewObjectWithChanges(List changes) { + List list = getAllDataList(); + list.addAll(changes); + return new ImmutableClass(list, this.age, this.weight); + } + + public int getAge() { + return age; + } + + public double getWeight() { + return weight; + } + +} diff --git a/src/main/java/homework_3/Main.java b/src/main/java/homework_3/Main.java new file mode 100644 index 00000000..9884add3 --- /dev/null +++ b/src/main/java/homework_3/Main.java @@ -0,0 +1,19 @@ +package homework_3; + +import java.util.LinkedList; +import java.util.List; + +public class Main { + + public static void main(String[] args) { + ImmutableClass obj = new ImmutableClass(2, 3.0); + obj.getAllDataList().forEach(System.out::println); + List changes = new LinkedList<>(); + changes.add(1); + changes.add(12.); + changes.add(13); + ImmutableClass obj2 = obj.getNewObjectWithChanges(changes); + obj2.getAllDataList().forEach(System.out::println); + } + +} diff --git a/src/main/java/homework_4/custom_annotation/ResourcesPath.java b/src/main/java/homework_4/custom_annotation/ResourcesPath.java new file mode 100644 index 00000000..89c7a5ce --- /dev/null +++ b/src/main/java/homework_4/custom_annotation/ResourcesPath.java @@ -0,0 +1,12 @@ +package homework_4.custom_annotation; + +import java.lang.annotation.*; + + +@Target({ElementType.LOCAL_VARIABLE, ElementType.FIELD, ElementType.CONSTRUCTOR}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ResourcesPath { + + String dirPath() default "./src/main/resources/custom_file_reader/"; + +} 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..6a86ca65 --- /dev/null +++ b/src/main/java/homework_4/custom_file_reader/CustomFileReader.java @@ -0,0 +1,67 @@ +package homework_4.custom_file_reader; + +import homework_4.custom_annotation.ResourcesPath; +import homework_4.custom_file_reader.utils.*; + +import static homework_4.custom_file_reader.utils.ModifiedStringPrinter.printModifiedString; + + +public class CustomFileReader { + + private final String fileName; + private final String dirPath; + + @ResourcesPath + public CustomFileReader() { + this.fileName = "file.txt"; + String tmpDirPath; + try { + ResourcesPath resourcesPath = (ResourcesPath) this.getClass().getConstructor().getDeclaredAnnotations()[0]; + tmpDirPath = resourcesPath.dirPath(); + } catch (NoSuchMethodException e) { + tmpDirPath = "./src/main/resources/"; // not including custom folder! + } + this.dirPath = tmpDirPath; + } + + public CustomFileReader(String dirPath, String fileName) { + this.dirPath = dirPath; + this.fileName = fileName; + } + + // using scanner + public synchronized void run1() { + doExcellent(new ScannerFileRead().fileReader(this.dirPath, this.fileName)); + } + + // using buffered reader + public synchronized void run2() { + doExcellent(new BufferedReaderAsStreamFileRead().fileReader(this.dirPath, this.fileName)); + } + + // using nio + public synchronized void run3() { + doExcellent(new NIOFileRead().fileReader(this.dirPath, this.fileName)); + } + + // using InputStreamReader + public synchronized void run4() { + doExcellent(new InputStreamReaderFileRead().fileReader(this.dirPath, this.fileName)); + } + + // prints all files and subdirectories from set directory + public void showDir() { + DirectoryScan.scanDir(this.dirPath); + } + + private boolean isNotExists(String res) { + return res == null; + } + + private void doExcellent(String result) { + if (isNotExists(result)) { + System.out.println("File " + this.fileName + " not found at: " + this.dirPath); + } else printModifiedString(result); + } + +} diff --git a/src/main/java/homework_4/custom_file_reader/utils/BufferedReaderAsStreamFileRead.java b/src/main/java/homework_4/custom_file_reader/utils/BufferedReaderAsStreamFileRead.java new file mode 100644 index 00000000..4783f3f2 --- /dev/null +++ b/src/main/java/homework_4/custom_file_reader/utils/BufferedReaderAsStreamFileRead.java @@ -0,0 +1,22 @@ +package homework_4.custom_file_reader.utils; + +import java.io.*; + + +public class BufferedReaderAsStreamFileRead implements FileReadability { + + @Override + public String fileReader(String dirPath, String fileName) { + try (final FileInputStream fileInputStream = new FileInputStream(dirPath + fileName); + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream))) { + final StringBuilder stringBuilder = new StringBuilder(fileInputStream.available()); + while (bufferedReader.ready()) { + stringBuilder.append(bufferedReader.readLine()).append("\n"); + } + return String.valueOf(stringBuilder); + } catch (IOException e) { + return null; + } + } + +} diff --git a/src/main/java/homework_4/custom_file_reader/utils/DirectoryScan.java b/src/main/java/homework_4/custom_file_reader/utils/DirectoryScan.java new file mode 100644 index 00000000..ec4bf265 --- /dev/null +++ b/src/main/java/homework_4/custom_file_reader/utils/DirectoryScan.java @@ -0,0 +1,37 @@ +package homework_4.custom_file_reader.utils; + +import java.io.File; + + +public class DirectoryScan { + + private DirectoryScan() { } + + public static void scanDir(String dirPath) { + File[] filesList = new File(dirPath).listFiles(); + if (filesList != null && filesList.length >= 1) { + System.out.println(dirPath + " contains:" + "\n--- --- ---"); + for (File file : filesList) { + System.out.println(file.getName() + "\tat: " + file.getAbsolutePath()); + System.out.println("---"); + } + System.out.println("--- --- ---"); + } else System.out.println(dirPath + " is empty!"); + } + + // additional method for extra usage + public static boolean isInDir(String dirPath, String fileName) { + File[] filesList = new File(dirPath).listFiles(); + if (filesList == null) { + System.out.println(dirPath + " is empty!"); + return false; + } + for (File file : filesList) { + if (file.getName().equalsIgnoreCase(fileName)) { + return true; + } + } + return false; + } + +} diff --git a/src/main/java/homework_4/custom_file_reader/utils/FileReadability.java b/src/main/java/homework_4/custom_file_reader/utils/FileReadability.java new file mode 100644 index 00000000..b2e8c1f0 --- /dev/null +++ b/src/main/java/homework_4/custom_file_reader/utils/FileReadability.java @@ -0,0 +1,8 @@ +package homework_4.custom_file_reader.utils; + + +public interface FileReadability { + + String fileReader(String dirPath, String fileName); + +} diff --git a/src/main/java/homework_4/custom_file_reader/utils/InputStreamReaderFileRead.java b/src/main/java/homework_4/custom_file_reader/utils/InputStreamReaderFileRead.java new file mode 100644 index 00000000..e7f53b8c --- /dev/null +++ b/src/main/java/homework_4/custom_file_reader/utils/InputStreamReaderFileRead.java @@ -0,0 +1,27 @@ +package homework_4.custom_file_reader.utils; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; + + +public class InputStreamReaderFileRead implements FileReadability { + + @Override + public String fileReader(String dirPath, String fileName) { + try (FileInputStream inputStream = new FileInputStream(dirPath + fileName); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) { + StringBuilder lines = new StringBuilder(); + String line; + while (null != (line = bufferedReader.readLine())) { + lines.append(line).append("\n"); + } + return String.valueOf(lines); + } catch (IOException e) { + return null; + } + } + +} diff --git a/src/main/java/homework_4/custom_file_reader/utils/ModifiedStringPrinter.java b/src/main/java/homework_4/custom_file_reader/utils/ModifiedStringPrinter.java new file mode 100644 index 00000000..021de505 --- /dev/null +++ b/src/main/java/homework_4/custom_file_reader/utils/ModifiedStringPrinter.java @@ -0,0 +1,13 @@ +package homework_4.custom_file_reader.utils; + + +public class ModifiedStringPrinter { + + private ModifiedStringPrinter() { } + + // printing string without '.' and ',' symbols + public static void printModifiedString(String str) { + System.out.println(str.replaceAll("[,.]", "")); + } + +} diff --git a/src/main/java/homework_4/custom_file_reader/utils/NIOFileRead.java b/src/main/java/homework_4/custom_file_reader/utils/NIOFileRead.java new file mode 100644 index 00000000..e792a9cf --- /dev/null +++ b/src/main/java/homework_4/custom_file_reader/utils/NIOFileRead.java @@ -0,0 +1,26 @@ +package homework_4.custom_file_reader.utils; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; + + +public class NIOFileRead implements FileReadability { + + @Override + public String fileReader(String dirPath, String fileName) { + File textFile; + try { + textFile = new File(dirPath + fileName); + List lines; + lines = Files.readAllLines(textFile.toPath()); + StringBuilder stringBuilder = new StringBuilder(); + lines.forEach(line -> stringBuilder.append(line).append("\n")); + return String.valueOf(stringBuilder); + } catch (IOException e) { + return null; + } + } + +} diff --git a/src/main/java/homework_4/custom_file_reader/utils/ScannerFileRead.java b/src/main/java/homework_4/custom_file_reader/utils/ScannerFileRead.java new file mode 100644 index 00000000..f0137449 --- /dev/null +++ b/src/main/java/homework_4/custom_file_reader/utils/ScannerFileRead.java @@ -0,0 +1,24 @@ +package homework_4.custom_file_reader.utils; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + + +public class ScannerFileRead implements FileReadability { + + @Override + public String fileReader(String dirPath, String fileName) { + try (Scanner scanner = new Scanner(new File(dirPath + fileName))) { + StringBuilder stringBuilder = new StringBuilder(); + while (scanner.hasNextLine()) { + stringBuilder.append(scanner.nextLine()); + stringBuilder.append("\n"); + } + return String.valueOf(stringBuilder); + } catch (FileNotFoundException e) { + return null; + } + } + +} 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..739623ee --- /dev/null +++ b/src/main/java/homework_4/singleton/Main.java @@ -0,0 +1,15 @@ +package homework_4.singleton; + +/* + Singleton provides access to CustomFileReader methods through GUI. + It's the only one instance of GUI able to run (thread-safe). + */ + + +public class Main { + + public static void main(String[] args) { + SingletonMenu.getInstance(); + } + +} diff --git a/src/main/java/homework_4/singleton/SingletonMenu.java b/src/main/java/homework_4/singleton/SingletonMenu.java new file mode 100644 index 00000000..0e4a3c6e --- /dev/null +++ b/src/main/java/homework_4/singleton/SingletonMenu.java @@ -0,0 +1,79 @@ +package homework_4.singleton; + +import homework_4.custom_file_reader.CustomFileReader; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + + +// Bill Pugh Singleton Implementation +public class SingletonMenu { + + private SingletonMenu() { + guiGenerator(); + } + + private static class SingletonHelper { + private static final SingletonMenu INSTANCE = new SingletonMenu(); + } + + public static SingletonMenu getInstance() { + return SingletonHelper.INSTANCE; + } + + private void guiGenerator() { + JFrame frame = new JFrame("Singleton Menu for CustomFileReader"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(500, 350); + + JPanel mainPanel = new JPanel(); + JButton button1 = new JButton("read file using Scanner"); + JButton button2 = new JButton("read file using BufferedReader"); + JButton button3 = new JButton("read file using NIO"); + JButton button4 = new JButton("read file using InputStreamReader"); + JButton button5 = new JButton("show files in directory"); + mainPanel.add(button1); + mainPanel.add(button2); + mainPanel.add(button3); + mainPanel.add(button4); + mainPanel.add(button5); + + CustomFileReader customFileReader = new CustomFileReader(); + addButtonListener(button1, customFileReader, 1); + addButtonListener(button2, customFileReader, 2); + addButtonListener(button3, customFileReader, 3); + addButtonListener(button4, customFileReader, 4); + addButtonListener(button5, customFileReader, 10); + + // Adding Components to the frame + frame.getContentPane().add(BorderLayout.CENTER, mainPanel); + frame.setVisible(true); + } + + private void addButtonListener(@NotNull JButton button, CustomFileReader customFileReader, int methodNumber) { + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + buttonActionPerformed(); + } + + private void buttonActionPerformed() { + if (methodNumber == 1) { + customFileReader.run1(); + } else if (methodNumber == 2) { + customFileReader.run2(); + } else if (methodNumber == 3) { + customFileReader.run3(); + } else if (methodNumber == 4) { + customFileReader.run4(); + } else if (methodNumber == 10) { + customFileReader.showDir(); + } else throw new IllegalArgumentException(); + } + }); + } + +} 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..4ddadbac --- /dev/null +++ b/src/main/java/homework_5/custom_regex_matcher/CustomRegexMatcher.java @@ -0,0 +1,27 @@ +package homework_5.custom_regex_matcher; + +import java.util.Scanner; + +public class CustomRegexMatcher { + + private CustomRegexMatcher() { } + + private static final String PHONE_NUMBER_FORMAT = "(\\+\\d)\\s\\(\\d{3}\\)\\s(\\d{3})-(\\d{4})"; + + public static void run() { + System.out.println(validate(getInput())); + } + + private static String getInput() { + try (Scanner scanner = new Scanner(System.in)) { + return scanner.nextLine().trim(); + } + } + + // should be written as: `+# (###) ###-####`, where # - is an integer number + private static Boolean validate(String str) { + return str.matches(PHONE_NUMBER_FORMAT); + } + + +} 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..701a87ac --- /dev/null +++ b/src/main/java/homework_5/power_of_number/PowerOfNumber.java @@ -0,0 +1,48 @@ +package homework_5.power_of_number; + +import java.util.NoSuchElementException; +import java.util.Scanner; + +public class PowerOfNumber { + + private static final String ERROR = "Only 2 non-negative integers are allowed"; + + public void run() { + int[] array = getInput(); + if (array.length == 2) System.out.println(power(array[0], array[1])); + } + + private int[] getInput() { + try (Scanner scanner = new Scanner(System.in)) { + System.out.println("Please, input the values in format: number power"); + String[] input = scanner.nextLine().split(" "); + if (input.length == 2) { + int[] result = new int[2]; + for (int i = 0; i < 2; i++) { + result[i] = Integer.parseInt(input[i]); + if (!isValid(result[i])) { + throw new NumberFormatException(); + } + } + return result; + } else { + throw new NumberFormatException(); + } + } catch (NumberFormatException | NoSuchElementException e) { + System.out.println(ERROR); + return new int[0]; + } + } + + private boolean isValid(int num) { + return num >= 0; + } + + private int power(int base, int p) { + if (p > 0) return base * power(base, p-1); + if (p < 0) return 1/base * power(base, p+1); + return 1; + } + + +} diff --git a/src/main/java/homework_6/map_problems_collision_generator/Main.java b/src/main/java/homework_6/map_problems_collision_generator/Main.java new file mode 100644 index 00000000..18a51a37 --- /dev/null +++ b/src/main/java/homework_6/map_problems_collision_generator/Main.java @@ -0,0 +1,20 @@ +package homework_6.map_problems_collision_generator; + +import java.util.HashMap; +import java.util.Map; + +public class Main { + + public static void main(String[] args) { + + Map unluckyMap = new HashMap<>(); + + MapProblemsMutableGenerator mapProblemsMutableGenerator = new MapProblemsMutableGenerator(); + mapProblemsMutableGenerator.setVal("ложим!"); + unluckyMap.put(mapProblemsMutableGenerator, mapProblemsMutableGenerator.getVal()); + mapProblemsMutableGenerator.setVal("кладем!"); + + System.out.println("не можИм! " + unluckyMap.get(mapProblemsMutableGenerator)); + } + +} diff --git a/src/main/java/homework_6/map_problems_collision_generator/MapProblemsCollisionGenerator.java b/src/main/java/homework_6/map_problems_collision_generator/MapProblemsCollisionGenerator.java new file mode 100644 index 00000000..6fc72057 --- /dev/null +++ b/src/main/java/homework_6/map_problems_collision_generator/MapProblemsCollisionGenerator.java @@ -0,0 +1,32 @@ +package homework_6.map_problems_collision_generator; + +public class MapProblemsCollisionGenerator { + + private final String val; + + public MapProblemsCollisionGenerator() { + this.val = "кладем?"; + } + + public MapProblemsCollisionGenerator(String s) { + this.val = s; + } + + public String getVal() { + return val; + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + MapProblemsCollisionGenerator that = (MapProblemsCollisionGenerator) obj; + return this.getVal().equals(that.getVal()); + } + +} diff --git a/src/main/java/homework_6/map_problems_collision_generator/MapProblemsMutableGenerator.java b/src/main/java/homework_6/map_problems_collision_generator/MapProblemsMutableGenerator.java new file mode 100644 index 00000000..43486379 --- /dev/null +++ b/src/main/java/homework_6/map_problems_collision_generator/MapProblemsMutableGenerator.java @@ -0,0 +1,34 @@ +package homework_6.map_problems_collision_generator; + +import java.util.Objects; + +public class MapProblemsMutableGenerator { + + private String val; + + public MapProblemsMutableGenerator() { + setVal("кладем?"); + } + + public String getVal() { + return val; + } + + public void setVal(String val) { + this.val = val; + } + + @Override + public int hashCode() { + return Objects.hashCode(val); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MapProblemsMutableGenerator that = (MapProblemsMutableGenerator) o; + return Objects.equals(val, that.val); + } + +} diff --git a/src/main/java/homework_7/kitten_to_cat/Cat.java b/src/main/java/homework_7/kitten_to_cat/Cat.java new file mode 100644 index 00000000..436b45e8 --- /dev/null +++ b/src/main/java/homework_7/kitten_to_cat/Cat.java @@ -0,0 +1,56 @@ +package homework_7.kitten_to_cat; + +import java.security.SecureRandom; +import java.util.Random; + +public class Cat { + + private final int age; + private final String name; + + public Cat(String name, int age) { + this.name = name; + this.age = age; + } + + public int getAge() { + return age; + } + + public String getName() { + return name; + } + + private boolean isNameValid() { + return this.name.length() > 2; + } + + @Override + public int hashCode() { + if (isNameValid()) { + return (this.age + this.name.charAt(0)) * 2 << 5; + } else { + try { + Random r = SecureRandom.getInstanceStrong(); + return r.nextInt(); + } catch (Exception e) { + throw new NumberFormatException("ERROR: SecureRandom @hashCode works incorrect for " + this.getClass()); + } + } + } + + @Override + public boolean equals(Object o) { + if (o == null || o.getClass() != this.getClass()) return false; + if (this == o) return true; + Cat that = (Cat) o; + return this.getAge() == that.getAge() && this.getName().equals(that.getName()); + } + + @Override + public String toString() { + return "Cat's name: " + this.getName() + + "\nCat's age: " + this.getAge(); + } + +} diff --git a/src/main/java/homework_7/kitten_to_cat/Kitten.java b/src/main/java/homework_7/kitten_to_cat/Kitten.java new file mode 100644 index 00000000..4f2da7db --- /dev/null +++ b/src/main/java/homework_7/kitten_to_cat/Kitten.java @@ -0,0 +1,63 @@ +package homework_7.kitten_to_cat; + +import java.security.SecureRandom; +import java.util.Random; + +public class Kitten { + + private final int age; + private final String name; + private final String breed; + + public int getAge() { + return age; + } + + public String getName() { + return name; + } + + public String getBreed() { + return breed; + } + + public Kitten(String name, int age, String breed) { + this.name = name; + this.age = age; + this.breed = breed; + } + + private boolean isNameValid() { + return this.name.length() > 2; + } + + @Override + public int hashCode() { + if (isNameValid()) { + return (this.age + this.name.charAt(0)) * 2 << 5; + } else { + try { + Random r = SecureRandom.getInstanceStrong(); + return r.nextInt(); + } catch (Exception e) { + throw new NumberFormatException("ERROR: SecureRandom @hashCode works incorrect for " + this.getClass()); + } + } + } + + @Override + public boolean equals(Object o) { + if (o == null || o.getClass() != this.getClass()) return false; + if (this == o) return true; + Kitten that = (Kitten) o; + return this.age == that.age && this.name.equals(that.name); + } + + @Override + public String toString() { + return "Kitten's name: " + this.getName() + + "\nKitten's age: " + this.getAge() + + "\nKitten's breed: " + this.getBreed(); + } + +} diff --git a/src/main/java/homework_7/kitten_to_cat/KittenToCatFunction.java b/src/main/java/homework_7/kitten_to_cat/KittenToCatFunction.java new file mode 100644 index 00000000..7ba4af51 --- /dev/null +++ b/src/main/java/homework_7/kitten_to_cat/KittenToCatFunction.java @@ -0,0 +1,8 @@ +package homework_7.kitten_to_cat; + +@FunctionalInterface +public interface KittenToCatFunction { + + Cat grow(Kitten k); + +} diff --git a/src/main/resources/custom_file_reader/empty_file.txt b/src/main/resources/custom_file_reader/empty_file.txt new file mode 100644 index 00000000..e69de29b diff --git a/src/main/resources/custom_file_reader/file.txt b/src/main/resources/custom_file_reader/file.txt new file mode 100644 index 00000000..d46a8616 --- /dev/null +++ b/src/main/resources/custom_file_reader/file.txt @@ -0,0 +1,18 @@ +“знаешь, если искать врага – обретаешь его в любом…” + +знаешь, если искать врага – обретаешь его в любом. +вот, пожалуй, спроси меня – мне никто не страшен: +я спокоен и прям и знаю, что впереди. +я хожу без страховки с факелом надо лбом +по стальной струне, натянутой между башен, +когда снизу кричат только: «упади». +разве они знают, чего мне стоило ремесло. +разве они видели, сколько раз я орал и плакал. +разве ступят на ветер, нащупав его изгиб. +они думают, я дурак, которому повезло. +если я отвечу им, я не удержу над бровями факел. +если я отвечу им, я погиб. + +23 июня 2013. Ришикеш + +Вера Николаевна Полозкова. “Работа горя”. \ No newline at end of file diff --git a/src/main/resources/sea_battle/rules.txt b/src/main/resources/sea_battle/rules.txt new file mode 100644 index 00000000..d87a56b4 --- /dev/null +++ b/src/main/resources/sea_battle/rules.txt @@ -0,0 +1,54 @@ +-Правила размещения кораблей (флота) + +Игровое поле — обычно квадрат 10×10 у каждого игрока, на котором размещается флот кораблей. +Вертикали обычно нумеруются сверху вниз, а горизонтали помечаются буквами слева направо. +При этом используются буквы русского алфавита от «а» до «к» (буквы «ё» и «й» обычно пропускаются) +либо от «а» до «и» (с использованием буквы «ё»), либо буквы латинского алфавита от «a» до «j». + +Размещаются: + 1 корабль — ряд из 4 клеток («четырёхпалубный»; линкор) + 2 корабля — ряд из 3 клеток («трёхпалубные»; крейсера) + 3 корабля — ряд из 2 клеток («двухпалубные»; эсминцы) + 4 корабля — 1 клетка («однопалубные»; торпедные катера) + +При размещении корабли не могут касаться друг друга сторонами и углами. +Встречаются, однако, варианты, когда касание углами не запрещается. +Встречаются также варианты игры, когда корабли могут размещаться буквой «Г» («трех-» и «четырехпалубные»), +квадратом или зигзагом («четырехпалубные»). +Кроме того, есть варианты с другим набором кораблей (напр., один пятипалубный, два четырёхпалубных и т. д.) +и/или другой формой поля (15×15 для пятипалубных (авианосец)). + +Рядом со «своим» полем чертится «чужое» такого же размера, только пустое. +Это участок моря, где плавают корабли противника. + +При попадании в корабль противника — на чужом поле ставится крестик, при холостом выстреле — точка. +Попавший стреляет ещё раз. + +Самыми уязвимыми являются линкор и торпедный катер: первый из-за крупных размеров, +в связи с чем его сравнительно легко найти, а второй из-за того, что топится с одного удара, +хотя его найти достаточно сложно. + +-Потопление кораблей противника + +Перед началом боевых действий игроки бросают жребий или договариваются, кто будет ходить первым. + +Игрок, выполняющий ход, совершает выстрел — называет вслух координаты клетки, в которой, по его мнению, +находится корабль противника, например, «В1». + + Если выстрел пришёлся в клетку, не занятую ни одним кораблём противника, + то следует ответ «Мимо!» и стрелявший игрок ставит на чужом квадрате в этом месте точку. + Право хода переходит к сопернику. + + Если выстрел пришёлся в клетку, где находится многопалубный корабль (размером больше чем 1 клетка), + то следует ответ «Ранил(а)!» или «Попал(а)!», кроме одного случая. + Стрелявший игрок ставит на чужом поле в эту клетку крестик, + а его противник ставит крестик на своём поле также в эту клетку. + Стрелявший игрок получает право на ещё один выстрел. + + Если выстрел пришёлся в клетку, где находится однотрубный корабль, + или последнюю непоражённую клетку многопалубного корабля, + то следует ответ «Убил(а)!» или «Потопил(а)!». + Оба игрока отмечают потопленный корабль на листе. Стрелявший игрок получает право на ещё один выстрел. + + +Победителем считается тот, кто первым потопит все 10 кораблей противника. diff --git a/src/test/java/homework_1/MainTest.java b/src/test/java/homework_1/MainTest.java new file mode 100644 index 00000000..67de6860 --- /dev/null +++ b/src/test/java/homework_1/MainTest.java @@ -0,0 +1,49 @@ +package homework_1; + +import base.UnitBase; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class MainTest extends UnitBase { + + @Test + void test1() { + String[] args = { + "abcdefg", + "hello", + "zero", + "", + "абвгдеёжзийклмнопрст", + "quit", + "eRrOr", + "ошибка" + }; + + Main.main(args); + printOut(); + assertEquals("abcdefg: 7 letters", getOutputLines()[0]); + assertEquals("hello: 5 letters", getOutputLines()[1]); + assertEquals("zero: 4 letters", getOutputLines()[2]); + assertEquals(": 0 letters", getOutputLines()[3]); + assertEquals("абвгдеёжзийклмнопрст: 20 letters", getOutputLines()[4]); + assertEquals("quit: 4 letters", getOutputLines()[5]); + assertEquals("\u001b[31mAlarm!\u001b[0m", getOutputLines()[6]); + } + + @Test + void test2() { + String[] args = { + "строка", + "0шибка", + "ошибкА", + }; + + Main.main(args); + printOut(); + assertEquals("строка: 6 letters", getOutputLines()[0]); + assertEquals("0шибка: 6 letters", getOutputLines()[1]); + assertEquals("\u001b[31mAlarm!\u001b[0m", getOutputLines()[2]); + } + +} \ No newline at end of file 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..6d9fa656 --- /dev/null +++ b/src/test/java/homework_2/pyramid_printer/PyramidPrinterTest.java @@ -0,0 +1,73 @@ +package homework_2.pyramid_printer; + +import base.UnitBase; +import org.junit.jupiter.api.Test; +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 PyramidPrinterTest extends UnitBase { + + PyramidPrinter pyramidPrinter = new PyramidPrinter(); + + // testing valid input + private static Stream validCases() { + return Stream.of( + Arguments.of(7), + Arguments.of(4), + Arguments.of(33), + Arguments.of(1), + Arguments.of(188) + ); + } + + @ParameterizedTest + @MethodSource("validCases") + void validTest(int height) { + setInput(String.valueOf(height)); + pyramidPrinter.run(); + printOut(); + removeFromOutput("Please, input Pyramid height: "); + for (int i = 0; i < height; i++) { + StringBuilder expectedStr = new StringBuilder(); + for (int j = 0; j < i + 1; j++) { + expectedStr.append("x"); + } + assertEquals(String.valueOf(expectedStr), getOutputLines()[i]); + } + } + + // testing not valid input values + private static Stream notValidCases() { + return Stream.of( + Arguments.of(String.valueOf(Integer.MAX_VALUE + 1)), + Arguments.of("anytext"), + Arguments.of(""), + Arguments.of("-278") + ); + } + + @ParameterizedTest + @MethodSource("notValidCases") + void testNotValid(String input) { + setInput(input); + pyramidPrinter.run(); + printOut(); + removeFromOutput("Please, input Pyramid height: "); + assertEquals("Only 1 non-negative integer is allowed as passed parameter", getOutputLines()[0]); + } + + @Test + void testNull() { + setInput("0"); + pyramidPrinter.run(); + printOut(); + removeFromOutput("Please, input Pyramid height: "); + assertEquals("", getOutputLines()[0]); + } + +} 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..f7e4b2fb --- /dev/null +++ b/src/test/java/homework_2/random_chars_table/RandomCharsTableTest.java @@ -0,0 +1,128 @@ +package homework_2.random_chars_table; + +import base.UnitBase; +import org.junit.jupiter.api.Test; +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 RandomCharsTableTest extends UnitBase { + + RandomCharsTable rct = new RandomCharsTable(); + + // robots will replace human beings ! + private void testInts(int length, int width) { + if (length <= 0 || width <= 0) { + throw new AssertionError(); + } + } + + private int testStr(String strategy) { + if (strategy.equalsIgnoreCase("odd")) { + return 1; + } else if (strategy.equalsIgnoreCase("even")) { + return 0; + } else { + throw new AssertionError(); + } + } + + // free for adding new valid values + private static Stream validCases() { + return Stream.of( + Arguments.of(5, 5, "odd"), + Arguments.of(7, 5, "even"), + Arguments.of(13, 15, "even"), + Arguments.of(2, 3, "odd"), + Arguments.of(1, 8, "odd"), + Arguments.of(1, 1, "even") + ); + } + + @ParameterizedTest + @MethodSource("validCases") + void testValid(int rows, int columns, String strategy) { + testInts(rows, columns); + int remainder = testStr(strategy); + + setInput( + String.format( + "%d %d %s", + rows, columns, strategy + )); + + rct.run(); + printOut(); + removeFromOutput("Input table length, table width, table strategy(even/odd): "); + for (int i = 0; i < rows; i++) { + String[] row = getOutputLines()[i].split(" "); + for (String el : row) { + assert el.charAt(0) == '|' || (el.charAt(0) >= 65 && el.charAt(0) <= 90); + } + } + + // check result could be empty + try { + if (!getOutputLines()[rows].equals("")) { + String[] result = getOutputLines()[rows].split(" "); + for (int i = 3; i < result.length; i++) { + assert (result[i].charAt(0) % 2 == remainder); + } + } + } catch (ArrayIndexOutOfBoundsException e) { + return; + } + } + + // free for adding new not valid cases in format Int, Int, String + private static Stream notValidCases() { + return Stream.of( + Arguments.of(-1, -2, "odd"), + Arguments.of(0, 0, "even"), + Arguments.of(1, 3, "omg"), + Arguments.of(1234, -2, "even") + ); + } + + @ParameterizedTest + @MethodSource("notValidCases") + void testNotValid(int rows, int columns, String strategy) { + setInput( + String.format( + "%d %d %s", + rows, columns, strategy + )); + rct.run(); + printOut(); + removeFromOutput("Input table length, table width, table strategy(even/odd): "); + assertEquals("Passed parameters should match the format [positive integer] [positive integer] [even|odd]", + getOutputLines()[0]); + } + + @Test + void testFormatCount() { + setInput("1 2 even 12even"); + + rct.run(); + printOut(); + removeFromOutput("Input table length, table width, table strategy(even/odd): "); + assertEquals("Passed parameters should match the format [positive integer] [positive integer] [even|odd]", + getOutputLines()[0]); + } + + @Test + void testEmpty() { + setInput(""); + + rct.run(); + printOut(); + removeFromOutput("Input table length, table width, table strategy(even/odd): "); + assertEquals("Passed parameters should match the format [positive integer] [positive integer] [even|odd]", + getOutputLines()[0]); + } + +} 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..cbae6c2d --- /dev/null +++ b/src/test/java/homework_2/traffic_light/TrafficLightTest.java @@ -0,0 +1,40 @@ +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.assertEquals; + +public class TrafficLightTest extends UnitBase { + + TrafficLight trafficLight = new TrafficLight(); + + public static Stream testCases() { + return Stream.of( + Arguments.of("0", "[1;92mGREEN\u001B[0m"), + Arguments.of("101", "[1;91mRED\u001B[0m"), + Arguments.of("121", "[1;92mGREEN\u001B[0m"), + Arguments.of("155", "[1;93mYELLOW\u001B[0m"), + Arguments.of("86399", "[1;93mYELLOW\u001B[0m"), + Arguments.of("86400", "The day is over"), + Arguments.of("anytext", "Only 1 non-negative integer is allowed as passed parameter"), + Arguments.of("-1", "Only 1 non-negative integer is allowed as passed parameter"), + Arguments.of("", "Only 1 non-negative integer is allowed as passed parameter") + ); + } + + @ParameterizedTest + @MethodSource("testCases") + void testFactorial(String in, String expected) { + setInput(in); + trafficLight.run(); + printOut(); + removeFromOutput("Please, input seconds gone from the day start: "); + assertEquals(expected, getOutputLines()[0]); + } + +} \ No newline at end of file diff --git a/src/test/java/homework_4/custom_annotation/ResourcesPathTest.java b/src/test/java/homework_4/custom_annotation/ResourcesPathTest.java new file mode 100644 index 00000000..72359d64 --- /dev/null +++ b/src/test/java/homework_4/custom_annotation/ResourcesPathTest.java @@ -0,0 +1,37 @@ +package homework_4.custom_annotation; + +import homework_4.custom_file_reader.CustomFileReader; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Constructor; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ResourcesPathTest { + + @Test + void testAnnotation() { + Constructor[] constructors = CustomFileReader.class.getConstructors(); + Constructor myConstructor = null; + for (Constructor constructor : constructors) { + if (constructor.isAnnotationPresent(ResourcesPath.class)) { + myConstructor = constructor; + break; + } + } + + if (myConstructor != null) { + String constructorType = "Empty constructor"; + if (myConstructor.getParameterCount() != 0) { + constructorType = "Constructor with parameters"; + } + System.out.println(constructorType + " in " + CustomFileReader.class.getSimpleName() + " class " + + "has annotation @" + ResourcesPath.class.getSimpleName()); + } else { + System.out.println("No annotated constructor found in " + CustomFileReader.class.getSimpleName()); + throw new AssertionError(); + } + assertTrue(myConstructor.isAnnotationPresent(ResourcesPath.class)); + } + +} 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..fdab46d9 --- /dev/null +++ b/src/test/java/homework_4/custom_file_reader/CustomFileReaderTest.java @@ -0,0 +1,113 @@ +package homework_4.custom_file_reader; + +import base.UnitBase; +import homework_4.custom_file_reader.utils.DirectoryScan; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.*; + +class CustomFileReaderTest extends UnitBase { + + CustomFileReader customFileReader = new CustomFileReader(); + String correctPath = "./src/main/resources/custom_file_reader/"; + String correctFileName = "file.txt"; + + @Test + void testValidRun1Method() { + customFileReader.run1(); + String result = getOutput(); + assertTrue(checkResult(result)); + } + + @Test + void testValidRun2Method() { + customFileReader.run2(); + String result = getOutput(); + assertTrue(checkResult(result)); + } + + @Test + void testValidRun3Method() { + customFileReader.run3(); + String result = getOutput(); + assertTrue(checkResult(result)); + } + + @Test + void testValidRun4Method() { + customFileReader.run4(); + String result = getOutput(); + assertTrue(checkResult(result)); + } + + @Test + void testNotExistingFileAsConstructorParameter() { + CustomFileReader cfr1 = new CustomFileReader(correctPath, "passwords.txt"); + String expected = "File " + "passwords.txt" + " not found at: " + correctPath; + cfr1.run1(); + String output = getOutput(); + assertEquals(expected, output); + } + + @Test + void testCorrectFileNameAndIncorrectFilePathAsConstuctorParameter() { + CustomFileReader cfr1 = new CustomFileReader("./src/", correctFileName); + String expected = "File " + correctFileName + " not found at: " + "./src/"; + cfr1.run4(); + String output = getOutput(); + assertEquals(expected, output); + } + + @Test + void testEmptyConstructor() { + new CustomFileReader(); + String notExpected = "File " + correctFileName + " not found at: " + correctPath; + assertNotEquals(notExpected, getOutput()); + } + + @Test + void testShowDirMethod() { + CustomFileReader cfr1 = new CustomFileReader(correctPath, correctFileName); + cfr1.showDir(); + String output = getOutput(); + + File directoryPath = new File(correctPath); + File[] filesList = directoryPath.listFiles(); + StringBuilder tmp = new StringBuilder(); + tmp.append(correctPath).append(" contains:").append("\n--- --- ---\n"); + assertNotNull(filesList); + for (File file : filesList) { + tmp + .append(file.getName()) + .append("\tat: ") + .append(file.getAbsolutePath()) + .append("\n") + .append("---") + .append("\n"); + } + tmp.append("--- --- ---"); + String expected = String.valueOf(tmp); + assertEquals(expected, output); + } + + @Test + void testEmptyDir() { + String hm3testDir = "./src/test/homework_3/"; + String expected = hm3testDir + " is empty!"; + DirectoryScan.scanDir(hm3testDir); + String output = getOutput(); + assertEquals(expected, output); + } + + @Test + void testIsInDir() { + assertTrue(DirectoryScan.isInDir(correctPath, correctFileName)); + } + + private boolean checkResult(String res) { + return !(res.contains(".") && res.contains(",")); + } + +} diff --git a/src/test/java/homework_4/singleton/SingletonMenuTest.java b/src/test/java/homework_4/singleton/SingletonMenuTest.java new file mode 100644 index 00000000..b6160bfe --- /dev/null +++ b/src/test/java/homework_4/singleton/SingletonMenuTest.java @@ -0,0 +1,16 @@ +package homework_4.singleton; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class SingletonMenuTest { + + @Test + void testCreatingInstancesOfSingletonClass() { + SingletonMenu expected = SingletonMenu.getInstance(); + SingletonMenu current = SingletonMenu.getInstance(); + assertSame(expected, current); + } + +} 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..1b73436b --- /dev/null +++ b/src/test/java/homework_5/custom_regex_matcher/CustomRegexMatcherTest.java @@ -0,0 +1,56 @@ +package homework_5.custom_regex_matcher; + +import base.UnitBase; +import org.junit.jupiter.api.Test; +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.*; + +class CustomRegexMatcherTest extends UnitBase { + + @Test + void testValidPhoneNumber() { + String expected = "true"; + setInput("+1 (267) 759-9000"); + CustomRegexMatcher.run(); + printOut(); + assertEquals(expected, getOutput()); + } + + @Test + void testValidUnicodeInputNumber() { + String expected = "true"; + setInput("\u002B\u0031 \u0028\u0032\u0036\u0037\u0029 \u0037\u0035\u0039\u002D\u0038\u0039\u0038\u0039"); + CustomRegexMatcher.run(); + printOut(); + assertEquals(expected, getOutput()); + } + + public static Stream incorrectPhoneNumbersFormats() { + return Stream.of( + Arguments.of("+9 (2902) 123-4567"), + Arguments.of("not number at all, ho-ho"), + Arguments.of("-2 (123) 456-7890"), + Arguments.of("(+1) (123) 456-7890"), + Arguments.of("_12345678901"), + Arguments.of("+1 234 567-8909"), + Arguments.of("+1 (3.14) 742-7580"), + Arguments.of("\u1F606") + ); + } + + @ParameterizedTest + @MethodSource("incorrectPhoneNumbersFormats") + void testSetOfIncorrectPhoneNumbersFormats(String input) { + String expected = "false"; + setInput(input); + CustomRegexMatcher.run(); + printOut(); + assertEquals(expected, getOutput()); + } + +} 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..47e7ac8f --- /dev/null +++ b/src/test/java/homework_5/power_of_number/PowerOfNumberTest.java @@ -0,0 +1,63 @@ +package homework_5.power_of_number; + +import base.UnitBase; +import org.junit.jupiter.api.Test; +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 { + + PowerOfNumber powerOfNumber = new PowerOfNumber(); + + private static final String ERROR = "Only 2 non-negative integers are allowed"; + + @Test + void testPowerWithValidInput() { + String expected = convertDoubleToIntAndReturnAsString(Math.pow(3, 5)); + setInput("3 5"); + powerOfNumber.run(); + printOut(); + removeFromOutput("Please, input the values in format: number power\n"); + assertEquals(expected, getOutputLines()[0]); + } + + @Test + void testPowerWithValidInput_ZeroPowerOfZero() { + String expected = convertDoubleToIntAndReturnAsString(Math.pow(0, 0)); + setInput("0 0"); + powerOfNumber.run(); + printOut(); + removeFromOutput("Please, input the values in format: number power\n"); + assertEquals(expected, getOutputLines()[0]); + } + + public static Stream incorrectInputs() { + return Stream.of( + Arguments.of(""), + Arguments.of("1 2 3 4 str"), + Arguments.of("1 "), + Arguments.of("1.93 2.47"), + Arguments.of("999999999999999999 999999999999999999") + ); + } + + @ParameterizedTest + @MethodSource("incorrectInputs") + void testIncorrectInputs_ErrorExpected(String incorrectInput) { + setInput(incorrectInput); + powerOfNumber.run(); + printOut(); + removeFromOutput("Please, input the values in format: number power\n"); + assertEquals(ERROR, getOutputLines()[0]); + } + + private String convertDoubleToIntAndReturnAsString(double value) { + return String.valueOf((int) (value)); + } + +} diff --git a/src/test/java/homework_7/kitten_to_cat/KittenToCatTest.java b/src/test/java/homework_7/kitten_to_cat/KittenToCatTest.java new file mode 100644 index 00000000..d9ac1eca --- /dev/null +++ b/src/test/java/homework_7/kitten_to_cat/KittenToCatTest.java @@ -0,0 +1,61 @@ +package homework_7.kitten_to_cat; + +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class KittenToCatTest { + + private static final String expected = Cat.class.getSimpleName(); + + @Test + void testKittenToCat() { + Kitten kitten = new Kitten("Joe Bezos", 3, "Amazonerre"); + KittenToCatFunction kittyFoo = kitten1 -> new Cat("Joseph Bezos", kitten.getAge() + 2); + Cat cat = kittyFoo.grow(kitten); + assertEquals(expected, cat.getClass().getSimpleName()); + } + + @Test + void testKittenInheritedToCatCast() { + + class JustBornKitten extends Kitten { + + private final LocalDate bornDate; + + public JustBornKitten(String name, int age, String breed) { + super(name, age, breed); + bornDate = LocalDate.now(); + } + + } + + JustBornKitten justBornKitten = new JustBornKitten("Billy", 0, "Microkitty"); + KittenToCatFunction kittyFoo = kitten -> new Cat("Bill Gates", justBornKitten.getAge() + 3); + Cat cat = kittyFoo.grow(justBornKitten); + assertEquals(expected, cat.getClass().getSimpleName()); + } + + @Test + void testKittenToInheritedCatCast() { + + class WildCat extends Cat { + + private final String location; + + public WildCat(String name, int age) { + super(name, age); + this.location = "Africa"; + } + + } + + Kitten kitty = new Kitten("Elon", 1, "Nikoleslie"); + KittenToCatFunction kittyFoo = kit -> new WildCat("Elon Mask", kitty.getAge() + 3); + WildCat wildCat = (WildCat) kittyFoo.grow(kitty); + assertEquals(wildCat.getClass().getSimpleName(), wildCat.getClass().getSimpleName()); + } + +}