function updatePassenger(index) {
index = Number(index);
let passenger = objects.passengers[index];
let row = Number(passenger.row);
let col = Number(passenger.col);
let state = passenger.state;
let queueState = passenger.queueState;
let chosenQueue = Number(passenger.chosenQueue);
let hasArrived =
Math.abs(Number(passenger.targetRow) - row) +
Math.abs(Number(passenger.targetCol) - col) ==
0;
switch (state) {
case "immigration":
if (queueState == "immigrationQueue" && hasArrived) {
if (
col == Number(objects[queueState][chosenQueue].col) + 50 &&
objects.immigration[chosenQueue].state == "IDLE"
) {
passenger.queueState = "none";
passenger.targetRow =
Number(objects.immigration[chosenQueue].row) + 3;
passenger.targetCol =
Number(objects.immigration[chosenQueue].col) - 1;
let newStack =
Number(objects.immigrationQueue[chosenQueue].stack) - 1;
objects.immigrationQueue[chosenQueue].stack = newStack;
objects.immigration[chosenQueue].state = "BUSY";
} else if (col < Number(objects[queueState][chosenQueue].col) + 50) {
let filledCol = objects.passengers.filter(function (i) {
return i.col == col + 1 && i.row == row;
});
if (filledCol.length == 0) {
passenger.targetCol = col + 1;
}
}
} else if (queueState == "none" && hasArrived) {
if (Math.random() < probImmigration) {
// TODO Create function callable by the different states.
// ? Could probably do a recursive function for this.
objects.immigration[chosenQueue].state = "IDLE";
let station = Number(passenger.station);
station += 1;
let newState = getKeyByValue(positions, station);
if (newState == undefined) {
newState = getKeyByValue(positions, station + 1);
station += 1;
if (newState == undefined) {
newState = getKeyByValue(positions, station + 1);
station += 1;
} // Final state if nothing else will be "out".
}
if (newState == "exiting") {
passenger.state = "exiting";
passenger.targetCol = width;
passenger.targetRow = height / 2;
} else {
passenger.state = newState;
queueState = newState + "Queue";
passenger.queueState = queueState;
function chosenQueueRectifier(chosenQueue) {
//* Recursive function when having mismatched station lengths.
if (chosenQueue >= objects[queueState].length) {
chosenQueue -= 1;
return chosenQueueRectifier(chosenQueue);
} else {
return chosenQueue;
}
}
chosenQueue = chosenQueueRectifier(chosenQueue);
for (let i in objects[queueState]) {
if (i !== chosenQueue) {
if (
Number(objects[queueState][i].stack) <
Number(objects[queueState][chosenQueue].stack)
) {
chosenQueue = Number(i);
}
}
}
if (Math.random() < randomChosenQueue) {
chosenQueue = Math.floor(
Math.random() * objects[queueState].length
);
}
let stackOverflow = 0;
if (Number(objects[queueState][chosenQueue].stack) > 50) {
stackOverflow =
Number(objects[queueState][chosenQueue].stack) - 50;
}
passenger.targetRow =
Number(objects[queueState][chosenQueue].row) + 3;
passenger.targetCol =
Number(objects[queueState][chosenQueue].col) - stackOverflow;
passenger.station = station;
passenger.chosenQueue = chosenQueue;
let newStack = Number(objects[queueState][chosenQueue].stack) + 1;
objects[queueState][chosenQueue].stack = newStack;
}
}
}
break;
case "testing":
if (queueState == "testingQueue" && hasArrived) {
if (
col == Number(objects[queueState][chosenQueue].col) + 50 &&
objects.testing[chosenQueue].state == "IDLE"
) {
passenger.queueState = "testBox";
passenger.targetRow = Number(objects.testing[chosenQueue].row) + 3;
passenger.targetCol = Number(objects.testing[chosenQueue].col) - 1;
let newStack = Number(objects.testingQueue[chosenQueue].stack) - 1;
objects.testingQueue[chosenQueue].stack = newStack;
objects.testing[chosenQueue].state = "BUSY";
} else if (col < Number(objects[queueState][chosenQueue].col) + 50) {
let filledCol = objects.passengers.filter(function (i) {
return i.col == col + 1 && i.row == row;
});
if (filledCol.length == 0) {
passenger.targetCol = col + 1;
}
}
} else if (queueState == "testBox" && hasArrived) {
if (Math.random() < probTesting) {
passenger.queueState = "enteringTestBox";
passenger.targetCol = Number(objects.testingBox[0].col) - 1;
objects.testing[chosenQueue].state = "IDLE";
}
} else if (queueState == "enteringTestBox" && hasArrived) {
let boxWidth = Number(objects.testingBox[0].width);
let boxHeight = Number(objects.testingBox[0].height);
let boxRow = Number(objects.testingBox[0].row);
let boxCol = Number(objects.testingBox[0].col);
let newCol;
let newRow;
let overlapping = true;
while (overlapping) {
let count = 1;
let randRow = Math.floor(Math.random() * boxHeight);
let randCol = Math.floor(Math.random() * boxWidth);
newRow = boxRow + randRow;
newCol = boxCol + randCol;
let overlappedList = objects.passengers.filter(function (d) {
return d.targetRow == newRow && d.targetCol == newCol;
});
if (overlappedList.length == 0) {
overlapping = false;
}
// ! DEFINE BEHAVIOUR WHEN BOX IS FULL (UNLIKELY, BUT STILL).
// * FOR NOW, IF BOX IS FULL, ALLOW OVERLAP.
if (count > boxWidth * boxHeight) {
overlapping = false;
}
}
passenger.targetCol = newCol;
passenger.targetRow = newRow;
passenger.queueState = "waiting";
} else if (queueState == "waiting" && hasArrived) {
passenger.timeWaited = Number(passenger.timeWaited) + 1;
if (passenger.timeWaited >= testingTime && passenger.covid) {
passenger.state = "covid";
passenger.targetRow = 0;
} else if (passenger.timeWaited >= testingTime) {
let station = Number(passenger.station);
station += 1;
let newState = getKeyByValue(positions, station);
if (newState == undefined) {
newState = getKeyByValue(positions, station + 1);
station += 1;
if (newState == undefined) {
newState = getKeyByValue(positions, station + 1);
station += 1;
} // Final state if nothing else will be "out".
}
if (newState == "exiting") {
passenger.state = "exiting";
passenger.targetCol = width;
passenger.targetRow = height / 2;
} else {
passenger.state = newState;
queueState = newState + "Queue";
passenger.queueState = queueState;
function chosenQueueRectifier(chosenQueue) {
//* Recursive function when having mismatched station lengths.
if (chosenQueue >= objects[queueState].length) {
chosenQueue -= 1;
return chosenQueueRectifier(chosenQueue);
} else {
return chosenQueue;
}
}
chosenQueue = chosenQueueRectifier(chosenQueue);
for (let i in objects[queueState]) {
if (i !== chosenQueue) {
if (
Number(objects[queueState][i].stack) <
Number(objects[queueState][chosenQueue].stack)
) {
chosenQueue = Number(i);
}
}
}
if (Math.random() < randomChosenQueue) {
chosenQueue = Math.floor(
Math.random() * objects[queueState].length
);
}
let stackOverflow = 0;
if (Number(objects[queueState][chosenQueue].stack) > 50) {
stackOverflow =
Number(objects[queueState][chosenQueue].stack) - 50;
}
passenger.targetRow =
Number(objects[queueState][chosenQueue].row) + 3;
passenger.targetCol =
Number(objects[queueState][chosenQueue].col) - stackOverflow;
passenger.station = station;
passenger.chosenQueue = chosenQueue;
let newStack = Number(objects[queueState][chosenQueue].stack) + 1;
objects[queueState][chosenQueue].stack = newStack;
}
}
}
break;
case "baggage":
if (queueState == "baggageQueue" && hasArrived) {
if (col == Number(objects[queueState][chosenQueue].col) + 50) {
let newStack = Number(objects.baggageQueue[chosenQueue].stack) - 1;
objects.baggageQueue[chosenQueue].stack = newStack;
passenger.queueState = "gettingBaggage";
passenger.targetCol = Number(objects.baggage[0].col) - 1;
// objects.testing[chosenQueue].state = "BUSY";
} else if (col < Number(objects[queueState][chosenQueue].col) + 50) {
let filledCol = objects.passengers.filter(function (i) {
return i.col == col + 1 && i.row == row;
});
if (filledCol.length == 0) {
passenger.targetCol = col + 1;
}
}
} else if (queueState == "gettingBaggage" && hasArrived) {
let boxWidth = Number(objects.baggage[0].width);
let boxHeight = Number(objects.baggage[0].height);
let boxRow = Number(objects.baggage[0].row);
let boxCol = Number(objects.baggage[0].col);
let newCol;
let newRow;
let overlapping = true;
while (overlapping) {
let count = 1;
let randRow = Math.floor(Math.random() * boxHeight);
let randCol = Math.floor(Math.random() * boxWidth);
newRow = boxRow + randRow;
newCol = boxCol + randCol;
let overlappedList = objects.passengers.filter(function (d) {
return d.targetRow == newRow && d.targetCol == newCol;
});
if (overlappedList.length == 0) {
overlapping = false;
}
// ! DEFINE BEHAVIOUR WHEN BOX IS FULL (UNLIKELY, BUT STILL).
// * FOR NOW, IF BOX IS FULL, ALLOW OVERLAP.
if (count > boxWidth * boxHeight) {
overlapping = false;
}
}
passenger.targetCol = newCol;
passenger.targetRow = newRow;
passenger.queueState = "reachedBaggage";
} else if (queueState == "reachedBaggage" && hasArrived) {
if (Math.random() < probFindBaggage) {
let station = Number(passenger.station);
station += 1;
let newState = getKeyByValue(positions, station);
if (newState == undefined) {
newState = getKeyByValue(positions, station + 1);
station += 1;
if (newState == undefined) {
newState = getKeyByValue(positions, station + 1);
station += 1;
} // Final state if nothing else will be "out".
}
if (newState == "exiting") {
passenger.state = "exiting";
passenger.targetCol = width;
passenger.targetRow = height / 2;
} else {
passenger.state = newState;
queueState = newState + "Queue";
passenger.queueState = queueState;
function chosenQueueRectifier(chosenQueue) {
//* Recursive function when having mismatched station lengths.
if (chosenQueue >= objects[queueState].length) {
chosenQueue -= 1;
return chosenQueueRectifier(chosenQueue);
} else {
return chosenQueue;
}
}
chosenQueue = chosenQueueRectifier(chosenQueue);
for (let i in objects[queueState]) {
if (i !== chosenQueue) {
if (
Number(objects[queueState][i].stack) <
Number(objects[queueState][chosenQueue].stack)
) {
chosenQueue = Number(i);
}
}
}
if (Math.random() < randomChosenQueue) {
chosenQueue = Math.floor(
Math.random() * objects[queueState].length
);
}
let stackOverflow = 0;
if (Number(objects[queueState][chosenQueue].stack) > 50) {
stackOverflow =
Number(objects[queueState][chosenQueue].stack) - 50;
}
passenger.targetRow =
Number(objects[queueState][chosenQueue].row) + 3;
passenger.targetCol =
Number(objects[queueState][chosenQueue].col) - stackOverflow;
passenger.station = station;
passenger.chosenQueue = chosenQueue;
let newStack = Number(objects[queueState][chosenQueue].stack) + 1;
objects[queueState][chosenQueue].stack = newStack;
}
} else {
passenger.queueState = "gettingBaggage";
hasArrived = true;
}
}
break;
case "exiting":
if (hasArrived) {
passenger.state = "out";
exitedPassengers += 1;
document.getElementById("numExited").innerHTML =
"Number of exited passengers: " + exitedPassengers + ".";
listTimeToClear.push(Number(passenger.timeTaken));
newAvg =
listTimeToClear.reduce((a, b) => a + b) / listTimeToClear.length;
listMeanTimeToClear.push(newAvg);
let overallAvg;
if (listSimulationMeanRunTime.length > 0) {
overallAvg =
listSimulationMeanRunTime[listSimulationMeanRunTime.length - 1];
var overallStdDev = Math.sqrt(
listSimulationRunTime
.map((x) => Math.pow(x - overallAvg, 2))
.reduce((a, b) => a + b) / listSimulationRunTime.length
);
} else {
overallAvg = 0;
var overallStdDev = 0;
}
document.getElementById("aveAll").innerHTML =
"Average time taken by a passenger: " +
newAvg.toFixed(2) +
". Average time taken for " +
passengerCount +
" passenger(s): " +
overallAvg.toFixed(2) +
" over " +
simulationsRan +
" simulation(s) with a standard deviation of " +
overallStdDev.toFixed(2) +
".";
if (isRunning == true) {
Plotly.extendTraces("tester", { y: [[getData1()]] }, [0]);
cnt++;
if (cnt > limit) {
Plotly.relayout("tester", {
xaxis: {
range: [cnt - limit, cnt],
},
});
}
}
}
break;
case "covid":
if (hasArrived) {
passenger.state = "exiting";
}
}
passenger.timeTaken = Number(passenger.timeTaken) + 1;
let targetRow = Number(passenger.targetRow);
let targetCol = Number(passenger.targetCol);
// compute the distance to the target destination
let rowsToGo = targetRow - row;
let colsToGo = targetCol - col;
// set the speed
let cellsPerStep = 1;
// compute the cell to move to
let newRow =
row + Math.min(Math.abs(rowsToGo), cellsPerStep) * Math.sign(rowsToGo);
let newCol =
col + Math.min(Math.abs(colsToGo), cellsPerStep) * Math.sign(colsToGo);
// update the location of the passenger
passenger.row = newRow;
passenger.col = newCol;
}