diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fee91d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +*.iml +out/ diff --git a/lab-01/README.md b/lab-01/README.md deleted file mode 100644 index 6d1f516..0000000 --- a/lab-01/README.md +++ /dev/null @@ -1,408 +0,0 @@ -# Quizer library -В данной задаче вам предлагается разработать приложение для проверки знаний учеников. - -Приложение должно функционировать следующим образом. Учитель врывается в класс и решает провести плановую проверку знаний, большими буквами на доске пишет название теста. Обрадованные прекрасной новостью, ученики, в свою очередь, охотно открывают разработанное вами приложение и вводят в _CLI_ название теста. Затем они предположительно самостоятельно отвечают на все вопросы, и в конце им выводится оценка. - -# Архитектура приложения - ->Всю работу ведите в пакете `by.<ваш ник>.quizer` -## Базовые элементы - -### Result -```java -/** - * Enum, который описывает результат ответа на задание - */ -enum Result { - OK, // Получен правильный ответ - WRONG, // Получен неправильный ответ - INCORRECT_INPUT // Некорректный ввод. Например, текст, когда ожидалось число -} -``` - -### Task - -```java -/** - * Interface, который описывает одно задание - */ -interface Task { - /** - @return текст задания - */ - String getText(); - - /** - * Проверяет ответ на задание и возвращает результат - * - * @param answer ответ на задание - * @return результат ответа - * @see Result - */ - Result validate(String answer); -} -``` - -### TaskGenerator - -```java -/** - * Interface, который описывает один генератор заданий - */ -interface TaskGenerator { - /** - * Возвращает задание. При этом новый объект может не создаваться, если класс задания иммутабельный - * - * @return задание - * @see Task - */ - Task generate(); -} -``` - -### Quiz -```java -/** - * Class, который описывает один тест - */ -class Quiz { - /** - * @param generator генератор заданий - * @param taskCount количество заданий в тесте - */ - Quiz(TaskGenerator generator, int taskCount) { - // ... - } - - /** - * @return задание, повторный вызов вернет слелующее - * @see Task - */ - Task nextTask() { - // ... - } - - /** - * Предоставить ответ ученика. Если результат {@link Result#INCORRECT_INPUT}, то счетчик неправильных - * ответов не увеличивается, а {@link #nextTask()} в следующий раз вернет тот же самый объект {@link Task}. - */ - Result provideAnswer(String answer) { - // ... - } - - /** - * @return завершен ли тест - */ - boolean isFinished() { - // ... - } - - /** - * @return количество правильных ответов - */ - int getCorrectAnswerNumber() { - // ... - } - - /** - * @return количество неправильных ответов - */ - int getWrongAnswerNumber() { - // ... - } - - /** - * @return количество раз, когда был предоставлен неправильный ввод - */ - int getIncorrectInputNumber() { - // ... - } - - /** - * @return оценка, которая является отношением количества правильных ответов к количеству всех вопросов. - * Оценка выставляется только в конце! - */ - double getMark() { - // ... - } -} -``` - -## Функция main() - -### getQuizMap -Этот метод будет использоваться из `main()`, чтобы получить список доступных тестов. Создание всех тестов (`Quiz`) будет захардкожено в этом методе. После реализации разных TaskGenerator’ов (см. ниже), добавьте в этот метод несколько различных тестов. - -```java -/** - * @return тесты в {@link Map}, где - * ключ - название теста {@link String} - * значение - сам тест {@link Quiz} - */ -static Map getQuizMap() { - // ... -} -``` - -### public static void main() - -```java -public static void main() { - // ... -} -``` - ->`public static void main()` - входная точка вашего приложения. - -#### Описание - -Для начала, получите список всех тестов с помощью статической функции `getQuizMap()` и выведите пользователю сообщение _“Введите название теста...”_. Затем получите объект `Quiz` по этому названию, если он есть, иначе попросите повторить попытку. - -Пока тест не завершен, опрашивайте ученика (пользуйтесь методами реализованного вами класса `Quiz`). В конце выведите ему его отметку. - -## Реализация Task и TaskGenerator ->Реализации `Task` следует расположить в пакете `tasks`, а реализации `TaskGenerator` в пакете `task_generators`. - -`Task` и `TaskGenerator` - интерфейсы, теперь нужно сделать их реализации. -Все классы `*Task` реализуют интерфейс `Task`, а `*TaskGenerator` - интерфейс `TaskGenerator`. - - -### ExpressionTaskGenerator -Генерирует примеры вида `=`. Например, `2*5=?`. - -```java -class ExpressionTaskGenerator implements TaskGenerator { - /** - * @param minNumber минимальное число - * @param maxNumber максимальное число - * @param generateSum разрешить генерацию с оператором + - * @param generateDifference разрешить генерацию с оператором - - * @param generateMultiplication разрешить генерацию с оператором * - * @param generateDivision разрешить генерацию с оператором / - */ - ExpressionTaskGenerator( - int minNumber, - int maxNumber, - boolean generateSum, - boolean generateDifference, - boolean generateMultiplication, - boolean generateDivision - ) { - // ... - } - - /** - * return задание типа {@link ExpressionTask} - */ - ExpressionTask generate() { - // ... - } -} -``` - -### EquationTaskGenerator -Генерирует уравнения вида `x=` и `x=`. Например, `x/2=6`. - -```java -class EquationTaskGenerator implements TaskGenerator { - /** - * @param minNumber минимальное число - * @param maxNumber максимальное число - * @param generateSum разрешить генерацию с оператором + - * @param generateDifference разрешить генерацию с оператором - - * @param generateMultiplication разрешить генерацию с оператором * - * @param generateDivision разрешить генерацию с оператором / - */ - EquationTaskGenerator( - int minNumber, - int maxNumber, - boolean generateSum, - boolean generateDifference, - boolean generateMultiplication, - boolean generateDivision - ) { - // ... - } - - /** - * return задание типа {@link EquationTask} - */ - EquationTask generate() { - // ... - } -} -``` - -### GroupTaskGenerator -`TaskGenerator`, который позволяет объединить несколько других `TaskGenerator`. - -```java -class GroupTaskGenerator implements TaskGenerator { - /** - * Конструктор с переменным числом аргументов - * - * @param generators генераторы, которые в конструктор передаются через запятую - */ - GroupTaskGenerator(TaskGenerator... generators) { - // ... - } - - /** - * Конструктор, который принимает коллекцию генераторов - * - * @param generators генераторы, которые передаются в конструктор в Collection (например, {@link ArrayList}) - */ - GroupTaskGenerator(Collection generators) { - // ... - } - - /** - * @return результат метода generate() случайного генератора из списка. - * Если этот генератор выбросил исключение в методе generate(), выбирается другой. - * Если все генераторы выбрасывают исключение, то и тут выбрасывается исключение. - */ - Task generate() { - // ... - } -} -``` - -### PoolTaskGenerator -`TaskGenerator`, который отдает задания из заранее заготовленного набора. - -```java -class PoolTaskGenerator implements TaskGenerator { - /** - * Конструктор с переменным числом аргументов - * - * @param allowDuplicate разрешить повторения - * @param tasks задания, которые в конструктор передаются через запятую - */ - PoolTaskGenerator( - boolean allowDuplicate, - Task... tasks - ) { - // ... - } - - /** - * Конструктор, который принимает коллекцию заданий - * - * @param allowDuplicate разрешить повторения - * @param tasks задания, которые передаются в конструктор в Collection (например, {@link LinkedList}) - */ - PoolTaskGenerator( - boolean allowDuplicate, - Collection tasks - ) { - // ... - } - - /** - * @return случайная задача из списка - */ - Task generate() { - // ... - } -} -``` - -### TextTask - -```java -/** - * Задание с заранее заготовленным текстом. - * Можно использовать {@link PoolTaskGenerator}, чтобы задавать задания такого типа. - */ -class TextTask implements Task { - /** - * @param text текст задания - * @param answer ответ на задание - */ - TextTask( - String text, - String answer - ) { - // ... - } - - // ... -} -``` - -## Добавляем абстракций -Для всего в этом пункте следует сделать пакет `math_tasks` в пакете `tasks` и `math_task_generators` в пакете `task_genertors`. - -Сейчас `ExpressionTask` и `EquationTask` наследуются напрямую от `Task`. Введем несколько абстракций, чтобы вынести общую логику из этих двух классов. - ->Описывывается иерархия для `Task`, такую же нужно повторить для `TaskGenerator` - -Сделайте интерфейс `MathTask`, который расширяет интерфейс `Task`. Сделайте абстрактный класс `AbstractMathTask`, который реализует интерфейс `MathTask`. Далее сделайте, чтобы классы `ExpressionMathTask` и `EquationMathTask` наследовались от `AbstractMathTask`. - -Перенесите обшую логику из `ExpressionMathTask` и `EquationMathTask` в `AbstractMathTask`. - -Добавьте в интерфейс MathTaskGenerator методы: -```java -int getMinNumber(); // получить минимальное число -int getMaxNumber(); // получить максимальное число -``` - -Добавьте в интерфейс `MathTaskGenerator` **default** метод: -```java -/** - * @return разница между максимальным и минимальным возможным числом - */ -default int getDiffNumber(); -``` - -## ★ EnumSet - -Сейчас сигнатуры `ExpressionTaskGenerator` и `EquationTaskGenerator` выглядят не очень красиво, приходится передавать туда 4 була для каждого оператора. Сделайте `enum Operation` внутри интерфейса `MathTask` и передавайте в `ExpressionTaskGenerator` и `EquationTaskGenerator` вместо булов `EnumSet`. - ->https://www.baeldung.com/java-enumset - -## Generator как nested class в Task★ - -Сейчас вся иерархия `Task` дублируется и для `Generator` в отдельном пакете, это не очень хорошая практика, т. к. за таким кодом сложно следить. Давайте сделаем все `Generator`'ы внутреннеми классами в соответствующих `Task`. Например, вместо `ExpressionTaskGenerator` будет `ExpressionTask.Generator`. При этом `GroupTaskGenerator` и `PoolTaskGenerator` остануться в отдельном пакете, т.к. они не привязаны к конкретному типу задачи. - -```java -interface Task { - interface Generator { /* ... */ } - // ... -} - -interface MathTask extends Task { - interface Generator extends Task.Generator { /* ... */ } - // ... -} - -abstract class AbstractMathTask implements Task { - static abstract class Generator implements MathTask.Generator { /* ... */ } - // ... -} - -class ExpressionTask extends AbstractMathTask { - static class Generator extends AbstractMathTask.Generator { /* ... */ } - // ... -} - -class EquationTask extends AbstractMathTask { - static class Generator extends AbstractMathTask.Generator { /* ... */ } - // ... -} -``` - -## ★ Real ExpressionTask и EquationTask -Сделайте, чтобы `ExpressionTaskGenerator` и `EquationTaskGenerator` работал с double вместо int. Также нужно изменить сигнатуру в методах `getMinNumber()`, `getMaxNumnber()`, `getDiffNumber` интерфейса `MathTask`, чтобы они возвращали double. - -Добавьте в `ExpressionTaskGenerator` и `EquationTaskGenerator` конструктор, который после `maxNumber` принимает еще `int precision` - количество знаков после запятой в генерируемых числах. В других конструкторах считается, что `precision = 0`, т.e. генерируются только целые числа. - ->★★ Учитывайте precision еще и в ответе - -## ★★ UML -В каком-нибудь онлайн UML-редакторе (если очень хочется, можно и в пеинте) сделайте схему с участием всех интерфейсов и классов. Это схему нужно приложить в AnyTask к ссылке на github. -## Добавляем исключения -Добавьте исключения везде, где это необходимо. Например, когда у `Quiz` вызывается метод `getMark()`, пока тест не завершен или в конструктор `*MathTask` `maxNumber` передается меньше, чем `minNumber`, в `precision` передается некорректное число и т.д. В случае некорректных `minNumber`, `maxNumber`, `precision` уместно использовать `IllegalArgumentException`, для раннего вызова `getMark()` стоит сделать свое исключение, назвать `QuizNotFinishedException`. Все свои исключения стоит создавать в пакете `exceptions`. -## Добавляем тесты (Quiz) и проверяем - -Теперь добавьте в метод `getQuizMap()` тестов (минимум 5) и тщательно протестируйте приложение. Обязательно используйте все созданные классы, постарайтесь придумать свои `TaskGenerator`. Например, который генерирует задания вида _"У **A** было X яблок, он(она) подарил(а) **B** Y яблок. Сколько яблок осталось у **A**?"_. diff --git a/lab-02/config.json b/lab-02/config.json new file mode 100644 index 0000000..007fd09 --- /dev/null +++ b/lab-02/config.json @@ -0,0 +1,72 @@ +{ + "generator" : { + "generating_time": 500 + }, + "cargo_types" : ["1", "2", "3", "4"], + "ingredients_count" : [6, 4, 2, 5], + "eating_time": 500, + "ships" : [ + { + "capacity" : 160, + "cargo_type" : "2" + }, + { + "capacity" : 200, + "cargo_type" : "1" + }, + { + "capacity" : 130, + "cargo_type" : 2 + }, + { + "capacity" : 180, + "cargo_type" : 3 + }, + { + "capacity" : 93, + "cargo_type" : "1" + }, + { + "capacity" : 111, + "cargo_type" : "4" + }, + { + "capacity" : 211, + "cargo_type" : 2 + } + ], + "tunnel": { + "max_size" : 4 + }, + "docs": [ + { + "unloading_speed" : 40, + "dock_capacity": [160, 200, 180, 100] + }, + { + "unloading_speed" : 28, + "dock_capacity": [260, 100, 280, 300] + }, + { + "unloading_speed" : 33, + "dock_capacity": [230, 150, 220, 176] + } + ], + "hobos": [ + { + "stealing_time": 100 + }, + { + "stealing_time": 200 + }, + { + "stealing_time": 300 + }, + { + "stealing_time": 200 + }, + { + "stealing_time": 400 + } + ] +} diff --git a/lab-02/src/Dock.java b/lab-02/src/Dock.java new file mode 100644 index 0000000..91d172e --- /dev/null +++ b/lab-02/src/Dock.java @@ -0,0 +1,49 @@ +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicLong; + +public class Dock implements Runnable { + static final Object lock = new Object(); + long unloading_speed; + final long[] dock_capacity; + final AtomicLong[] curr_dock_capacities; + @Override + public void run() { + try { + while (!Thread.currentThread().isInterrupted()) { + synchronized (lock) { + lock.wait(); + } + Ship ship = Tunnel.tunnel.poll(); + if (ship != null) { + Tunnel.tunnel_size.getAndDecrement(); + System.out.println(ship + " is unloading"); + long type = ship.cargo_type; + long capacity = Math.min(ship.capacity, dock_capacity[(int) type] - curr_dock_capacities[(int) type].get()); + Thread.sleep((long) ((double) capacity / unloading_speed * 1000)); + System.out.println("Capacity: " + capacity + " of type: " + type + " was unloaded"); + curr_dock_capacities[(int) type].addAndGet(capacity); + ship.capacity -= capacity; + System.out.println(ship + ", unloading is end"); + synchronized (ship.lock) { + ship.lock.notify(); + } + } + } + } catch (InterruptedException e) { + System.out.println("Oops Dock"); + Thread.currentThread().interrupt(); + } + } + + Dock(long unloading_speed, long[] dock_capacity) { + if (dock_capacity.length != Ship.cargo_types.length) { + throw new IllegalArgumentException("Incorrect length of dock_capacities"); + } + this.unloading_speed = unloading_speed; + this.dock_capacity = Arrays.copyOf(dock_capacity, dock_capacity.length); + curr_dock_capacities = new AtomicLong[dock_capacity.length]; + for (int i = 0; i < dock_capacity.length; ++i) { + curr_dock_capacities[i] = new AtomicLong(0); + } + } +} diff --git a/lab-02/src/Generator.java b/lab-02/src/Generator.java new file mode 100644 index 0000000..a0b0b44 --- /dev/null +++ b/lab-02/src/Generator.java @@ -0,0 +1,32 @@ +import org.json.simple.JSONObject; +import org.json.simple.JSONArray; + +public class Generator implements Runnable{ + + JSONObject jo; + static int generate(long number) { + return (int) (Math.random() * number); + } + Generator(JSONObject jo) { this.jo = jo; } + + @Override + public void run() { + long generating_time = (long) ((JSONObject) jo.get("generator")).get("generating_time"); + JSONArray ships = (JSONArray) jo.get("ships"); + for (Object o : ships) { + JSONObject ship = (JSONObject) o; + Object cargo_type = ship.get("cargo_type"); + if (cargo_type.getClass() == String.class) { + Main.ships.add(new Ship((long) ship.get("capacity"), (String) cargo_type)); + } else { + Main.ships.add(new Ship((long) ship.get("capacity"), (long) cargo_type)); + } + try { + Thread.sleep(generating_time); + } catch (InterruptedException e) { + System.out.println("Generator stopped"); + Thread.currentThread().interrupt(); + } + } + } +} diff --git a/lab-02/src/Hobos.java b/lab-02/src/Hobos.java new file mode 100644 index 0000000..1ab3c87 --- /dev/null +++ b/lab-02/src/Hobos.java @@ -0,0 +1,97 @@ +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +public class Hobos implements Runnable{ + static long eating_time; + long stealing_time; + + static long eat = 0; + + static long ID = 0; + long ID_; + + static long[] ingredients_count; + static AtomicLong[] curr_ingredients_count; + + static boolean check_ingridients() { + for (int i = 0; i < curr_ingredients_count.length; ++i) { + if (curr_ingredients_count[i].get() < ingredients_count[i]) { + return false; + } + } + return true; + }; + static void steal() { + long hobos_num = Main.hobos.size(); + ArrayList hobos_threads = new ArrayList<>(); + for(long i = 0; i < hobos_num - 2; ++i) { + hobos_threads.add(new Thread()); + } + + while(!Thread.currentThread().isInterrupted()) { + long a, b; + a = Generator.generate(hobos_num); + b = Generator.generate(hobos_num); + while (a == b) { + b = Generator.generate(hobos_num); + } + System.out.println("Start to steal!!!"); + for(int i = 0, j = 0, size = Main.hobos.size(); i < size; ++i) { + if (i != a && i != b) { + hobos_threads.set(j, new Thread(Main.hobos.get(i))); + hobos_threads.get(j).start(); + ++j; + } + } + while (!check_ingridients()) {} + System.out.println("Time to eat!!!"); + ++eat; + for (var thread : hobos_threads) { + thread.interrupt(); + } + for (int i = 0; i < curr_ingredients_count.length; ++i) { + curr_ingredients_count[i].set(0); + } + try { + Thread.sleep(eating_time); + } catch (InterruptedException e) { + System.out.println("Oops Hobos"); + Thread.currentThread().interrupt(); + } + } + + } + + @Override + public void run() { + System.out.println("Start stole " + this); + while (!Thread.currentThread().isInterrupted()) { + int ing = Generator.generate(ingredients_count.length); + Dock dock = Main.docs.get(Generator.generate(Main.docs.size())); + while (curr_ingredients_count[ing].get() < ingredients_count[ing] && + dock.curr_dock_capacities[ing].get() > 0 && + !Thread.currentThread().isInterrupted()) { + curr_ingredients_count[ing].getAndIncrement(); + dock.curr_dock_capacities[ing].getAndDecrement(); + try { + Thread.sleep(stealing_time); + } catch (InterruptedException e) { + System.out.println("Oops Hobos"); + Thread.currentThread().interrupt(); + } + } + } + System.out.println("End stole " + this); + } + + Hobos(long stealing_time) { + this.stealing_time = stealing_time; + ID_ = ++ID; + } + + @Override + public String toString() { + return "Hobos: {" + ID_ + "}"; + } +} diff --git a/lab-02/src/Main.java b/lab-02/src/Main.java new file mode 100644 index 0000000..a3a5987 --- /dev/null +++ b/lab-02/src/Main.java @@ -0,0 +1,116 @@ +import org.json.simple.JSONObject; +import org.json.simple.JSONArray; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicLong; + +public class Main { + static double eps = 1e-6; + static ArrayList ships = new ArrayList<>(); + static ArrayList docs = new ArrayList<>(); + static ArrayList hobos = new ArrayList<>(); + public static void main(String[] args) { + try { + Object obj = new JSONParser().parse(new FileReader(args[0])); + JSONObject jo = (JSONObject) obj; + + JSONObject jtunnel = (JSONObject) jo.get("tunnel"); + Tunnel tunnel = new Tunnel(((Long) jtunnel.get("max_size")).intValue()); + + JSONArray jcargo_types = (JSONArray) jo.get("cargo_types"); + int size = jcargo_types.size(); + Ship.cargo_types = new String[size]; + for (int i = 0; i < size; ++i) { + Ship.cargo_types[i] = (String) jcargo_types.get(i); + } + + Thread generator = new Thread(new Generator(jo)); + generator.start(); + + JSONArray jdocs = (JSONArray) jo.get("docs"); + for (Object o: jdocs) { + JSONObject jdock = (JSONObject) o; + JSONArray jdock_capacity = (JSONArray) jdock.get("dock_capacity"); + size = jdock_capacity.size(); + long[] dock_capacity = new long[size]; + for (int i = 0; i < size; ++i) { + dock_capacity[i] = (long) jdock_capacity.get(i); + } + + docs.add(new Dock((long) jdock.get("unloading_speed"), dock_capacity)); + } + + Hobos.eating_time = (long) jo.get("eating_time"); + + JSONArray jingredients_count = (JSONArray) jo.get("ingredients_count"); + size = jingredients_count.size(); + Hobos.ingredients_count = new long[size]; + Hobos.curr_ingredients_count = new AtomicLong[size]; + for (int i = 0; i < size; ++i) { + Hobos.ingredients_count[i] = (long) jingredients_count.get(i); + Hobos.curr_ingredients_count[i] = new AtomicLong(0); + } + JSONArray jhobos = (JSONArray) jo.get("hobos"); + for (Object o : jhobos) { + JSONObject jhobo = (JSONObject) o; + hobos.add(new Hobos((long) jhobo.get("stealing_time"))); + } + + ArrayList ship_threads = new ArrayList<>(); + ArrayList dock_threads = new ArrayList<>(); + + size = docs.size(); + for (int i = 0; i < size; ++i) { + dock_threads.add(new Thread(docs.get(i))); + dock_threads.get(i).start(); + } + + Thread process = new Thread(tunnel::process); + Thread hobos = new Thread(Hobos::steal); + process.start(); + hobos.start(); + + size = ships.size(); + for (int i = 0; i < size || generator.isAlive(); size = ships.size()) { + if (i < size) { + int finalI = i; + ship_threads.add(new Thread(() -> { + tunnel.enter(ships.get(finalI)); + })); + ship_threads.get(finalI).start(); + ++i; + } + } + + for (var thread : ship_threads) { + try { + thread.join(); + } catch (InterruptedException exc) { + System.out.println("Oops"); + } + } + + process.interrupt(); + + for (var thread : dock_threads) { + thread.interrupt(); + } + + hobos.interrupt(); + + System.out.println("Interupted"); + for (var dock : docs) { + System.out.println(Arrays.toString(dock.curr_dock_capacities)); + } + System.out.println(Hobos.eat); + } catch (IOException | ParseException exc) { + System.out.println("Oops"); + } + } +} \ No newline at end of file diff --git a/lab-02/src/Ship.java b/lab-02/src/Ship.java new file mode 100644 index 0000000..31084b6 --- /dev/null +++ b/lab-02/src/Ship.java @@ -0,0 +1,85 @@ +import java.util.Arrays; +import java.util.Objects; + +public class Ship { + static long ship_capacity_min = 0; + static long ship_capacity_max = 500; + + static long ID = 0; + long ID_; + + final Object lock = new Object(); + + long capacity = ship_capacity_min; + final long cargo_type; + static String[] cargo_types; + + Ship(long cargo_type) { + if (cargo_type >= cargo_types.length) { + throw new IllegalArgumentException("Index bound error"); + } + this.cargo_type = cargo_type; + ID_ = ++ID; + } + Ship(String cargo_type) { + for (int i = 0; i < cargo_types.length; ++i) { + if (cargo_types[i].equals(cargo_type)) { + this.cargo_type = i; + ID_ = ++ID; + return; + } + } + throw new IllegalArgumentException("Unexist type"); + } + + Ship(long capacity, long cargo_type) { + this(cargo_type); + if (capacity < ship_capacity_min || capacity > ship_capacity_max) { + throw new IllegalArgumentException("You enter incorrect amount of capacity"); + } + this.capacity = capacity; + } + Ship(long capacity, String cargo_type) { + this(cargo_type); + if (capacity < ship_capacity_min || capacity > ship_capacity_max) { + throw new IllegalArgumentException("You enter incorrect amount of capacity"); + } + this.capacity = capacity; + } + + @Override + public String toString() { + return "Ship: {" + + " ID: " + ID_ + + " Type: " + cargo_types[(int) cargo_type] + + " Capacity: " + capacity + + "}"; + } +} + +// static void setShipCapacityMin(double min) { +// if (min < -Main.eps) { +// throw new IllegalArgumentException("Capacity can't be negative"); +// } +// ship_capacity_min = min; +// } +// +// void setCapacity(double capacity, boolean isUnloaded) { +// if (capacity < (isUnloaded ? 0 : ship_capacity_min) - Main.eps) { +// throw new IllegalArgumentException("You enter incorrect capacity"); +// } +// this.capacity = capacity; +// } +// double getShipCapacityMax() { return ship_capacity_max; } +// double getShipCapacityMin() { return ship_capacity_min; } +// +// long getCargoType() { return cargo_type; } +// long getID() { return ID; } +// +// double getCapacity() { return capacity; } +//static void setShipCapacityMax(long max) { +// if (max - ship_capacity_min < -Main.eps) { +// throw new IllegalArgumentException("Max capacity can't be less than min capacity"); +// } +// ship_capacity_max = max; +//} diff --git a/lab-02/src/Tunnel.java b/lab-02/src/Tunnel.java new file mode 100644 index 0000000..c8f85c4 --- /dev/null +++ b/lab-02/src/Tunnel.java @@ -0,0 +1,40 @@ +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; + +public class Tunnel { + long max_ships; + static final ConcurrentLinkedQueue tunnel = new ConcurrentLinkedQueue<>(); + static final AtomicInteger tunnel_size = new AtomicInteger(0); + Tunnel(long max_ships) { + this.max_ships = max_ships; + } + + void enter(Ship ship) { + if (tunnel_size.get() < max_ships) { + tunnel_size.getAndIncrement(); + System.out.println(ship + " entered in tunnel"); + tunnel.add(ship); + try { + synchronized (ship.lock) { + ship.lock.wait(); + } + } catch (InterruptedException e) { + System.out.println("Oops"); + Thread.currentThread().interrupt(); + } + } else { + System.out.println(ship + " sinked"); + } + System.out.println("Work Ended"); + } + void process() { + while (!Thread.currentThread().isInterrupted()) { + if (!tunnel.isEmpty()) { + synchronized (Dock.lock) { + Dock.lock.notify(); + } + } + } + } + +}