📄 logic.js
字号:
//声明全局变量
var evnStack = []; //事件记录列表
var ifOutOfTime = false; //是否超出指定的仿真时间范围
var nextTime = 0; //下一到达时间
var customerNum = 0; //系统中顾客数
var endTime = 0; //离去时间
var hasServeNum = 0; //已服务人数
var idleTime = 0; //服务台闲期
var curStatus = ['闲', '忙', '闲->忙', '忙->闲']; //服务台状态数组 0:闲 1:忙 2:闲->忙 3:忙->闲
var emulateTime; //仿真时间长度
var minSpaceTime; //两事件最短间隔时间
var maxSpaceTime; //两事件最长间隔时间
var minServeTime; //最短服务时间
var maxServeTime; //最长服务时间
//如果没有设置参数,则参数默认
emulateTime = 500;
minSpaceTime = 1;
maxSpaceTime = 50;
minServeTime = 1;
maxServeTime = 30;
//开始仿真
function startEmluator() {
varInitialization();
//初始化事件,开始营业
evnStack.push([0, null, null, null, null, null, 0, 0, null, null, null, null, null, 0, null]);
//在指定时间范围内随机产生事件
while (!ifOutOfTime) //如果还未超出时间范围
generateNextEvent();
//最后停止营业
pushEvent([nextTime, null, null, null, null, null, 0, 0, null, null, null, null, null, hasServeNum, null]);
go('resultarea').value = outputResult();
}
//返回指定ID的对象
function go(id) {
return document.getElementById(id);
}
//全局变量初始化
function varInitialization() {
evnStack = [];
ifOutOfTime = false;
nextTime = 0;
customerNum = 0;
endTime = 0;
hasServeNum = 0;
idleTime = 0;
//alert(emulateTime+':'+minSpaceTime+':'+maxSpaceTime+':'+minServeTime+':'+maxServeTime);
}
//产生下一到来事件及其对应的离开事件记录
function generateNextEvent() {
var t_curTime = nextTime; //当前仿真钟
var t_reachTime = t_curTime + randomTime(minSpaceTime, maxSpaceTime); //产生随机到达时间
var t_startTime = endTime<t_curTime?t_curTime:endTime; //服务开始时间
var t_waitTime = endTime-nextTime>0 ? endTime-nextTime : 0; //等待时间>=0
var t_serveTime = randomTime(minSpaceTime, maxSpaceTime); //产生随机服务时间
var evn = new Array();
evn = [t_curTime, //仿真钟 = 上一到达事件的[下一到达时间]
1, //事件类型 1-到达
customerNum+hasServeNum+1, //顾客编号 = 系统中的顾客数+已服务的顾客数+1
t_curTime, //到达时间 = 仿真钟
t_reachTime, //下一到达时间 = 到达时间+随机间隔时间
curStatus[customerNum>0?1:2], //服务台状态 原系统中顾客数>0 --忙 原系统中顾客数=0 --闲->忙
customerNum, //队长 = 系统中的顾客数
customerNum+1, //系统中顾客数
t_startTime, //服务开始时间 = 上一顾客离去时间 或 到达时间(当离去时间<到达时间)
t_waitTime, //等待时间 = 上一顾客离去时间-到达时间
t_serveTime, //服务时间 = 随机时间长度
t_startTime+t_serveTime, //离去时间 = 服务开始时间+服务时间
t_waitTime+t_serveTime, //逗留时间 = 等待时间+服务时间
hasServeNum, //已服务人数 在updateLeaveEvent中更新
idleTime>0?idleTime:null]; //服务台闲期 idleTime在updateLeaveEvent中更新
//将此到达事件压入事件列表
pushEvent(evn);
//产生它的离开事件
generateNextLeaveEvent(evn);
//更新系统全局变量
nextTime = t_reachTime; //下一顾客到达时间
customerNum ++; //系统中顾客数加 1
endTime = endTime+t_serveTime; //离去时间
idleTime = null; //闲期
if (nextTime >= emulateTime) ifOutOfTime = true; //超出时间范围
//更新当前到达事件与下一到达事件间的所有离开事件 (系统中的顾客数, 已服务人数等)
updateLeaveEvent(t_curTime, t_reachTime);
}
//产生某个到来事件的离开事件记录
function generateNextLeaveEvent(evn) {
var levn = new Array();
levn = [evn[11], //仿真钟 = 离去时间
2, //事件类型 2-离开
evn[2], //顾客编号
null,
null,
null, //服务台状态 在updateLeaveEvent中更新
null, //队长 在updateLeaveEvent中更新
null, //系统中的顾客数 在updateLeaveEvent中更新
null,
null,
null,
evn[11], //离去时间
null,
null, //已服务人数 在updateLeaveEvent中更新
null];
//将此离开事件压入事件列表
pushEvent(levn);
}
//更新指定时间范围内的离开事件
function updateLeaveEvent(start, end) {
var evnArray = []; //指定区间内的离开事件在事件列表中的下标
for (var i=evnStack.length-1; i>=0; i--) {
if (evnStack[i][1] == 2) { //只判断离去事件
if (evnStack[i][7] != null) break; //如果已经更新,则代表前面的离开事件都已更新,退出循环
if (evnStack[i][0] >= start && evnStack[i][0] <= end) //选出在指定范围内的事件
evnArray.push(i);
}
}
for (var i=evnArray.length-1; i>=0; i--) {
customerNum -= 1; //系统中顾客数减 1
hasServeNum += 1; //已服务人数加 1
evnStack[evnArray[i]][7] = customerNum;
evnStack[evnArray[i]][13] = hasServeNum;
evnStack[evnArray[i]][5] = curStatus[customerNum>0 ? 1 : (evnStack[evnArray[i]][0]>0 ? 3 : 0)]; //服务台状态 原系统中顾客数>0 --忙 原系统中顾客数=0且仿真钟<>0 --忙->闲 原系统中顾客数=0且仿真钟=0 --闲
evnStack[evnArray[i]][6] = customerNum-1>0 ? customerNum-1 : 0; //队长 = 系统中的顾客数-1 >=0
if (evnStack[evnArray[i]][5] == curStatus[3] && i != evnStack.length) //如果服务台状态 忙->闲 则更新下一到达事件的闲期 ^不能是最后一个事件,否则数组下标溢出
idleTime = end-evnStack[evnArray[i]][0]; //保存服务台闲期
}
}
//将事件记录压入数组并排序
function pushEvent(evn) {
evnStack.push(evn);
//按仿真钟从小到大排序
evnStack.sort(function(a, b) {return a[0]-b[0]});
}
//产生一个界于两数之间的随机时间,包括边界
function randomTime(min, max) {
return Math.floor(min+Math.random()*(max-min+1));
}
//输出仿真结果表
function outputResult() {
var str;
str = '仿真钟 类型 顾客 到达 下一到达 状态 队长 顾客数 开始 等待 服务 离去 逗留 已服务 闲期';
for (var i=0; i<=evnStack.length-1; i++) {
str = str + '\r\n';
for (var j=0; j<=14; j++) {
str = str + (evnStack[i][j]==null ? '--' : evnStack[i][j]);
if (j != 14) str = str + ' ';
}
}
return str;
}
//输出统计结果
function outputStatics() {
var t_totalQueueLength = 0; //各次队长总和
var t_totalCustomerNum = 0; //各次系统中顾客数总和
var t_totalWaitTime = 0; //顾客等待时间总和
var t_totalStayTime = 0; //顾客逗留时间总和
var t_totalServeTime = 0; //顾客服务时间总和
var avgQueueLength = 0; //平均队长
var maxQueueLength = 0; //最大队长
var avgCustomerNum = 0; //系统中平均顾客数
var avgWaitTime = 0; //平均等待时间
var avgStayTime = 0; //平均逗留时间
var avgServeTime = 0; //平均服务时间
var totalIdleTime = 0; //服务器台总闲期
var percentOfIdleTime = 0; //闲期所占百分比
var totalServeCustomer = 0; //总服务顾客数
//取得最后一个在指定时间范围内的事件的编号
var stackLen = 0;
for (var i=evnStack.length-1; i>=0; i--) {
if (evnStack[i][0] <= emulateTime) {
stackLen = i;
break;
}
}
//取得总服务顾客数
for (var i=evnStack.length-1; i>=0; i--) {
if (evnStack[i][13] != null) {
totalServeCustomer = evnStack[i][13];
break;
}
}
for (var i=1; i<=stackLen; i++) {
t_totalQueueLength += evnStack[i][6]*(evnStack[i][6]-evnStack[i-1][6]);
t_totalCustomerNum += evnStack[i][7]*(evnStack[i][6]-evnStack[i-1][6]);
t_totalWaitTime += evnStack[i][9];
t_totalStayTime += evnStack[i][12];
totalIdleTime += evnStack[i][14];
if (evnStack[i][6] > maxQueueLength) maxQueueLength = evnStack[i][6];
}
t_totalServeTime = t_totalStayTime - t_totalWaitTime;
avgQueueLength = Math.round(t_totalQueueLength/emulateTime);
avgCustomerNum = Math.round(t_totalCustomerNum/emulateTime);
avgWaitTime = t_totalWaitTime/totalServeCustomer;
avgStayTime = t_totalStayTime/totalServeCustomer;
avgServeTime = t_totalServeTime/totalServeCustomer;
percentOfIdleTime = totalIdleTime*100/emulateTime;
var returnStr;
returnStr = '平均队长:' + avgQueueLength + '<br />'
+ '最大队长:' + maxQueueLength + '<br />'
+ '系统中平均顾客数:' + avgCustomerNum + '<br />'
+ '平均等待时间:' + avgWaitTime.toFixed(2) + '<br />'
+ '平均逗留时间:' + avgStayTime.toFixed(2) + '<br />'
+ '平均服务时间:' + avgServeTime.toFixed(2) + '<br />'
+ '服务器台总闲期:' + totalIdleTime + '<br />'
+ '闲期所占百分比:' + percentOfIdleTime.toFixed(2) + '%<br />'
+ '总服务顾客数:' + totalServeCustomer;
return returnStr;
}
//事件结构定义
//仿真钟 事件类型 顾客 到达时间 下一到达时间 服务台状态 队长 系统中顾客数 服务开始时间 等待时间 服务时间 离去时间 逗留时间 已服务人数 服务台闲期
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -