From 08f94aa5d3e00b1aae2f79cb8523dc876d028320 Mon Sep 17 00:00:00 2001 From: Yadunand Prem Date: Thu, 25 Aug 2022 17:25:02 +0800 Subject: [PATCH] init --- .gitignore | 2 ++ ArrivalEvent.java | 34 ++++++++++++++++++++ BaseShopEvent.java | 22 +++++++++++++ DepartureEvent.java | 19 +++++++++++ Event.java | 72 +++++++++++++++++++++++++++++++++++++++++ Lab1.java | 26 +++++++++++++++ ServiceBeginEvent.java | 27 ++++++++++++++++ ServiceEndEvent.java | 23 +++++++++++++ ShopSimulation.java | 58 +++++++++++++++++++++++++++++++++ Simulation.java | 20 ++++++++++++ Simulator.java | 51 +++++++++++++++++++++++++++++ inputs/Lab1.1.in | 4 +++ inputs/Lab1.2.in | 4 +++ inputs/Lab1.3.in | 6 ++++ inputs/Lab1.4.in | 5 +++ inputs/Lab1.5.in | 4 +++ outputs/Lab1.1.out | 12 +++++++ outputs/Lab1.2.out | 10 ++++++ outputs/Lab1.3.out | 16 +++++++++ outputs/Lab1.4.out | 16 +++++++++ outputs/Lab1.5.out | 12 +++++++ test.sh | 73 ++++++++++++++++++++++++++++++++++++++++++ 22 files changed, 516 insertions(+) create mode 100644 .gitignore create mode 100644 ArrivalEvent.java create mode 100644 BaseShopEvent.java create mode 100644 DepartureEvent.java create mode 100644 Event.java create mode 100644 Lab1.java create mode 100644 ServiceBeginEvent.java create mode 100644 ServiceEndEvent.java create mode 100644 ShopSimulation.java create mode 100644 Simulation.java create mode 100644 Simulator.java create mode 100644 inputs/Lab1.1.in create mode 100644 inputs/Lab1.2.in create mode 100644 inputs/Lab1.3.in create mode 100644 inputs/Lab1.4.in create mode 100644 inputs/Lab1.5.in create mode 100644 outputs/Lab1.1.out create mode 100644 outputs/Lab1.2.out create mode 100644 outputs/Lab1.3.out create mode 100644 outputs/Lab1.4.out create mode 100644 outputs/Lab1.5.out create mode 100644 test.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0e7974b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +Lab1.pdf \ No newline at end of file diff --git a/ArrivalEvent.java b/ArrivalEvent.java new file mode 100644 index 0000000..54816a5 --- /dev/null +++ b/ArrivalEvent.java @@ -0,0 +1,34 @@ + +class ArrivalEvent extends BaseShopEvent { + + double serviceTime; + + public ArrivalEvent(double time, int customerId, boolean[] available, double serviceTime) { + super(time, customerId, available); + this.availableCounters = available; + this.serviceTime = serviceTime; + } + + @Override + public Event[] simulate() { + int counter = -1; + for (int i = 0; i < this.availableCounters.length; i++) { + if (this.availableCounters[i]) { + counter = i; + break; + } + } + if (counter == -1) { + return new Event[] { new DepartureEvent(this.getTime(), customerId, availableCounters) }; + } + + return new Event[] { + new ServiceBeginEvent(this.getTime(), this.customerId, this.availableCounters, this.serviceTime, + counter) }; + } + + @Override + public String toString() { + return super.toString() + String.format(": Customer %d arrives", this.customerId); + } +} \ No newline at end of file diff --git a/BaseShopEvent.java b/BaseShopEvent.java new file mode 100644 index 0000000..13760ac --- /dev/null +++ b/BaseShopEvent.java @@ -0,0 +1,22 @@ + +/** + * This class encapsulates an event in the shop + * simulation. Your task is to replace this + * class with new classes, following proper OOP principles. + * + * @author Wei Tsang + * @version CS2030S AY21/22 Semester 2 + */ + +abstract class BaseShopEvent extends Event { + + final int customerId; + boolean[] availableCounters; + + public BaseShopEvent(double time, int customerId, boolean[] availableCounters) { + super(time); + this.customerId = customerId; + this.availableCounters = availableCounters; + } + +} \ No newline at end of file diff --git a/DepartureEvent.java b/DepartureEvent.java new file mode 100644 index 0000000..ce376a8 --- /dev/null +++ b/DepartureEvent.java @@ -0,0 +1,19 @@ + +class DepartureEvent extends BaseShopEvent { + + public DepartureEvent(double time, int customerId, boolean[] available) { + super(time, customerId, available); + } + + @Override + public String toString() { + return super.toString() + + String.format(": Customer %d departed", this.customerId); + } + + @Override + public Event[] simulate() { + return new Event[] {}; + } + +} \ No newline at end of file diff --git a/Event.java b/Event.java new file mode 100644 index 0000000..8ae0b75 --- /dev/null +++ b/Event.java @@ -0,0 +1,72 @@ +/** + * The Event class is an abstract class that encapsulates a + * discrete event to be simulated. An event encapsulates the + * time the event occurs. A subclass of event _must_ override + * the simulate() method to implement the logic of the + * simulation when this event is simulated. The simulate method + * returns an array of events, which the simulator will then + * add to the event queue. Note that an event also implements + * the Comparable interface so that a PriorityQueue can + * arrange the events in the order of event time. + * + * @author Wei Tsang + * @version CS2030S AY21/22 Semester 2 + */ +abstract class Event implements Comparable { + /** The time this event occurs in the simulation. */ + private final double time; + + /** + * Creates an event that occurs at the given time. + * + * @param time The time the event occurs. + */ + public Event(double time) { + this.time = time; + } + + /** + * Getter to return the time of this event. + * + * @return The time this event occurs. + */ + public double getTime() { + return this.time; + } + + /** + * Compare this event with a given event e. + * + * @param e The other event to compare to. + * @return 1 if this event occurs later than e; + * 0 if they occur the same time; + * -1 if this event occurs earlier. + */ + @Override + public int compareTo(Event e) { + if (this.time > e.time) { + return 1; + } else if (this.time == e.time) { + return 0; + } else { + return -1; + } + } + + /** + * Return the string representation this event. + * + * @return A string consists of the time this event occurs. + */ + @Override + public String toString() { + return String.format("%.3f", this.time); + } + + /** + * Simulate this event. + * + * @return An array of new events to be scheduled by the simulator. + */ + public abstract Event[] simulate(); +} diff --git a/Lab1.java b/Lab1.java new file mode 100644 index 0000000..e87a597 --- /dev/null +++ b/Lab1.java @@ -0,0 +1,26 @@ +import java.util.Scanner; + +/** + * The main class for CS2030S Lab 1. + * + * @author Wei Tsang + * @version CS2030S AY21/22 Semester 2 + */ +class Lab1 { + public static void main(String[] args) { + + // Create a scanner to read from standard input. + Scanner sc = new Scanner(System.in); + + // Create a simulation. The ShopSimulation + // constructor will read the simulation parameters + // and initial events using the scanner. + Simulation simulation = new ShopSimulation(sc); + + // Create a new simulator and run the simulation + new Simulator(simulation).run(); + + // Clean up the scanner. + sc.close(); + } +} diff --git a/ServiceBeginEvent.java b/ServiceBeginEvent.java new file mode 100644 index 0000000..372f410 --- /dev/null +++ b/ServiceBeginEvent.java @@ -0,0 +1,27 @@ + +class ServiceBeginEvent extends BaseShopEvent { + + double serviceTime; + int counterId; + + public ServiceBeginEvent(double time, int customerId, boolean[] available, double serviceTime, int counterId) { + super(time, customerId, available); + this.serviceTime = serviceTime; + this.counterId = counterId; + // TODO Auto-generated constructor stub + } + + @Override + public String toString() { + return super.toString() + + String.format(": Customer %d service begin (by Counter %d)", this.customerId, this.counterId); + } + + @Override + public Event[] simulate() { + this.availableCounters[this.counterId] = false; + double endTime = this.getTime() + this.serviceTime; + return new Event[] { + new ServiceEndEvent(endTime, this.customerId, this.availableCounters, this.counterId) }; + } +} \ No newline at end of file diff --git a/ServiceEndEvent.java b/ServiceEndEvent.java new file mode 100644 index 0000000..1d9567d --- /dev/null +++ b/ServiceEndEvent.java @@ -0,0 +1,23 @@ + +class ServiceEndEvent extends BaseShopEvent { + + int counterId; + + public ServiceEndEvent(double time, int customerId, boolean[] available, int counterId) { + super(time, customerId, available); + this.counterId = counterId; + // TODO Auto-generated constructor stub + } + + @Override + public String toString() { + return super.toString() + + String.format(": Customer %d service done (by Counter %d)", this.customerId, this.counterId); + } + + @Override + public Event[] simulate() { + this.availableCounters[counterId] = true; + return new Event[] { new DepartureEvent(this.getTime(), customerId, availableCounters) }; + } +} \ No newline at end of file diff --git a/ShopSimulation.java b/ShopSimulation.java new file mode 100644 index 0000000..814e837 --- /dev/null +++ b/ShopSimulation.java @@ -0,0 +1,58 @@ +import java.util.Scanner; + +/** + * This class implements a shop simulation. + * + * @author Wei Tsang + * @version CS2030S AY21/22 Semester 2 + */ +class ShopSimulation extends Simulation { + /** + * The availability of counters in the shop. + */ + public boolean[] availableCounters; + + /** + * The list of customer arrival events to populate + * the simulation with. + */ + public Event[] initEvents; + + /** + * Constructor for a shop simulation. + * + * @param sc A scanner to read the parameters from. The first + * integer scanned is the number of customers; followed + * by the number of service counters. Next is a + * sequence of (arrival time, service time) pair, each + * pair represents a customer. + */ + public ShopSimulation(Scanner sc) { + initEvents = new Event[sc.nextInt()]; + int numOfCounters = sc.nextInt(); + + availableCounters = new boolean[numOfCounters]; + for (int i = 0; i < numOfCounters; i++) { + availableCounters[i] = true; + } + + int id = 0; + while (sc.hasNextDouble()) { + double arrivalTime = sc.nextDouble(); + double serviceTime = sc.nextDouble(); + initEvents[id] = new ArrivalEvent(arrivalTime, id, availableCounters, serviceTime); + id += 1; + } + } + + /** + * Retrieve an array of events to populate the + * simulator with. + * + * @return An array of events for the simulator. + */ + @Override + public Event[] getInitialEvents() { + return initEvents; + } +} diff --git a/Simulation.java b/Simulation.java new file mode 100644 index 0000000..8b6a465 --- /dev/null +++ b/Simulation.java @@ -0,0 +1,20 @@ +/** + * This class is a general abstract class that + * encapsulates a simulation. To implement a + * simulation, inherit from this class and implement + * the `getInitialEvents` method. + * + * @author Wei Tsang + * @version CS2030S AY21/22 Semester 2 + */ +abstract class Simulation { + /** + * An abstract method to return an array of events + * used to initialize the simulation. + * + * @return An array of initial events that the + * simulator can use to kick-start the + * simulation. + */ + public abstract Event[] getInitialEvents(); +} diff --git a/Simulator.java b/Simulator.java new file mode 100644 index 0000000..0166db7 --- /dev/null +++ b/Simulator.java @@ -0,0 +1,51 @@ +import java.util.PriorityQueue; + +/** + * This class implements a discrete event simulator. + * The simulator maintains a priority queue of events. + * It runs through the events and simulates each one until + * the queue is empty. + * + * @author Wei Tsang + * @version CS2030S AY21/22 Semester 2 + */ +public class Simulator { + /** The event queue. */ + private final PriorityQueue events; + + /** + * The constructor for a simulator. It takes in + * a simulation as an argument, and calls the + * getInitialEvents method of that simulation to + * initialize the event queue. + * + * @param simulation The simulation to simulate. + */ + public Simulator(Simulation simulation) { + this.events = new PriorityQueue(); + for (Event e : simulation.getInitialEvents()) { + this.events.add(e); + } + } + + /** + * Run the simulation until no more events is in + * the queue. For each event in the queue (in + * increasing order of time), print out its string + * representation, then simulate it. If the + * simulation returns one or more events, add them + * to the queue, and repeat. + */ + public void run() { + Event event = this.events.poll(); + while (event != null) { + System.out.println(event); + Event[] newEvents = event.simulate(); + for (Event e : newEvents) { + this.events.add(e); + } + event = this.events.poll(); + } + return; + } +} diff --git a/inputs/Lab1.1.in b/inputs/Lab1.1.in new file mode 100644 index 0000000..6fde254 --- /dev/null +++ b/inputs/Lab1.1.in @@ -0,0 +1,4 @@ +3 1 +1.0 1.0 +3.0 1.0 +5.0 1.0 diff --git a/inputs/Lab1.2.in b/inputs/Lab1.2.in new file mode 100644 index 0000000..efc9f6e --- /dev/null +++ b/inputs/Lab1.2.in @@ -0,0 +1,4 @@ +3 1 +1.1 2.0 +2.2 2.0 +3.3 2.0 diff --git a/inputs/Lab1.3.in b/inputs/Lab1.3.in new file mode 100644 index 0000000..d63c1c7 --- /dev/null +++ b/inputs/Lab1.3.in @@ -0,0 +1,6 @@ +5 2 +1.0 1.0 +1.2 1.0 +1.4 1.0 +1.6 1.0 +2.1 1.0 diff --git a/inputs/Lab1.4.in b/inputs/Lab1.4.in new file mode 100644 index 0000000..232e851 --- /dev/null +++ b/inputs/Lab1.4.in @@ -0,0 +1,5 @@ +4 2 +1.0 1.0 +1.1 1.0 +2.2 1.0 +2.3 1.0 diff --git a/inputs/Lab1.5.in b/inputs/Lab1.5.in new file mode 100644 index 0000000..1bf5387 --- /dev/null +++ b/inputs/Lab1.5.in @@ -0,0 +1,4 @@ +3 2 +1.0 4 +2.1 1 +4.2 1 diff --git a/outputs/Lab1.1.out b/outputs/Lab1.1.out new file mode 100644 index 0000000..468dc2f --- /dev/null +++ b/outputs/Lab1.1.out @@ -0,0 +1,12 @@ +1.000: Customer 0 arrives +1.000: Customer 0 service begin (by Counter 0) +2.000: Customer 0 service done (by Counter 0) +2.000: Customer 0 departed +3.000: Customer 1 arrives +3.000: Customer 1 service begin (by Counter 0) +4.000: Customer 1 service done (by Counter 0) +4.000: Customer 1 departed +5.000: Customer 2 arrives +5.000: Customer 2 service begin (by Counter 0) +6.000: Customer 2 service done (by Counter 0) +6.000: Customer 2 departed diff --git a/outputs/Lab1.2.out b/outputs/Lab1.2.out new file mode 100644 index 0000000..901e4f2 --- /dev/null +++ b/outputs/Lab1.2.out @@ -0,0 +1,10 @@ +1.100: Customer 0 arrives +1.100: Customer 0 service begin (by Counter 0) +2.200: Customer 1 arrives +2.200: Customer 1 departed +3.100: Customer 0 service done (by Counter 0) +3.100: Customer 0 departed +3.300: Customer 2 arrives +3.300: Customer 2 service begin (by Counter 0) +5.300: Customer 2 service done (by Counter 0) +5.300: Customer 2 departed diff --git a/outputs/Lab1.3.out b/outputs/Lab1.3.out new file mode 100644 index 0000000..ea09baa --- /dev/null +++ b/outputs/Lab1.3.out @@ -0,0 +1,16 @@ +1.000: Customer 0 arrives +1.000: Customer 0 service begin (by Counter 0) +1.200: Customer 1 arrives +1.200: Customer 1 service begin (by Counter 1) +1.400: Customer 2 arrives +1.400: Customer 2 departed +1.600: Customer 3 arrives +1.600: Customer 3 departed +2.000: Customer 0 service done (by Counter 0) +2.000: Customer 0 departed +2.100: Customer 4 arrives +2.100: Customer 4 service begin (by Counter 0) +2.200: Customer 1 service done (by Counter 1) +2.200: Customer 1 departed +3.100: Customer 4 service done (by Counter 0) +3.100: Customer 4 departed diff --git a/outputs/Lab1.4.out b/outputs/Lab1.4.out new file mode 100644 index 0000000..65c50af --- /dev/null +++ b/outputs/Lab1.4.out @@ -0,0 +1,16 @@ +1.000: Customer 0 arrives +1.000: Customer 0 service begin (by Counter 0) +1.100: Customer 1 arrives +1.100: Customer 1 service begin (by Counter 1) +2.000: Customer 0 service done (by Counter 0) +2.000: Customer 0 departed +2.100: Customer 1 service done (by Counter 1) +2.100: Customer 1 departed +2.200: Customer 2 arrives +2.200: Customer 2 service begin (by Counter 0) +2.300: Customer 3 arrives +2.300: Customer 3 service begin (by Counter 1) +3.200: Customer 2 service done (by Counter 0) +3.200: Customer 2 departed +3.300: Customer 3 service done (by Counter 1) +3.300: Customer 3 departed diff --git a/outputs/Lab1.5.out b/outputs/Lab1.5.out new file mode 100644 index 0000000..771a25b --- /dev/null +++ b/outputs/Lab1.5.out @@ -0,0 +1,12 @@ +1.000: Customer 0 arrives +1.000: Customer 0 service begin (by Counter 0) +2.100: Customer 1 arrives +2.100: Customer 1 service begin (by Counter 1) +3.100: Customer 1 service done (by Counter 1) +3.100: Customer 1 departed +4.200: Customer 2 arrives +4.200: Customer 2 service begin (by Counter 1) +5.000: Customer 0 service done (by Counter 0) +5.000: Customer 0 departed +5.200: Customer 2 service done (by Counter 1) +5.200: Customer 2 departed diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..aab80a4 --- /dev/null +++ b/test.sh @@ -0,0 +1,73 @@ +#!/bin/bash +function control_c() { + if [ -e $out ] + then + rm -f $out + fi +} + +trap control_c INT + +if [ $# -ne 1 ] +then + echo "usage: $0
" + exit 1 +fi + +PROG=$1 +if [ ! -e $PROG.class ] +then + echo "$PROG.class does not exist. Have you compiled it with make or javac?" + exit 1 +fi + +num_failed=0 +i=1 +while true +do + if [ -e inputs/$PROG.$i.in ] + then + if [ $(uname) == "Darwin" ] + then + out=$(mktemp -t $PROG) + else + out=$(mktemp --suffix=$PROG) + fi + java $PROG < inputs/$PROG.$i.in > $out + status="$?" + if [ "$status" -ne "0" ] + then + echo "$PROG: return non-zero status $status for test case $i" + # cat inputs/$PROG.$i.in + num_failed=$((num_failed + 1)) + else + if [ -e $out ] + then + if [ `diff -bB $out outputs/$PROG.$i.out | wc -l` -ne 0 ] + then + echo "test $i: failed" + #cat inputs/$PROG.$i.in + num_failed=$((num_failed + 1)) + else + echo "test $i: passed" + fi + rm -f $out + else + echo "$PROG: cannot find output file. Execution interrupted?" + num_failed=$((num_failed + 1)) + fi + fi + i=$((i + 1)) + else + break + fi +done + +if [ $i -eq 1 ] +then + echo "$PROG: no test cases found 🤷" +elif [ $num_failed -eq 0 ] +then + echo "$PROG: passed everything 🎉" +fi +# vim:noexpandtab:sw=4:ts=4