diff options
| author | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-13 18:00:17 +1100 |
|---|---|---|
| committer | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-13 18:00:17 +1100 |
| commit | 98cef5e9a772602d42acfcf233838c760424db9a (patch) | |
| tree | 5277fa1d7cc0a69a0f166fcbf10fd320f345f049 /comp2511/blackout/BlackoutController.java | |
initial commit
Diffstat (limited to 'comp2511/blackout/BlackoutController.java')
| -rw-r--r-- | comp2511/blackout/BlackoutController.java | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/comp2511/blackout/BlackoutController.java b/comp2511/blackout/BlackoutController.java new file mode 100644 index 0000000..fcbedc4 --- /dev/null +++ b/comp2511/blackout/BlackoutController.java @@ -0,0 +1,230 @@ +package unsw.blackout; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; // prefer vectors for cache locality +import java.util.Optional; + +import unsw.response.models.EntityInfoResponse; +import unsw.response.models.FileInfoResponse; +import unsw.utils.Angle; + +public class BlackoutController { + private Vector<EntityBase> Entities = new Vector<EntityBase>(); + + // We use optional as a more explicit way of saying we return null, or to represent infinity etc. + // Note, the HD part is not entirely implemented. + + /** + * Returns an optional Entitybase, where optional means it does not exist. + */ + private Optional<EntityBase> getEntity(String Id) { + for (EntityBase entity : this.Entities) { + if (entity.getId().equals(Id)) { + return Optional.of(entity); + } + } + return Optional.empty(); + } + /** + * Removes an entity based on a String id, does nothing if it already exists. + */ + private void removeEntity(String id) { + Optional<EntityBase> entity = getEntity(id); + if (entity.isEmpty()) { + return; + } + this.Entities.remove(entity.get()); + } + /** + * Adds an entity based on a String id, does nothing if it already exists. + */ + private void addEntity(EntityBase entity) { + if (getEntity(entity.getId()).isPresent()) { + return; + } + this.Entities.add(entity); + } + +// Public methods. + public void createDevice(String deviceId, String type, Angle position) { + if(type.equals(HandheldDevice.class.getSimpleName())) { + this.addEntity(new HandheldDevice(deviceId, position)); + } else if (type.equals(LaptopDevice.class.getSimpleName())) { + this.addEntity(new LaptopDevice(deviceId, position)); + } else if (type.equals(DesktopDevice.class.getSimpleName())) { + this.addEntity(new DesktopDevice(deviceId, position)); + } else if (type.equals(CloudStorageDevice.class.getSimpleName())) { + this.addEntity(new CloudStorageDevice(deviceId, position)); + } + } + + public void removeDevice(String deviceId) { + Optional<EntityBase> entity = this.getEntity(deviceId); + if (entity.isEmpty() || !(entity.get() instanceof DeviceBase)) { + return; + } + this.removeEntity(deviceId); + } + + public void createSatellite(String satelliteId, String type, double height, Angle position) { + if (type.equals(StandardSatellite.class.getSimpleName())) { + this.addEntity(new StandardSatellite(satelliteId, height, position)); + } else if (type.equals(ShrinkingSatellite.class.getSimpleName())) { + this.addEntity(new ShrinkingSatellite(satelliteId, height, position)); + } else if (type.equals(RelaySatellite.class.getSimpleName())) { + this.addEntity(new RelaySatellite(satelliteId, height, position)); + } else if (type.equals(ElephantSatellite.class.getSimpleName())) { + this.addEntity(new ElephantSatellite(satelliteId, height, position)); + } + } + + public void removeSatellite(String satelliteId) { + Optional<EntityBase> entity = this.getEntity(satelliteId); + if (entity.isEmpty() || !(entity.get() instanceof SatelliteBase)) { + return; + } + this.removeEntity(satelliteId); + } + + public List<String> listDeviceIds() { + ArrayList<String> list = new ArrayList<String>(); + for (EntityBase entity : this.Entities) { + if (!(entity instanceof DeviceBase)) { + continue; + } + list.add(entity.getId()); + } + return list; + } + + public List<String> listSatelliteIds() { + ArrayList<String> list = new ArrayList<String>(); + for (EntityBase entity : this.Entities) { + if (!(entity instanceof SatelliteBase)) { + continue; + } + list.add(entity.getId()); + } + return list; + } + + public void addFileToDevice(String deviceId, String filename, String content) { + Optional<EntityBase> entity = this.getEntity(deviceId); + if (entity.isEmpty() || !(entity.get() instanceof DeviceBase)) { + return; + } + DeviceBase device = (DeviceBase)entity.get(); + device.addFile(filename, content); + } + + public EntityInfoResponse getInfo(String id) { + Optional<EntityBase> optional_entity = this.getEntity(id); + if (optional_entity.isEmpty()) { + return null; + } + EntityBase entity = optional_entity.get(); + Angle position = entity.getAngle(); + double height = entity.getHeight(); + String type = entity.getClass().getSimpleName(); + Map<String, FileInfoResponse> files = new HashMap<>(); + for (File file : entity.getReceivedFiles()) { + String filename = file.getFilename(); + String transmitted_contents = file.getTransmittedContents(); + int final_size = file.getContentsSize(); + boolean is_transmitted = file.hasFullyTransmitted(); + + if (is_transmitted && entity.canShrink()) { + if (file.isQuantum()) { + final_size = (int)((double)final_size * (2.0 / 3.0) + 0.5); + } + } + + files.put(filename, new FileInfoResponse(filename, transmitted_contents, final_size, is_transmitted)); + } + return new EntityInfoResponse(id, position, height, type, files); + } + + /** + * Helper function, sends all files associated with the entity to their targets if they exist. + */ + private void sendEntityFiles(EntityBase entity) { + Vector<File> remove_files = new Vector<File>(); + + for (File file : entity.getSentFiles()) { + if (file.hasFullyTransmitted()) { + continue; + } + + Optional<EntityBase> target = this.getEntity(file.getTargetId()); + if (target.isEmpty()) { // as per the reference implementation, if it's deleted just ignore it (undef in spec) + continue; + } + + if (entity.maybeTransferFile(file, target.get())) { + continue; + } + + remove_files.add(file); + } + + entity.removeSentFiles(remove_files); + } + + public void simulate() { + for (EntityBase entity : this.Entities) { + entity.move(); + } + // For sending files, we need the origin entity, available in BlackoutController. + for (EntityBase entity : this.Entities) { + this.sendEntityFiles(entity); + } + } + + /** + * Simulate for the specified number of minutes. + * You shouldn't need to modify this function. + */ + public void simulate(int numberOfMinutes) { + for (int i = 0; i < numberOfMinutes; i++) { + simulate(); + } + } + + public List<String> communicableEntitiesInRange(String id) { + Optional<EntityBase> optional_entity = this.getEntity(id); + + if (optional_entity.isEmpty()) { + return null; + } + + EntityBase entity = optional_entity.get(); + + List<String> communicable_entities = new ArrayList<String>(); + for (EntityBase e : this.Entities) { + if (!entity.canCommunicate(e, this.Entities)) { + continue; + } + communicable_entities.add(e.getId()); + } + + return communicable_entities; + } + + public void sendFile(String fileName, String fromId, String toId) throws FileTransferException { + // Assumes we can communicate! (part of the spec) + Optional<EntityBase> optional_entity_from = this.getEntity(fromId); + Optional<EntityBase> optional_entity_to = this.getEntity(toId); + + if (optional_entity_from.isEmpty() || optional_entity_to.isEmpty()) { + return; + } + + EntityBase entity_from = optional_entity_from.get(); + EntityBase entity_to = optional_entity_to.get(); + + entity_from.sendFileTo(fileName, entity_to); + } +}
\ No newline at end of file |
