diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ff0e845..9140af8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -34,7 +34,7 @@ testing { // Apply a specific Java toolchain to ease working on different environments. java { toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) + languageVersion.set(JavaLanguageVersion.of(20)) } } @@ -42,3 +42,8 @@ application { // Define the main class for the application. mainClass.set("simulation.MainSimulation") } + +// Always execute all tests, even when not all tasks are up-to-date. +tasks.withType { + outputs.upToDateWhen { false } +} \ No newline at end of file diff --git a/app/src/main/java/simulation/Event.java b/app/src/main/java/simulation/Event.java index 6867797..227e6bd 100644 --- a/app/src/main/java/simulation/Event.java +++ b/app/src/main/java/simulation/Event.java @@ -1,16 +1,21 @@ package simulation; class Event { - // Constructor, creates an event of a certain type that should be put in the event list at a certain time. - Event(int type, double timeOfEvent) { + // Constructor, creates an event of a certain type that should be put in the + // event list at a certain time. + Event(int type, double eventTimeStamp) throws IllegalArgumentException { + if (type > 3 || type < 1) + throw new IllegalArgumentException("Event type must be one of ARRIVAL, READY or MEASURE"); + eventType = type; - eventTime = timeOfEvent; + eventTime = eventTimeStamp; } // Empty constructor (used by the event list constructor) - Event() { } + // Event() { + // } public double eventTime; public int eventType; - public Event next = null; + public Event next = null; // Explicitly initialize to null } diff --git a/app/src/main/java/simulation/EventList.java b/app/src/main/java/simulation/EventList.java index 94d3dfc..15fd209 100644 --- a/app/src/main/java/simulation/EventList.java +++ b/app/src/main/java/simulation/EventList.java @@ -1,43 +1,72 @@ package simulation; +import java.util.LinkedList; + +// Essentially a linked list of a non-template node type public class EventList { - private Event head, tail; + private Event head = null; + private Integer size = 0; EventList() { - head = new Event(); - tail = new Event(); - head.next = tail; } - public void InsertEvent(int type, double TimeOfEvent) { - Event temp, pretemp; + // Yes + public Event getHead() { + return head; + } - pretemp = this.head; - temp = this.head.next; + public Integer length() { + return size; + } - Event newEvent = new Event(type, TimeOfEvent); - - // Find the right place in the list using a sliding window - while ((temp.eventTime < newEvent.eventTime) && (temp != tail)) { - pretemp = temp; - temp = temp.next; + public void insertEvent(Event newEvent) { + if (this.head == null) { + this.head = newEvent; + size += 1; + return; } - pretemp.next = newEvent; - newEvent.next = temp; + Event cursor = this.head; + // int tries = 0; + // Find the right place in the list using a sliding window + while ((cursor.next != null) && (cursor.eventTime < newEvent.eventTime)) { + cursor = cursor.next; + // tries++; + } + + if (cursor.eventTime > newEvent.eventTime) { + newEvent.next = this.head; + this.head = newEvent; + } else { + newEvent.next = cursor.next; + cursor.next = newEvent; + } + + // System.out.println("Tries: " + tries); + size += 1; } - public Event FetchEvent() { - Event temp = head.next; - head.next = temp.next; + public Event popEvent() { + if (head == null) + return null; + Event temp = head; + head = head.next; temp.next = null; + size -= 1; return temp; } - public Event popFront() { + public Event fetchEvent() { Event temp = head.next; head.next = temp.next; temp.next = null; + size -= 1; return temp; } + + // public Event popFront() { + // Event front = this.head; + // this.head = this.head.next; + // return front; + // } } diff --git a/app/src/main/java/simulation/GlobalSimulation.java b/app/src/main/java/simulation/GlobalSimulation.java index 758cb78..6d12e27 100644 --- a/app/src/main/java/simulation/GlobalSimulation.java +++ b/app/src/main/java/simulation/GlobalSimulation.java @@ -1,7 +1,10 @@ package simulation; +import java.util.Random; + // This class is only created to be able to store the global time. -public class GlobalSimulation{ +public class GlobalSimulation { public static final int ARRIVAL = 1, READY = 2, MEASURE = 3; public static double time = 0; + public static Random rand = new Random(); } \ No newline at end of file diff --git a/app/src/main/java/simulation/MainSimulation.java b/app/src/main/java/simulation/MainSimulation.java index 231c1e2..82a350b 100644 --- a/app/src/main/java/simulation/MainSimulation.java +++ b/app/src/main/java/simulation/MainSimulation.java @@ -5,16 +5,15 @@ import java.io.*; public class MainSimulation extends GlobalSimulation { public static void main(String[] args) throws IOException { - Event actEvent; EventList myEventList = new EventList(); - + Event actEvent; State actState = new State(myEventList); - myEventList.InsertEvent(ARRIVAL, 0); - myEventList.InsertEvent(MEASURE, 5); + myEventList.insertEvent(new Event(ARRIVAL, 0)); + myEventList.insertEvent(new Event(MEASURE, 5)); while (MainSimulation.time < 50000) { - actEvent = myEventList.FetchEvent(); + actEvent = myEventList.popEvent(); MainSimulation.time = actEvent.eventTime; actState.TreatEvent(actEvent); } diff --git a/app/src/main/java/simulation/State.java b/app/src/main/java/simulation/State.java index 5f192f4..1030ca8 100644 --- a/app/src/main/java/simulation/State.java +++ b/app/src/main/java/simulation/State.java @@ -3,55 +3,44 @@ package simulation; import java.util.*; class State extends GlobalSimulation { - public int numberInQueue = 0, accumulated = 0, noMeasurements = 0; + private EventList eventList; - private EventList myEventList; - - static Random slump = new Random(); - - State(EventList x) { - myEventList = x; - } - - private void InsertEvent(int event, double timeOfEvent) { - myEventList.InsertEvent(event, timeOfEvent); + State(EventList eventList) { + this.eventList = eventList; } + // Dispatches the events to the right handler public void TreatEvent(Event x) { - switch (x.eventType) { - case ARRIVAL: - arrival(); - break; - case READY: - ready(); - break; - case MEASURE: - measure(); - break; - } + if (x.eventType == ARRIVAL) + arrival(); + else if (x.eventType == READY) + ready(); + else if (x.eventType == MEASURE) + measure(); } - private double generateMean(double mean) { - return 2 * mean * slump.nextDouble(); + // Helper to generate a random number with certain statistical properties + private static double generateMean(double mean) { + return 2 * mean * rand.nextDouble(); } private void arrival() { if (numberInQueue == 0) - InsertEvent(READY, time + generateMean(1)); + eventList.insertEvent(new Event(READY, time + generateMean(1))); numberInQueue++; - InsertEvent(ARRIVAL, time + generateMean(2)); + eventList.insertEvent(new Event(ARRIVAL, time + generateMean(2))); } private void ready() { numberInQueue--; if (numberInQueue > 0) - InsertEvent(READY, time + generateMean(1)); + eventList.insertEvent(new Event(READY, time + generateMean(1))); } private void measure() { accumulated = accumulated + numberInQueue; noMeasurements++; - InsertEvent(MEASURE, time + generateMean(5)); + eventList.insertEvent(new Event(MEASURE, time + generateMean(5))); } } \ No newline at end of file diff --git a/app/src/test/java/simulation/EventListTest.java b/app/src/test/java/simulation/EventListTest.java new file mode 100644 index 0000000..db0f07e --- /dev/null +++ b/app/src/test/java/simulation/EventListTest.java @@ -0,0 +1,63 @@ +package simulation; + +import java.util.Random; + +import org.junit.jupiter.api.Test; + +public class EventListTest { + @Test + void testEventListConstructor() { + EventList eventList = new EventList(); + Event event = new Event(1, 0.0); + eventList.insertEvent(event); + assert eventList.getHead() == event; + assert eventList.getHead().next == null; + } + + @Test + void testOrdering() { + EventList eventList = new EventList(); + Event event1 = new Event(1, 0.0); + Event event2 = new Event(1, 1.0); + Event event3 = new Event(1, 2.0); + eventList.insertEvent(event3); + eventList.insertEvent(event2); + eventList.insertEvent(event1); + assert eventList.getHead() == event1; + assert eventList.getHead().next == event2; + assert eventList.getHead().next.next == event3; + assert eventList.getHead().next.next.next == null; + } + + @Test + void testLength() { + Random rand = new Random(); + EventList eventList = new EventList(); + for(int i : rand.ints(0, 100).limit(100).toArray()) { + eventList.insertEvent(new Event(1, (double) i)); + } + assert eventList.length() == 100; + } + + @Test + void testPop() { + EventList eventList = new EventList(); + Event event1 = new Event(1, 0.0); + eventList.insertEvent(event1); + assert eventList.popEvent() == event1; + assert eventList.popEvent() == null; + } + + @Test + void testOrderingRandomAmount() { + Random rand = new Random(); + EventList eventList = new EventList(); + for(int i : rand.ints(0, 100).limit(100).toArray()) { + eventList.insertEvent(new Event(1, (double) i)); + } + for(Event e = eventList.getHead(); e != null; e = eventList.popEvent()) { + if(e.next == null) break; + assert e.eventTime < e.next.eventTime; + } + } +} diff --git a/app/src/test/java/simulation/EventTest.java b/app/src/test/java/simulation/EventTest.java new file mode 100644 index 0000000..48122f2 --- /dev/null +++ b/app/src/test/java/simulation/EventTest.java @@ -0,0 +1,17 @@ +package simulation; + +import org.junit.jupiter.api.Test; + +public class EventTest { + @Test void testConstructor() { + Event event = new Event(1, 0.0); + assert event.eventType == 1; + assert event.eventTime == 0.0; + } + + // @Test void testEmptyConstructor() { + // Event event = new Event(); + // assert event.eventType == 0; + // assert event.eventTime == 0.0; + // } +}