The JavaScript code example demonstrates how to program a simple discrete event simulation.
<!DOCTYPE html> <html> <head> <title>XoaX.net's Javascript</title> <script type="text/javascript" src="SimpleSimulation.js"></script> </head> <body onload="Initialization()"> </body> </html>
var qgEventSimulation = null;
function Initialization() {
qgEventSimulation = new CEventSimulation();
Loop();
}
function Loop() {
if (qgEventSimulation.TimeAllocated() < 7000) {
if (Math.random() < .01) {
qgEventSimulation.AddEvent();
}
}
// Check whether the first event in the queue is finished
let qProcessed = qgEventSimulation.Update();
if (qProcessed != null) {
console.log("An event was processed.")
}
setTimeout(Loop, 10);
}
class CEvent {
#mdDuration;
#mqColor;
#miIndex;
constructor(dDuration, iEventIndex) {
this.#miIndex = iEventIndex;
this.#mdDuration = dDuration;
this.#mqColor = "rgb("+Math.floor(256*Math.random())+", "+Math.floor(256*Math.random())+", "+Math.floor(256*Math.random())+")";
}
TimeRemaining(dElapsed) {
return (this.#mdDuration - dElapsed);
}
CreateElement() {
let qNewDiv = document.createElement("div");
qNewDiv.style.backgroundColor = this.#mqColor;
qNewDiv.style.border = "2px solid #808080";
qNewDiv.style.margin = "5px";
qNewDiv.style.width = "100px";
qNewDiv.style.height = Math.floor(this.#mdDuration/10)+"px";
qNewDiv.innerHTML = "Event #"+this.#miIndex;
return qNewDiv
}
PercentComplete(dElapsed) {
return Math.floor((100*dElapsed)/this.#mdDuration);
}
}
class CEventSimulation {
#mdLastEventFinished;
#mqEventQueue;
#mqTimeMarker;
#miEventsCreated;
constructor() {
this.#miEventsCreated = 0;
this.#mdLastEventFinished = null;
this.#mqEventQueue = new CQueue();
this.#mqTimeMarker = document.createElement("div");
this.#mqTimeMarker.style.backgroundColor = "yellow";
this.#mqTimeMarker.style.width = "100px";
this.#mqTimeMarker.style.height = "1px";
this.#mqTimeMarker.style.position = "relative";
this.#mqTimeMarker.style.left = "0px";
}
AddEvent() {
let dDuration = Math.floor(1000 + 1000*Math.random());
this.#miEventsCreated += 1;
let qNewEvent = new CEvent(dDuration, this.#miEventsCreated);
if (this.#mdLastEventFinished == null) {
this.#mdLastEventFinished = Date.now();
}
this.#mqEventQueue.Push(qNewEvent);
let qBody = document.body;
let qNewDiv = qNewEvent.CreateElement();
if (qBody.childElementCount > 0) {
let qLastChild = qBody.lastChild;
qLastChild.insertAdjacentElement("afterend", qNewDiv);
} else {
qBody.appendChild(qNewDiv);
}
}
Update() {
if (!this.#mqEventQueue.IsEmpty()) {
let dCurrTime = Date.now();
let dElapsedTime = dCurrTime - this.#mdLastEventFinished;
let qFirstEvent = this.#mqEventQueue.GetFirst();
let dTimeRemaining = qFirstEvent.TimeRemaining(dElapsedTime);
if (dTimeRemaining < 0.0) {
let qRemovedEvent = this.#mqEventQueue.Pop();
if (this.#mqEventQueue.IsEmpty()) {
this.#mdLastEventFinished = null;
} else {
this.#mdLastEventFinished += (dElapsedTime + dTimeRemaining);
}
let qBody = document.body;
qBody.removeChild(qBody.firstElementChild);
return qRemovedEvent;
} else {
// Add the timeline marker
let dPercentComplete = qFirstEvent.PercentComplete(dElapsedTime);
this.#mqTimeMarker.style.top = dPercentComplete+"%";
let qFirstChild = document.body.firstElementChild;
qFirstChild.appendChild(this.#mqTimeMarker);
}
}
}
TimeAllocated() {
let qHead = this.#mqEventQueue.mqList.mqpHead;
let dTime = 0;
while (qHead != null) {
dTime += qHead.mqData.TimeRemaining(0);
qHead = qHead.mqpNext;
}
return dTime;
}
}
class CLink {
mqData;
mqpNext;
constructor(qData) {
this.mqData = qData;
this.mqpNext = null;
}
}
class CLinkedList {
mqpHead;
mqpTail;
constructor() {
this.mqpHead = null;
this.mqpTail = null;
}
InsertAtTail(qData) {
if (this.mqpTail == null) {
this.mqpHead = new CLink(qData);
this.mqpTail = this.mqpHead;
} else {
this.mqpTail.mqpNext = new CLink(qData);
this.mqpTail = this.mqpTail.mqpNext;
}
}
RemoveAtHead() {
this.mqpHead = this.mqpHead.mqpNext;
if (this.mqpHead == null) {
this.mqpTail = this.mqpHead;
}
}
IsEmpty() {
return (this.mqpHead == null);
}
}
class CQueue {
mqList;
constructor() {
this.mqList = new CLinkedList();
}
Push(qData) {
this.mqList.InsertAtTail(qData);
}
Pop() {
let qPopped = this.mqList.mqpHead;
this.mqList.RemoveAtHead();
return qPopped.mqData;
}
IsEmpty() {
return this.mqList.IsEmpty();
}
GetFirst() {
if (this.IsEmpty()) {
return null;
}
return this.mqList.mqpHead.mqData;
}
}© 20072026 XoaX.net LLC. All rights reserved.