{
console.clear(); svg.selectAll("*").remove();
// Initialize time and time step
let t = 0;
let dt = 0.005;
svg.append("text")
.attr("x", X(0.45))
.attr("y", -marg/4)
.attr("font-size", 20)
.attr("id", "curTime")
.text("t = " + t.toFixed(3));
// Initialize customer and server queues
let q = [];
let nextArrival = 0;
let customerID = 0;
mutable nCustLost = 0;
mutable nCustServ = 0;
let s =[];
for (let n=0;n<maxServers;n++) {
s.push([-1,-1,Infinity, Infinity, -1]);
}
// Start simulation
let curServers = -1;
while (true) {
t+=dt;
svg.selectAll("#curTime").text("t=" + t.toFixed(3));
// Redraw store if params changed
if (getNserv() != curServers) {
curServers = getNserv();
svg.selectAll("rect").remove();
// Draw box representing the store
let store = svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width-2*marg)
.attr("height", height-2*marg)
.attr("stroke", "black")
.attr("stroke-width",5)
.attr("fill", "none");
// Draw server stations
for (let n=0;n<maxServers;n++) {
-
if (n<Nservers) {s[n][4] = 0;}
+
if (n<viewof Nservers.value) {s[n][4] = 0;}
svg.append("rect")
.attr("x", X(0+stationWidth*n))
.attr("y", Y(stationHeight))
.attr("width", X(stationWidth))
.attr("height", (height-2*marg)*stationHeight)
.attr("stroke", "black")
.attr("stroke-width",3)
.attr("fill", stationStatus(n));
}
}
// Check for new customer arrivals
if (nextArrival <= t) {
let x = Math.random()*0.8+0.1;
let y = Math.random()*0.6+0.3;
let curT = t;
let waitTime = t+getWaitTime();
customerID+=1;
q.push([x,y,curT,waitTime,customerID]);
svg.append("circle")
.attr("cx", X(x))
.attr("cy", Y(y))
.attr("r", 10)
.attr("stroke", "transparent")
.attr("fill", colorize(getAnnoyance(curT,t,waitTime)))
.attr("id", 'c' + customerID);
nextArrival = nextArrival+getArrTime();
console.log("Next arrival time: " + nextArrival);
}
// Check customer wait times and update display
for (let n=0;n<q.length;n++) {
// Any customers who have been waiting too long will leave the store
if (q[n][3] < t) {
mutable nCustLost+=1;
svg.selectAll("[id=c" + q[n][4] + "]")
.transition()
.duration(200)
.attr("r", 50)
.style("fill", "red")
.transition()
.duration(100)
.attr("r", 1)
.style("fill", "transparent")
.remove();
q.splice(n,1);
n-=1;
}
// Otherwise update their color
else {
let a = q[n][2];
let b = q[n][3];
svg.selectAll("[id=c" + q[n][4] + "]")
.attr("fill", colorize(getAnnoyance(a,t,b)));
}
}
// Check if any customers are waiting
if (q.length > 0) {
let openStation = getOpenStation(s);
// Check if any service stations are open
if (openStation > -1) {
// Get the customer who has been waiting the longest and move to the service queue
let cust = q.shift();
// Determine when their service will be done
cust[3] = t+getServTime();
// Compute the position of the server window
cust[0] = 0.05+(openStation*stationWidth);
cust[1] = stationHeight/2;
// Add customer to service array
s[openStation] = cust;
// Animate the transition
svg.selectAll("[id=c" + cust[4] + "]")
.transition()
.duration(1000)
.attr("cx", X(cust[0]))
.attr("cy", Y(cust[1]))
.attr("r", 15)
.style("fill", "blue");
}
}
// Check for customers done getting service
for (let n=0;n<maxServers;n++) {
if (s[n][3] < t) {
mutable nCustServ+=1;
svg.selectAll("[id=c" + s[n][4] + "]")
.transition()
.duration(200)
.attr("r",50)
.style("fill", "green")
.transition("fill", "transparent")
.duration(200)
.remove();
s[n] = [-1,-1,Infinity,Infinity,0];
}
}
// Check if we closed any stations with customers inside!
// This makes them mad and they will leave immediately.
-
for (let n=Nservers;n<maxServers;n++) {
+
for (let n=viewof Nservers.value;n<maxServers;n++) {
if (s[n][4] > 0) {
mutable nCustLost+=1;
svg.selectAll("[id=c" + s[n][4] + "]")
.transition()
.duration(200)
.attr("r", 50)
.style("fill", "red")
.transition()
.remove();
s[n] = [-1,-1,Infinity,Infinity,-1];
}
}
yield(svg.node().parentNode)
}
}