Light12306/Web12306/js/platform/DifficultyCalculator.js
2015-11-23 01:49:27 +08:00

372 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

define(function (require, exports, module) {
var data = require("../data.js");
var queryTicket = require("../otn/queryticket.js");
var cache = null;
var lastKey = null;
var levelDesc = [
{
color: "#66B769",
name: "容易",
star: "一星",
desc: "一般情况下,购买此车次可比其它车次略容易一点。"
},
{
color: "#829CDA",
name: "普通",
star: "二星",
desc: "此车次购买容易程度处于中间平均的水平上。"
},
{
color: "#DE8439",
name: "略难",
star: "三星",
desc: "此车次特定情况下可能会比较难买。多留意跨站信息。"
},
{
color: "#CE5353",
name: "较难",
star: "四星",
desc: "高峰期可能会难以购买此次列车,如果有其它选择,可优先考虑其它车次。"
},
{
color: "#FF0000",
name: "困难",
star: "五星",
desc: "买买买!买到就是赚到!建议同时考虑其它可能购买车次!!"
}
];
var hotLineManual = {
"670000T1280C": {
hot: 2,
ratio: null,
startHot: 1,
endHot: 1
},
"760000T12607": {
hot: 2,
ratio: null,
startHot: 1,
endHot: 1
}
};
/**
* 额外的难度系数,用于调整一些特定线路的难度系数
*/
var extraRatioMatrix = [
[/(乌鲁木齐南?|兰州)/, 2],
[/拉萨/, 2],
[/哈尔滨[东西北]?/, 1.5],
[/长春[西南]?/, 1.5],
[/成都[东南]?/, 2]
];
var hotLineMatrix = [
{
type: 0, //单向,节前顺向,节后逆向
from: [
/广州[东北南]?/,
/深圳[东西南]?/
],
to: [
/郑州东?/,
/重庆[南北]?/,
/(武[昌汉]|汉口)/,
/(达州|兰州|常德|乌鲁木齐南|潮汕|饶平|拉萨)/,
/成都[东南]?/,
/岳阳东?/,
/长沙南?/,
/衡阳东?/,
/襄阳东?/,
/西安[南北]?/,
/哈尔滨[东西北]?/,
/长春[西南]?/
]
},
{
type: 0, //单向,节前顺向,节后逆向
from: [
/北京[东西南北]?/
],
to: [
/(武[昌汉]|汉口)/,
/长沙南?/,
/宝鸡南?/,
/重庆[南北]?/,
/成都[东南]?/,
/(兰州|乌鲁木齐南|拉萨)/,
/西安[南北]?/,
/哈尔滨[东西北]?/,
/长春[西南]/
]
},
{
type: 0,
from: [
/上海([西南]|虹桥)?/
],
to: [
/重庆[南北]?/,
/成都[东南]?/,
/哈尔滨[东西北]?/,
/长春[西南]/,
/广州[东北南]?/,
/西安[南北]?/,
/郑州东?/,
/怀化南?/,
/(武[昌汉]|汉口)/,
/(达州|兰州|乌鲁木齐南|南充|拉萨)/
]
},
{
type: 0,
to: [
/成都[东南]?/
],
from: [
/上海([西南]|虹桥)?/,
/深圳[东西北]?/,
/东莞东?/,
/杭州东?/,
/北京[东西南北]?/,
/哈尔滨[东西北]?/,
/长春[西南]/,
/广州[东北南]?/,
/西安[南北]?/,
/宁波南?/,
/温州南?/,
/福州南?/,
/(武[昌汉]|汉口)/,
/(达州|兰州|乌鲁木齐南|南充|拉萨)/,
/苏州(北|新区|园区)?/
]
},
{
type: 1, //双向
from: [
/(武[昌汉]|汉口)/
],
to: [
/重庆[南北]?/,
/成都[东南]?/,
/哈尔滨[东西北]?/,
/长春[西南]?/
]
}
];
var isDifficultyEnabled = function (date) {
if (!/(\d{4})-(0?\d+)-(0?\d+)/.exec(date || ""))
return false;
var year = parseInt(RegExp.$1, 10);
var month = parseInt(RegExp.$2, 10);
var day = parseInt(RegExp.$3, 10);
return year === 2016 && month < 3;
};
/**
* 判断指定的日期是否是回乡日期
* @param {string} date 具体日期
* @returns {boolean} 如果是回乡日期,则返回 true否则返回 false
*/
var isBackHome = function (date) {
if (!/(\d{4})-(0?\d+)-(0?\d+)/.exec(date || ""))
return false;
var year = parseInt(RegExp.$1, 10);
var month = parseInt(RegExp.$2, 10);
var day = parseInt(RegExp.$3, 10);
return month < 2 || (month === 2 && day <= 8);
};
/**
* 计算单个车次的购票难度
* @param {object} train 车次
* @param {Array} originalTrains 原始车次
*/
var calculateTrainDifficulty = function (train, originalTrains) {
train.dp = {};
//城铁
if (train.code[0] === 'C') {
train.dp.difficulty = 20;
train.dp.point = 2;
return;
}
var ratio = 40;
//是否是热门车次以及回乡
var isBack = isBackHome(train.date);
var isHotLine = (function () {
var data = hotLineManual[train.id];
if (data) {
ratio = data.ratio || ratio;
train.start.isHot = data.startHot;
train.end.isHot = data.endHot;
train.dp.hotRatio = data.hot;
return data.hot > 0;
}
var points = _.map(hotLineMatrix, function (l) {
var startHot = false, endHot = false, hotRatio = 0;
if (l.type === 0) {
startHot = _.any(!isBack ? l.to : l.from, function (r) {
return r.test(train.start.name) || r.test(train.from.name)
}) ? 1 : 0;
endHot = _.any(!isBack ? l.from : l.to, function (r) {
return r.test(train.end.name) || r.test(train.to.name)
}) ? 1 : 0;
} else {
startHot = _.any(l.to, function (r) {
return r.test(train.start.name)
}) ? 1 : 0 || _.any(l.from, function (r) {
return r.test(train.start.name) || r.test(train.from.name)
}) ? 1 : 0;
endHot = _.any(l.to, function (r) {
return r.test(train.end.name)
}) ? 1 : 0 || _.any(l.from, function (r) {
return r.test(train.end.name) || r.test(train.to.name)
}) ? 1 : 0;
}
hotRatio = (startHot ? 1 : 0) + (endHot ? 1 : 0);
return [startHot, endHot, hotRatio];
});
if (points.length) {
var hr = _.max(points, function (h) {
return h[2];
});
train.start.isHot = hr[0] > 0;
train.end.isHot = hr[1] > 0;
train.dp.hotRatio = hr[2];
return true;
}
return false;
})();
/*
* 基础购票难度系数均为40特殊车次直接指定
* 列车始发站、终到站如果命中任意一条规则,则难度+20
* 如果车次非始发站或非终到站则每次难度均加10*区域额外难度系数非热门线路或30热门线路
* 15点后24点前发Z、T 车次难度加60或40热门线路
* DG车非热门线路难度减10
* 非热门线路始发终到满足任意一个条件则难度减5
*
* 最终难度区间10-未知,越高越难
*/
var isHs = /^[GD]/i.test(train.code);
var isZt = /^[ZT]/i.test(train.code);
//额外难度系数
var extraRatio = Math.max(_.max(_.map(extraRatioMatrix, function (erm) {
return erm[0].test(train.start.name) || erm[0].test(train.end.name) || erm[0].test(train.from.name) || erm[0].test(train.to.name) ? erm[1] : 0;
})), 1);
/*
* 考虑车次数量和分布。
* 如果没有GD则额外难度系数 *1.1
* 如果车次总数量小于3则额外难度系数*2
* 如果车辆总数小于6则额外难度系数*1.5
* 如果车辆总数小于10则额外难度系数*1.1
*/
if (originalTrains) {
if (originalTrains.length < 3)
extraRatio *= 2;
else if (originalTrains.length < 6)
extraRatio *= 1.5;
else if (originalTrains.length < 10)
extraRatio *= 1.1;
if (!_.any(originalTrains, function (train) {
return /[GDC]/.test(train.code[0]);
}))
extraRatio *= 1.1;
}
if (isHotLine)
ratio += 20 * train.dp.hotRatio * (isZt ? 1.5 : 1) * extraRatio;
//非始发站
if (!train.from.endpoint)
ratio += (train.start.isHot ? 60 : (isZt ? 40 : 20) * extraRatio);
//非终到站
if (!train.to.endpoint)
ratio += (train.end.isHot ? 60 : (isZt ? 40 : 20) * extraRatio);
//15点以后的ZT
if (isZt && parseInt(/^0?(\d+)/.exec(train.from.time)[1], 10) >= 15) {
ratio += isHotLine ? 60 : 40;
}
if (!isHotLine) {
if (isHs)
ratio -= 10;
if (train.from.endpoint)
ratio -= 10;
if (train.to.endpoint)
ratio -= 10;
}
train.dp.difficulty = ratio;
train.dp.point = ratio / 10;
};
/**
* 设置对应车次的困难度提示信息
* @param {} train
* @returns {}
*/
var setDifficultyInfo = function (train) {
var dp = train.dp;
var level = Math.min(Math.floor(dp.point / 4), 4);
_.extend(dp, levelDesc[level]);
};
/**
* 计算车次购票难度。最终难度区间10-200指数越高越难。
* @param {Array} trains 要计算的车次
*/
var calculateTrainsDifficulty = function (trains) {
_.each(trains, function (train) {
calculateTrainDifficulty(train);
setDifficultyInfo(train);
});
cache = _.map(trains, function (t) {
return {id: t.id, dp: t.dp};
});
};
queryTicket.events.on("processTrains", function (e, data) {
if (!isDifficultyEnabled(data.query.date))
return;
var key = data.query.from + data.query.to + data.query.date;
if (key === lastKey) {
_.each(data.available, function (train) {
var dpe = _.findWhere(cache, {id: train.id});
if (!dpe) {
calculateTrainDifficulty(train, data.original);
setDifficultyInfo(train);
cache[train.id] = {id: train.id, dp: train.dp};
} else {
train.dp = dpe.dp;
}
});
} else {
lastKey = key;
calculateTrainsDifficulty(data.available, data.original);
}
});
});