aboutsummaryrefslogtreecommitdiff
path: root/comp2511/blackout/BlackoutController.java
diff options
context:
space:
mode:
authorNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-13 18:00:17 +1100
committerNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-13 18:00:17 +1100
commit98cef5e9a772602d42acfcf233838c760424db9a (patch)
tree5277fa1d7cc0a69a0f166fcbf10fd320f345f049 /comp2511/blackout/BlackoutController.java
initial commit
Diffstat (limited to 'comp2511/blackout/BlackoutController.java')
-rw-r--r--comp2511/blackout/BlackoutController.java230
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