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 a47928d..227e6bd 100644 --- a/app/src/main/java/simulation/Event.java +++ b/app/src/main/java/simulation/Event.java @@ -1,7 +1,21 @@ package simulation; -class Event{ +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 eventTimeStamp) throws IllegalArgumentException { + if (type > 3 || type < 1) + throw new IllegalArgumentException("Event type must be one of ARRIVAL, READY or MEASURE"); + + eventType = type; + eventTime = eventTimeStamp; + } + + // Empty constructor (used by the event list constructor) + // Event() { + // } + public double eventTime; public int eventType; - public Event next; + 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 fb469a3..15fd209 100644 --- a/app/src/main/java/simulation/EventList.java +++ b/app/src/main/java/simulation/EventList.java @@ -1,35 +1,72 @@ package simulation; -public class EventList{ - - private Event list, last; - - EventList(){ - list = new Event(); - last = new Event(); - list.next = last; +import java.util.LinkedList; + +// Essentially a linked list of a non-template node type +public class EventList { + private Event head = null; + private Integer size = 0; + + EventList() { } - - public void InsertEvent(int type, double TimeOfEvent){ - Event dummy, predummy; - Event newEvent = new Event(); - newEvent.eventType = type; - newEvent.eventTime = TimeOfEvent; - predummy = list; - dummy = list.next; - while ((dummy.eventTime < newEvent.eventTime) & (dummy != last)){ - predummy = dummy; - dummy = dummy.next; - } - predummy.next = newEvent; - newEvent.next = dummy; - } - - public Event FetchEvent(){ - Event dummy; - dummy = list.next; - list.next = dummy.next; - dummy.next = null; - return dummy; + + // Yes + public Event getHead() { + return head; } + + public Integer length() { + return size; + } + + public void insertEvent(Event newEvent) { + if (this.head == null) { + this.head = newEvent; + size += 1; + return; + } + + 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 popEvent() { + if (head == null) + return null; + Event temp = head; + head = head.next; + temp.next = null; + size -= 1; + return temp; + } + + 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 317e084..6d12e27 100644 --- a/app/src/main/java/simulation/GlobalSimulation.java +++ b/app/src/main/java/simulation/GlobalSimulation.java @@ -1,6 +1,10 @@ package simulation; -public class GlobalSimulation{ +import java.util.Random; + +// This class is only created to be able to store the global time. +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 c6ac416..82a350b 100644 --- a/app/src/main/java/simulation/MainSimulation.java +++ b/app/src/main/java/simulation/MainSimulation.java @@ -2,20 +2,23 @@ package simulation; import java.io.*; -public class MainSimulation extends GlobalSimulation{ - - public static void main(String[] args) throws IOException { - Event actEvent; - EventList myEventList = new EventList(); - State actState = new State(myEventList); - myEventList.InsertEvent(ARRIVAL, 0); - myEventList.InsertEvent(MEASURE, 5); - while (time < 50000){ - actEvent = myEventList.FetchEvent(); - time = actEvent.eventTime; - actState.TreatEvent(actEvent); - } - System.out.println("Mean number of customers: " + 1.0*actState.accumulated/actState.noMeasurements); - System.out.println("Number of measurements done: " + actState.noMeasurements); - } +public class MainSimulation extends GlobalSimulation { + + public static void main(String[] args) throws IOException { + EventList myEventList = new EventList(); + Event actEvent; + State actState = new State(myEventList); + + myEventList.insertEvent(new Event(ARRIVAL, 0)); + myEventList.insertEvent(new Event(MEASURE, 5)); + + while (MainSimulation.time < 50000) { + actEvent = myEventList.popEvent(); + MainSimulation.time = actEvent.eventTime; + actState.TreatEvent(actEvent); + } + + System.out.println("Mean number of customers: " + (double) actState.accumulated / actState.noMeasurements); + System.out.println("Number of measurements done: " + actState.noMeasurements); + } } \ No newline at end of file diff --git a/app/src/main/java/simulation/State.java b/app/src/main/java/simulation/State.java index 29cff41..1030ca8 100644 --- a/app/src/main/java/simulation/State.java +++ b/app/src/main/java/simulation/State.java @@ -2,57 +2,45 @@ package simulation; import java.util.*; -class State extends GlobalSimulation{ - +class State extends GlobalSimulation { public int numberInQueue = 0, accumulated = 0, noMeasurements = 0; - - private EventList myEventList; + private EventList eventList; - Random slump = new Random(); - - State(EventList x){ - myEventList = x; + State(EventList eventList) { + this.eventList = eventList; } - - private void InsertEvent(int event, double timeOfEvent){ - myEventList.InsertEvent(event, timeOfEvent); + + // Dispatches the events to the right handler + public void TreatEvent(Event x) { + if (x.eventType == ARRIVAL) + arrival(); + else if (x.eventType == READY) + ready(); + else if (x.eventType == MEASURE) + measure(); } - - - public void TreatEvent(Event x){ - switch (x.eventType){ - case ARRIVAL: - arrival(); - break; - case READY: - ready(); - break; - case MEASURE: - measure(); - break; - } + + // Helper to generate a random number with certain statistical properties + private static double generateMean(double mean) { + return 2 * mean * rand.nextDouble(); } - - private double generateMean(double mean){ - return 2*mean*slump.nextDouble(); - } - - private void arrival(){ + + 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(){ + + private void ready() { numberInQueue--; if (numberInQueue > 0) - InsertEvent(READY, time + generateMean(1)); + eventList.insertEvent(new Event(READY, time + generateMean(1))); } - - private void measure(){ + + 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; + // } +}