diff --git a/lab-02/by/mnik0_0/docks_and_hobos/Dock.java b/lab-02/by/mnik0_0/docks_and_hobos/Dock.java new file mode 100644 index 0000000..cdfacbf --- /dev/null +++ b/lab-02/by/mnik0_0/docks_and_hobos/Dock.java @@ -0,0 +1,84 @@ +package by.mnik0_0.docks_and_hobos; + +import java.util.ArrayList; +import java.util.HashMap; +import static java.lang.Math.min; + +public class Dock implements Runnable { + private final int unloadingSpeed; + private final int dockCapacity; + private final HashMap goods = new HashMap<>(); + private Tunnel tunnel; + private String name; + + public String getName() { + return name; + } + + public Dock(int unloadingSpeed, int dockCapacity, Tunnel tunnel, String name, ArrayList types) { + this.unloadingSpeed = unloadingSpeed; + this.dockCapacity = dockCapacity; + this.tunnel = tunnel; + this.name = name; + for (String type: types) { + goods.put(type, 0); + } + } + + public int getUnloadingSpeed() { + return unloadingSpeed; + } + + public int getDockCapacity() { + return dockCapacity; + } + + public synchronized boolean getGoodByType(String type) { + int count = goods.get(type); + if (count == 0) { + return false; + } + goods.put(type, count - 1); + return true; + } + + @Override + public void run() { + while (true) { + Ship ship = tunnel.getShipFromTunnel(this); + + if (ship == null) { + continue; + } + + double timeInSeconds = ship.getCapacity() / (double) unloadingSpeed; + try { + Thread.sleep((long) (timeInSeconds * 1000L)); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + int capacity = ship.getCapacity(); + String type = ship.getCargoType(); + synchronized (goods) { + int capacityInDocks = goods.get(type); + int tmpResult = capacityInDocks + capacity; + int result = min(tmpResult, dockCapacity); + int delta = tmpResult - result; + if (delta > 0) { + System.out.printf("We lose in %s - %s %d%n", name, type, delta); + } + goods.put(type, result); + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("------------------------\n"); + stringBuilder.append(name).append("\n"); + for (String t: goods.keySet()) { + stringBuilder.append(t).append(" ").append(goods.get(t)).append("\n"); + } + stringBuilder.append("------------------------\n"); + System.out.println(stringBuilder); + } + } + } +} diff --git a/lab-02/by/mnik0_0/docks_and_hobos/HoboGroup.java b/lab-02/by/mnik0_0/docks_and_hobos/HoboGroup.java new file mode 100644 index 0000000..3b0f1da --- /dev/null +++ b/lab-02/by/mnik0_0/docks_and_hobos/HoboGroup.java @@ -0,0 +1,102 @@ +package by.mnik0_0.docks_and_hobos; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Random; + +public class HoboGroup implements Runnable { + private HashMap ingredientsCount; + private HashMap ingredientsWeNeed; + private ArrayList types = new ArrayList<>(); + private int hobos; + private final Dock dock; + private Random random = new Random(); + int stealingTime; + int eatingTime; + int startIndex; + + public HoboGroup(HashMap ingredientsCount, int hobos, Dock dock, int stealingTime, int eatingTime) { + this.ingredientsCount = ingredientsCount; + this.hobos = hobos; + this.dock = dock; + this.ingredientsWeNeed = new HashMap<>(ingredientsCount); + this.types.addAll(ingredientsCount.keySet()); + this.stealingTime = stealingTime; + this.eatingTime = eatingTime; + } + + public String getTypeToSteal() { + int currentIndex = startIndex; + startIndex = (startIndex + 1) % types.size(); + int counter = 0; + + while (counter < types.size()) { + String type = types.get(currentIndex); + int count = ingredientsWeNeed.get(type); + if (count != 0) { + ingredientsWeNeed.put(type, count - 1); + return type; + } + counter++; + currentIndex = (currentIndex + 1) % types.size(); + } + + return null; + } + + public boolean readyToCook() { + for (int counter : ingredientsWeNeed.values()) { + if (counter != 0) { + return false; + } + } + return true; + } + + @Override + public void run() { + + while (true) { + + int workers = hobos - 2; + + for (int i = 0; i < workers; i++) { + String type = getTypeToSteal(); + if (type == null) { + continue; + } + if (!dock.getGoodByType(type)) { + + int count = ingredientsWeNeed.get(type); + ingredientsWeNeed.put(type, count + 1); + } + } + + try { + Thread.sleep(stealingTime * 1000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("------------------------\n"); + stringBuilder.append("hobos in ").append(dock.getName()).append("\n"); + for (String t: ingredientsWeNeed.keySet()) { + stringBuilder.append(t).append(" ").append(ingredientsWeNeed.get(t)).append("/").append(ingredientsCount.get(t)).append("\n"); + } + stringBuilder.append("------------------------\n"); + System.out.println(stringBuilder); + + if (readyToCook()) { + System.out.printf("Eating in %s%n", dock.getName()); + try { + Thread.sleep(eatingTime * 1000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + ingredientsWeNeed = new HashMap<>(ingredientsCount); + } + } + + } +} diff --git a/lab-02/by/mnik0_0/docks_and_hobos/Program.java b/lab-02/by/mnik0_0/docks_and_hobos/Program.java new file mode 100644 index 0000000..ae6297b --- /dev/null +++ b/lab-02/by/mnik0_0/docks_and_hobos/Program.java @@ -0,0 +1,129 @@ +package by.mnik0_0.docks_and_hobos; + +import com.google.gson.Gson; +import com.google.gson.annotations.SerializedName; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + + +class RootObject { + class Tunnel { + @SerializedName("maxShips") + public int maxShips; + } + + class ShipGenerator { + @SerializedName("generatingTime") + public int generatingTime; + + @SerializedName("shipCapacityMin") + public int shipCapacityMin; + + @SerializedName("shipCapacityMax") + public int shipCapacityMax; + } + + class Dock { + + class HoboGroup { + @SerializedName("hobos") + public int hobos; + + @SerializedName("stealingTime") + public int stealingTime; + + @SerializedName("eatingTime") + public int eatingTime; + + @SerializedName("ingredients") + public HashMap ingredients; + } + + @SerializedName("unloadingSpeed") + public int unloadingSpeed; + + @SerializedName("dockCapacity") + public int dockCapacity; + + @SerializedName("name") + public String name; + + @SerializedName("hoboGroup") + public HoboGroup hoboGroup; + } + + @SerializedName("types") + public String[] types; + + @SerializedName("tunnel") + public Tunnel tunnel; + + @SerializedName("shipGenerator") + public ShipGenerator shipGenerator; + + @SerializedName("docks") + public Dock[] docks; +} + + +public class Program { + public static void main(String[] args) { + + Gson gson = new Gson(); + RootObject rootObject; + try { + FileReader reader = new FileReader("lab-02/by/mnik0_0/docks_and_hobos/config.json"); + rootObject = gson.fromJson(reader, RootObject.class); + } catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + // TUNNEL + Tunnel tunnel = new Tunnel(rootObject.tunnel.maxShips); + + // SHIP GENERATOR + int generatingTime = rootObject.shipGenerator.generatingTime; + int shipCapacityMin = rootObject.shipGenerator.shipCapacityMin; + int shipCapacityMax = rootObject.shipGenerator.shipCapacityMax; + ArrayList cargoTypes = new ArrayList<>( + List.of(rootObject.types) + ); + + ShipGenerator shipGenerator = new ShipGenerator(generatingTime, shipCapacityMin, shipCapacityMax, cargoTypes, tunnel); + + // DOCKS AND GROUPS + ArrayList docks = new ArrayList<>(); + ArrayList hoboGroups = new ArrayList<>(); + for (RootObject.Dock d: rootObject.docks) { + int unloadingSpeed = d.unloadingSpeed; + int dockCapacity = d.dockCapacity; + String name = d.name; + Dock dock = new Dock(unloadingSpeed, dockCapacity, tunnel, name, cargoTypes); + docks.add(dock); + + HashMap ingredientsCount = d.hoboGroup.ingredients; + int hobos = d.hoboGroup.hobos; + int stealingTime = d.hoboGroup.stealingTime; + int eatingTime = d.hoboGroup.eatingTime; + HoboGroup group = new HoboGroup(ingredientsCount, hobos, dock, stealingTime, eatingTime); + hoboGroups.add(group); + } + + Thread shipGeneratorThread = new Thread(shipGenerator); + shipGeneratorThread.start(); + + for (Dock dock: docks) { + Thread dockThread = new Thread(dock); + dockThread.start(); + } + + for (HoboGroup hoboGroup: hoboGroups) { + Thread hoboGroupThread = new Thread(hoboGroup); + hoboGroupThread.start(); + } + + } +} diff --git a/lab-02/by/mnik0_0/docks_and_hobos/Ship.java b/lab-02/by/mnik0_0/docks_and_hobos/Ship.java new file mode 100644 index 0000000..1c66b1f --- /dev/null +++ b/lab-02/by/mnik0_0/docks_and_hobos/Ship.java @@ -0,0 +1,29 @@ +package by.mnik0_0.docks_and_hobos; + +public class Ship { + private final int capacity; + private final String cargoType; + private String name; + + public String getName() { + return name; + } + + public Ship(int capacity, String cargoType, String name) { + this.capacity = capacity; + this.cargoType = cargoType; + this.name = name; + } + + public int getCapacity() { + return capacity; + } + + public String getCargoType() { + return cargoType; + } + + public void sink() { + System.out.printf("Ship sunk %s%n", name); + } +} diff --git a/lab-02/by/mnik0_0/docks_and_hobos/ShipGenerator.java b/lab-02/by/mnik0_0/docks_and_hobos/ShipGenerator.java new file mode 100644 index 0000000..02957ec --- /dev/null +++ b/lab-02/by/mnik0_0/docks_and_hobos/ShipGenerator.java @@ -0,0 +1,44 @@ +package by.mnik0_0.docks_and_hobos; + +import java.util.ArrayList; +import java.util.Random; + +public class ShipGenerator implements Runnable { + private int generatingTime; + private int shipCapacityMin; + private int shipCapacityMax; + private Tunnel tunnel; + private final ArrayList cargoTypes; + private final Random random = new Random(); + + public ShipGenerator(int generatingTime, int shipCapacityMin, int shipCapacityMax, ArrayList cargoTypes, Tunnel tunnel) { + this.generatingTime = generatingTime; + this.shipCapacityMin = shipCapacityMin; + this.shipCapacityMax = shipCapacityMax; + this.cargoTypes = cargoTypes; + this.tunnel = tunnel; + } + + @Override + public void run() { + int name = 0; + while (true) { + int capacity = random.nextInt(shipCapacityMax - shipCapacityMin + 1) + shipCapacityMin; + + int cargoId = random.nextInt(cargoTypes.size()); + + Ship ship = new Ship( + capacity, + cargoTypes.get(cargoId), + String.valueOf(name) + ); + name++; + tunnel.enterTunnel(ship); + try { + Thread.sleep(generatingTime * 1000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} diff --git a/lab-02/by/mnik0_0/docks_and_hobos/Tunnel.java b/lab-02/by/mnik0_0/docks_and_hobos/Tunnel.java new file mode 100644 index 0000000..a803e6a --- /dev/null +++ b/lab-02/by/mnik0_0/docks_and_hobos/Tunnel.java @@ -0,0 +1,42 @@ +package by.mnik0_0.docks_and_hobos; + +import java.util.ArrayDeque; +import java.util.Deque; + +public class Tunnel { + private final int maxShips; + private Deque shipsInTunnel; + + public Tunnel(int maxShips) { + this.maxShips = maxShips; + this.shipsInTunnel = new ArrayDeque<>(); + } + + public synchronized void enterTunnel(Ship ship) { + if (maxShips <= shipsInTunnel.size()) { + ship.sink(); + return; + } + System.out.printf("enter the tunnel %s%n", ship.getName()); + + shipsInTunnel.add(ship); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("------------------------\n"); + stringBuilder.append("TUNNEL\n"); + for (Ship s: shipsInTunnel) { + stringBuilder.append(s.getName()).append(" ").append(s.getCargoType()).append(" ").append(s.getCapacity()).append("\n"); + } + stringBuilder.append("------------------------\n"); + System.out.println(stringBuilder); + } + + public synchronized Ship getShipFromTunnel(Dock dock) { + if (shipsInTunnel.isEmpty()) { + return null; + } + Ship ship = shipsInTunnel.pop(); + System.out.printf("leave the tunnel %s%n", ship.getName()); + + return ship; + } +} diff --git a/lab-02/by/mnik0_0/docks_and_hobos/config.json b/lab-02/by/mnik0_0/docks_and_hobos/config.json new file mode 100644 index 0000000..e9049b9 --- /dev/null +++ b/lab-02/by/mnik0_0/docks_and_hobos/config.json @@ -0,0 +1,56 @@ +{ + "types": [ + "a", + "b", + "c", + "d", + "e", + "f" + ], + "tunnel": { + "maxShips": 10 + }, + "shipGenerator": { + "generatingTime": 1, + "shipCapacityMin": 10, + "shipCapacityMax": 20 + }, + "docks": [ + { + "unloadingSpeed": 5, + "dockCapacity": 100, + "name": "dock1", + "hoboGroup": { + "hobos": 5, + "stealingTime": 1, + "eatingTime": 1, + "ingredients": { + "a": 8, + "b": 9, + "c": 1, + "d": 5, + "e": 2, + "f": 4 + } + } + }, + { + "unloadingSpeed": 5, + "dockCapacity": 100, + "name": "dock2", + "hoboGroup": { + "hobos": 4, + "stealingTime": 1, + "eatingTime": 2, + "ingredients": { + "a": 4, + "b": 2, + "c": 5, + "d": 12, + "e": 3, + "f": 3 + } + } + } + ] +} \ No newline at end of file diff --git a/lab-02/lib/gson-2.10.1.jar b/lab-02/lib/gson-2.10.1.jar new file mode 100644 index 0000000..a88c5bd Binary files /dev/null and b/lab-02/lib/gson-2.10.1.jar differ