From 5ad0da0bc98856988f33b680294366a964515cbb Mon Sep 17 00:00:00 2001 From: irrygan Date: Fri, 21 Oct 2016 12:34:50 +0500 Subject: [PATCH 1/9] initial commit --- robbery.js | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 3 deletions(-) diff --git a/robbery.js b/robbery.js index 4a8309d..209bc0a 100644 --- a/robbery.js +++ b/robbery.js @@ -6,6 +6,74 @@ */ exports.isStar = true; +var DAYS = [ + 'ПН', 'ВТ', 'СР', 'ЧТ', + 'ПТ', 'СБ', 'ВС' +]; +var WEEK_START = Date.parse('1 1 1970 00:00 GMT') / 1000; +var DEADLINE = Date.parse('1 3 1970 23:59 GMT') / 1000; +var THIRTY_MINUTES = 1800; + +function dateToTimestamp(str) { + for (var i = 0; i < DAYS.length; i++) { + str = str.replace(DAYS[i], i + 1); + } + str = str.replace(/(\d) (\d{2}:\d{2})(\+\d+)?/, '1 $1 1970 $2 GMT$3'); + + return Date.parse(str) / 1000; +} + +function toTimestampInterval(interval) { + return { + 'from': dateToTimestamp(interval.from), + 'to': dateToTimestamp(interval.to) + }; +} + +function normalizeSchedule(schedule) { + var busyIntervals = []; + + Object.keys(schedule).forEach(function (thug) { + var busy = schedule[thug].map(toTimestampInterval); + busyIntervals = busyIntervals.concat(busy); + }); + busyIntervals = busyIntervals.sort(function (one, another) { + return one.from < another.from ? -1 : 1; + }); + + return busyIntervals; +} + +function getWorkingDAYS(workingHours) { + var workingDAYS = []; + for (var i = 0; i < 3; i++) { + var from = DAYS[i] + ' ' + workingHours.from; + var to = DAYS[i] + ' ' + workingHours.to; + workingDAYS.push({ + 'from': dateToTimestamp(from), + 'to': dateToTimestamp(to) + }); + } + + return workingDAYS; +} + +function getSpareTimes(schedule) { + var spareTime = []; + var current = WEEK_START; + for (var i = 0; i < schedule.length; i++) { + if (current > schedule[i].from) { + current = current < schedule[i].to ? schedule[i].to : current; + continue; + } + spareTime.push({ 'from': current, 'to': schedule[i].from }); + current = schedule[i].to; + } + spareTime.push({ 'from': current, 'to': DEADLINE }); + + return spareTime; +} + /** * @param {Object} schedule – Расписание Банды * @param {Number} duration - Время на ограбление в минутах @@ -15,7 +83,24 @@ exports.isStar = true; * @returns {Object} */ exports.getAppropriateMoment = function (schedule, duration, workingHours) { - console.info(schedule, duration, workingHours); + schedule = normalizeSchedule(schedule); + duration *= 60; + var workingDAYS = getWorkingDAYS(workingHours); + var bankTimezone = parseInt(/\+(\d+)$/.exec(workingHours.from)[1]); + var spareTime = getSpareTimes(schedule); + + var robberyTime = []; + workingDAYS.forEach(function (workingDay) { + var possible = []; + for (var j = 0; j < spareTime.length; j++) { + var minTo = Math.min(workingDay.to, spareTime[j].to); + var maxFrom = Math.max(workingDay.from, spareTime[j].from); + if (minTo - maxFrom >= duration) { + possible.push({ 'from': maxFrom, 'to': minTo }); + } + } + robberyTime = robberyTime.concat(possible); + }); return { @@ -24,7 +109,7 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {Boolean} */ exists: function () { - return false; + return robberyTime.length > 0; }, /** @@ -35,7 +120,22 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {String} */ format: function (template) { - return template; + if (robberyTime.length === 0) { + return ''; + } + var date = new Date(); + date.setTime(robberyTime[0].from * 1000); + + var minutes = date + .getUTCMinutes() + .toLocaleString(undefined, { 'minimumIntegerDigits': 2 }); + var hours = (date.getUTCHours() + bankTimezone) + .toLocaleString(undefined, { 'minimumIntegerDigits': 2 }); + + return template + .replace('%HH', hours) + .replace('%MM', minutes) + .replace('%DD', DAYS[date.getUTCDate() - 1]); }, /** @@ -44,6 +144,21 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {Boolean} */ tryLater: function () { + if (!this.exists()) { + return false; + } + + if (robberyTime[0].to - robberyTime[0].from - THIRTY_MINUTES >= duration) { + robberyTime[0].from = robberyTime[0].from + THIRTY_MINUTES; + + return true; + } + if (robberyTime.length > 1) { + robberyTime.shift(); + + return true; + } + return false; } }; From b07ebf2d5901dd69c75ddfa64b5bda7497f5135f Mon Sep 17 00:00:00 2001 From: irrygan Date: Fri, 21 Oct 2016 13:12:24 +0500 Subject: [PATCH 2/9] normal sorting, normal time conversion --- robbery.js | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/robbery.js b/robbery.js index 209bc0a..d7d321e 100644 --- a/robbery.js +++ b/robbery.js @@ -32,44 +32,52 @@ function toTimestampInterval(interval) { function normalizeSchedule(schedule) { var busyIntervals = []; - Object.keys(schedule).forEach(function (thug) { var busy = schedule[thug].map(toTimestampInterval); busyIntervals = busyIntervals.concat(busy); }); busyIntervals = busyIntervals.sort(function (one, another) { - return one.from < another.from ? -1 : 1; + if (one.from < another.from) { + return -1; + } + if (one.from > another.from) { + return 1; + } + + return 0; }); return busyIntervals; } -function getWorkingDAYS(workingHours) { - var workingDAYS = []; +function getWorkingDays(workingHours) { + var workingDays = []; for (var i = 0; i < 3; i++) { var from = DAYS[i] + ' ' + workingHours.from; var to = DAYS[i] + ' ' + workingHours.to; - workingDAYS.push({ + workingDays.push({ 'from': dateToTimestamp(from), 'to': dateToTimestamp(to) }); } - return workingDAYS; + return workingDays; } function getSpareTimes(schedule) { var spareTime = []; var current = WEEK_START; for (var i = 0; i < schedule.length; i++) { - if (current > schedule[i].from) { + if (current >= schedule[i].from) { current = current < schedule[i].to ? schedule[i].to : current; continue; } spareTime.push({ 'from': current, 'to': schedule[i].from }); current = schedule[i].to; } - spareTime.push({ 'from': current, 'to': DEADLINE }); + if (current < DEADLINE) { + spareTime.push({ 'from': current, 'to': DEADLINE }); + } return spareTime; } @@ -85,12 +93,12 @@ function getSpareTimes(schedule) { exports.getAppropriateMoment = function (schedule, duration, workingHours) { schedule = normalizeSchedule(schedule); duration *= 60; - var workingDAYS = getWorkingDAYS(workingHours); + var workingDays = getWorkingDays(workingHours); var bankTimezone = parseInt(/\+(\d+)$/.exec(workingHours.from)[1]); var spareTime = getSpareTimes(schedule); var robberyTime = []; - workingDAYS.forEach(function (workingDay) { + workingDays.forEach(function (workingDay) { var possible = []; for (var j = 0; j < spareTime.length; j++) { var minTo = Math.min(workingDay.to, spareTime[j].to); @@ -124,12 +132,13 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { return ''; } var date = new Date(); - date.setTime(robberyTime[0].from * 1000); + date.setTime((robberyTime[0].from + bankTimezone * 3600) * 1000); var minutes = date .getUTCMinutes() .toLocaleString(undefined, { 'minimumIntegerDigits': 2 }); - var hours = (date.getUTCHours() + bankTimezone) + var hours = date + .getUTCHours() .toLocaleString(undefined, { 'minimumIntegerDigits': 2 }); return template From 1ab07b7cc1b715d46f8ae93076d7a0f358ec327b Mon Sep 17 00:00:00 2001 From: irrygan Date: Fri, 21 Oct 2016 13:31:37 +0500 Subject: [PATCH 3/9] set deadline and weekstart to bank timezone --- robbery.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/robbery.js b/robbery.js index d7d321e..05cf575 100644 --- a/robbery.js +++ b/robbery.js @@ -10,8 +10,6 @@ var DAYS = [ 'ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ', 'ВС' ]; -var WEEK_START = Date.parse('1 1 1970 00:00 GMT') / 1000; -var DEADLINE = Date.parse('1 3 1970 23:59 GMT') / 1000; var THIRTY_MINUTES = 1800; function dateToTimestamp(str) { @@ -64,9 +62,9 @@ function getWorkingDays(workingHours) { return workingDays; } -function getSpareTimes(schedule) { +function getSpareTimes(schedule, weekStart, deadline) { var spareTime = []; - var current = WEEK_START; + var current = weekStart; for (var i = 0; i < schedule.length; i++) { if (current >= schedule[i].from) { current = current < schedule[i].to ? schedule[i].to : current; @@ -75,8 +73,8 @@ function getSpareTimes(schedule) { spareTime.push({ 'from': current, 'to': schedule[i].from }); current = schedule[i].to; } - if (current < DEADLINE) { - spareTime.push({ 'from': current, 'to': DEADLINE }); + if (current < deadline) { + spareTime.push({ 'from': current, 'to': deadline }); } return spareTime; @@ -95,7 +93,9 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { duration *= 60; var workingDays = getWorkingDays(workingHours); var bankTimezone = parseInt(/\+(\d+)$/.exec(workingHours.from)[1]); - var spareTime = getSpareTimes(schedule); + var weekStart = Date.parse('1 1 1970 00:00 GMT+' + bankTimezone) / 1000; + var deadline = Date.parse('1 3 1970 23:59 GMT+' + bankTimezone) / 1000; + var spareTime = getSpareTimes(schedule, weekStart, deadline); var robberyTime = []; workingDays.forEach(function (workingDay) { From 798e94d82f5b1486bfdc222a5db036af52f361c2 Mon Sep 17 00:00:00 2001 From: irrygan Date: Fri, 21 Oct 2016 21:43:29 +0500 Subject: [PATCH 4/9] refactoring --- robbery.js | 151 ++++++++++++++++++++++++++++------------------------- 1 file changed, 80 insertions(+), 71 deletions(-) diff --git a/robbery.js b/robbery.js index 05cf575..1d16e53 100644 --- a/robbery.js +++ b/robbery.js @@ -6,78 +6,95 @@ */ exports.isStar = true; -var DAYS = [ - 'ПН', 'ВТ', 'СР', 'ЧТ', - 'ПТ', 'СБ', 'ВС' -]; -var THIRTY_MINUTES = 1800; +var DAYS = ['ПН', 'ВТ', 'СР']; function dateToTimestamp(str) { for (var i = 0; i < DAYS.length; i++) { str = str.replace(DAYS[i], i + 1); } + + /* Будем считать, что понедельник - 1 января 1970 года. + * соответственно банк меняет сигнализацию 4 января 1970 года. + */ str = str.replace(/(\d) (\d{2}:\d{2})(\+\d+)?/, '1 $1 1970 $2 GMT$3'); - return Date.parse(str) / 1000; + return Date.parse(str); } function toTimestampInterval(interval) { return { - 'from': dateToTimestamp(interval.from), - 'to': dateToTimestamp(interval.to) + from: dateToTimestamp(interval.from), + to: dateToTimestamp(interval.to) }; } -function normalizeSchedule(schedule) { +function getBusyIntervals(schedule) { var busyIntervals = []; Object.keys(schedule).forEach(function (thug) { var busy = schedule[thug].map(toTimestampInterval); busyIntervals = busyIntervals.concat(busy); }); - busyIntervals = busyIntervals.sort(function (one, another) { - if (one.from < another.from) { - return -1; - } - if (one.from > another.from) { - return 1; - } - return 0; + return busyIntervals.sort(function (one, another) { + return Math.sign(one.from - another.from); }); - - return busyIntervals; } function getWorkingDays(workingHours) { - var workingDays = []; - for (var i = 0; i < 3; i++) { - var from = DAYS[i] + ' ' + workingHours.from; - var to = DAYS[i] + ' ' + workingHours.to; - workingDays.push({ - 'from': dateToTimestamp(from), - 'to': dateToTimestamp(to) + return DAYS.reduce(function (acc, day) { + var from = day + ' ' + workingHours.from; + var to = day + ' ' + workingHours.to; + acc.push({ + from: dateToTimestamp(from), + to: dateToTimestamp(to) }); - } - return workingDays; + return acc; + }, []); } -function getSpareTimes(schedule, weekStart, deadline) { - var spareTime = []; +function invertBusyIntervals(busyIntervals, weekStart, deadline) { + var spareIntervals = []; var current = weekStart; - for (var i = 0; i < schedule.length; i++) { - if (current >= schedule[i].from) { - current = current < schedule[i].to ? schedule[i].to : current; + for (var i = 0; i < busyIntervals.length; i++) { + if (current >= busyIntervals[i].from) { + current = current < busyIntervals[i].to ? busyIntervals[i].to : current; continue; } - spareTime.push({ 'from': current, 'to': schedule[i].from }); - current = schedule[i].to; + spareIntervals.push({ + from: current, + to: busyIntervals[i].from + }); + current = busyIntervals[i].to; } if (current < deadline) { - spareTime.push({ 'from': current, 'to': deadline }); + spareIntervals.push({ + from: current, + to: deadline + }); + } + + return spareIntervals; +} + +function getRobberyIntervals(spareIntervals, workingDay, durationInMilliseconds) { + var robberyIntervals = []; + for (var j = 0; j < spareIntervals.length; j++) { + var minTo = Math.min(workingDay.to, spareIntervals[j].to); + var maxFrom = Math.max(workingDay.from, spareIntervals[j].from); + if (minTo - maxFrom >= durationInMilliseconds) { + robberyIntervals.push({ + from: maxFrom, + to: minTo + }); + } } - return spareTime; + return robberyIntervals; +} + +function padNumberLeft(number, length) { + return number.toLocaleString(undefined, { 'minimumIntegerDigits': length }); } /** @@ -89,25 +106,18 @@ function getSpareTimes(schedule, weekStart, deadline) { * @returns {Object} */ exports.getAppropriateMoment = function (schedule, duration, workingHours) { - schedule = normalizeSchedule(schedule); - duration *= 60; - var workingDays = getWorkingDays(workingHours); - var bankTimezone = parseInt(/\+(\d+)$/.exec(workingHours.from)[1]); - var weekStart = Date.parse('1 1 1970 00:00 GMT+' + bankTimezone) / 1000; - var deadline = Date.parse('1 3 1970 23:59 GMT+' + bankTimezone) / 1000; - var spareTime = getSpareTimes(schedule, weekStart, deadline); - - var robberyTime = []; - workingDays.forEach(function (workingDay) { - var possible = []; - for (var j = 0; j < spareTime.length; j++) { - var minTo = Math.min(workingDay.to, spareTime[j].to); - var maxFrom = Math.max(workingDay.from, spareTime[j].from); - if (minTo - maxFrom >= duration) { - possible.push({ 'from': maxFrom, 'to': minTo }); - } - } - robberyTime = robberyTime.concat(possible); + var bankTimezone = parseInt(/\+(\d+)$/.exec(workingHours.from)[1], 10); + var weekStart = dateToTimestamp('ПН 00:00+' + bankTimezone); + var deadline = dateToTimestamp('СР 23:59+' + bankTimezone); + + var busyIntervals = getBusyIntervals(schedule); + var spareIntervals = invertBusyIntervals(busyIntervals, weekStart, deadline); + + var durationInMilliseconds = duration * 60 * 1000; + var robberyIntervals = []; + getWorkingDays(workingHours).forEach(function (workingDay) { + var intervals = getRobberyIntervals(spareIntervals, workingDay, durationInMilliseconds); + robberyIntervals = robberyIntervals.concat(intervals); }); return { @@ -117,7 +127,7 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {Boolean} */ exists: function () { - return robberyTime.length > 0; + return robberyIntervals.length > 0; }, /** @@ -128,23 +138,20 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {String} */ format: function (template) { - if (robberyTime.length === 0) { + if (robberyIntervals.length === 0) { return ''; } - var date = new Date(); - date.setTime((robberyTime[0].from + bankTimezone * 3600) * 1000); - var minutes = date - .getUTCMinutes() - .toLocaleString(undefined, { 'minimumIntegerDigits': 2 }); - var hours = date - .getUTCHours() - .toLocaleString(undefined, { 'minimumIntegerDigits': 2 }); + var hourInMilliseconds = 60 * 60 * 1000; + var date = new Date(robberyIntervals[0].from + bankTimezone * hourInMilliseconds); + var minutes = padNumberLeft(date.getUTCMinutes(), 2); + var hours = padNumberLeft(date.getUTCHours(), 2); + var day = DAYS[date.getUTCDate() - 1]; return template .replace('%HH', hours) .replace('%MM', minutes) - .replace('%DD', DAYS[date.getUTCDate() - 1]); + .replace('%DD', day); }, /** @@ -157,13 +164,15 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { return false; } - if (robberyTime[0].to - robberyTime[0].from - THIRTY_MINUTES >= duration) { - robberyTime[0].from = robberyTime[0].from + THIRTY_MINUTES; + var halfHourInMilliseconds = 30 * 60 * 1000; + var delayedRobberyStart = robberyIntervals[0].from + halfHourInMilliseconds; + if (robberyIntervals[0].to - delayedRobberyStart >= durationInMilliseconds) { + robberyIntervals[0].from = delayedRobberyStart; return true; } - if (robberyTime.length > 1) { - robberyTime.shift(); + if (robberyIntervals.length > 1) { + robberyIntervals.shift(); return true; } From 42cd467fb88b9daee1145e1e9fbed858a5eac4b6 Mon Sep 17 00:00:00 2001 From: irrygan Date: Sat, 22 Oct 2016 14:29:09 +0500 Subject: [PATCH 5/9] more refactoring --- robbery.js | 86 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/robbery.js b/robbery.js index 1d16e53..8f3e8b7 100644 --- a/robbery.js +++ b/robbery.js @@ -9,16 +9,17 @@ exports.isStar = true; var DAYS = ['ПН', 'ВТ', 'СР']; function dateToTimestamp(str) { - for (var i = 0; i < DAYS.length; i++) { - str = str.replace(DAYS[i], i + 1); - } + var utcTimeString = str; + DAYS.forEach(function (day, i) { + utcTimeString = utcTimeString.replace(day, i + 1); + }); /* Будем считать, что понедельник - 1 января 1970 года. * соответственно банк меняет сигнализацию 4 января 1970 года. */ - str = str.replace(/(\d) (\d{2}:\d{2})(\+\d+)?/, '1 $1 1970 $2 GMT$3'); + utcTimeString = utcTimeString.replace(/(\d) (\d{2}:\d{2})(\+\d+)?/, '1 $1 1970 $2 GMT$3'); - return Date.parse(str); + return Date.parse(utcTimeString); } function toTimestampInterval(interval) { @@ -29,44 +30,44 @@ function toTimestampInterval(interval) { } function getBusyIntervals(schedule) { - var busyIntervals = []; - Object.keys(schedule).forEach(function (thug) { + return Object.keys(schedule).reduce(function (acc, thug) { var busy = schedule[thug].map(toTimestampInterval); - busyIntervals = busyIntervals.concat(busy); - }); + acc = acc.concat(busy); - return busyIntervals.sort(function (one, another) { - return Math.sign(one.from - another.from); - }); + return acc; + }, []); } function getWorkingDays(workingHours) { - return DAYS.reduce(function (acc, day) { + return DAYS.map(function (day) { var from = day + ' ' + workingHours.from; var to = day + ' ' + workingHours.to; - acc.push({ + + return { from: dateToTimestamp(from), to: dateToTimestamp(to) - }); - - return acc; - }, []); + }; + }); } function invertBusyIntervals(busyIntervals, weekStart, deadline) { + var sortedBusyIntervals = busyIntervals.slice().sort(function (one, another) { + return Math.sign(one.from - another.from); + }); var spareIntervals = []; var current = weekStart; - for (var i = 0; i < busyIntervals.length; i++) { - if (current >= busyIntervals[i].from) { - current = current < busyIntervals[i].to ? busyIntervals[i].to : current; - continue; + sortedBusyIntervals.forEach(function (interval) { + if (current >= interval.from) { + current = current < interval.to ? interval.to : current; + + return; } spareIntervals.push({ from: current, - to: busyIntervals[i].from + to: interval.from }); - current = busyIntervals[i].to; - } + current = interval.to; + }); if (current < deadline) { spareIntervals.push({ from: current, @@ -77,18 +78,20 @@ function invertBusyIntervals(busyIntervals, weekStart, deadline) { return spareIntervals; } -function getRobberyIntervals(spareIntervals, workingDay, durationInMilliseconds) { +function getRobberyIntervals(spareIntervals, workingDays, durationInMilliseconds) { var robberyIntervals = []; - for (var j = 0; j < spareIntervals.length; j++) { - var minTo = Math.min(workingDay.to, spareIntervals[j].to); - var maxFrom = Math.max(workingDay.from, spareIntervals[j].from); - if (minTo - maxFrom >= durationInMilliseconds) { - robberyIntervals.push({ - from: maxFrom, - to: minTo - }); - } - } + spareIntervals.forEach(function (interval) { + workingDays.forEach(function (day) { + var minTo = Math.min(day.to, interval.to); + var maxFrom = Math.max(day.from, interval.from); + if (minTo - maxFrom >= durationInMilliseconds) { + robberyIntervals.push({ + from: maxFrom, + to: minTo + }); + } + }); + }); return robberyIntervals; } @@ -114,11 +117,12 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { var spareIntervals = invertBusyIntervals(busyIntervals, weekStart, deadline); var durationInMilliseconds = duration * 60 * 1000; - var robberyIntervals = []; - getWorkingDays(workingHours).forEach(function (workingDay) { - var intervals = getRobberyIntervals(spareIntervals, workingDay, durationInMilliseconds); - robberyIntervals = robberyIntervals.concat(intervals); - }); + var workingDays = getWorkingDays(workingHours); + var robberyIntervals = getRobberyIntervals( + spareIntervals, + workingDays, + durationInMilliseconds + ); return { From 244ed59f7ef65298b071bec4b2d5349fc275617e Mon Sep 17 00:00:00 2001 From: irrygan Date: Mon, 24 Oct 2016 09:30:50 +0500 Subject: [PATCH 6/9] even more refactoring --- robbery.js | 66 +++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/robbery.js b/robbery.js index 8f3e8b7..2d93c19 100644 --- a/robbery.js +++ b/robbery.js @@ -8,18 +8,23 @@ exports.isStar = true; var DAYS = ['ПН', 'ВТ', 'СР']; -function dateToTimestamp(str) { - var utcTimeString = str; +function dateToTimestamp(date) { + var isoDate = date; DAYS.forEach(function (day, i) { - utcTimeString = utcTimeString.replace(day, i + 1); + isoDate = isoDate.replace(day, i + 1); }); /* Будем считать, что понедельник - 1 января 1970 года. - * соответственно банк меняет сигнализацию 4 января 1970 года. - */ - utcTimeString = utcTimeString.replace(/(\d) (\d{2}:\d{2})(\+\d+)?/, '1 $1 1970 $2 GMT$3'); + соответственно банк меняет сигнализацию 4 января 1970 года. */ + isoDate = isoDate.replace(/(\d) (\d{2}:\d{2})(\+\d+)?/, '1 $1 1970 $2 GMT$3'); - return Date.parse(utcTimeString); + return Date.parse(isoDate); +} + +function getTimezone(time) { + var match = /\+(\d+)$/.exec(time); + + return match && Number(match[1]); } function toTimestampInterval(interval) { @@ -57,16 +62,13 @@ function invertBusyIntervals(busyIntervals, weekStart, deadline) { var spareIntervals = []; var current = weekStart; sortedBusyIntervals.forEach(function (interval) { - if (current >= interval.from) { - current = current < interval.to ? interval.to : current; - - return; + if (current < interval.from) { + spareIntervals.push({ + from: current, + to: interval.from + }); } - spareIntervals.push({ - from: current, - to: interval.from - }); - current = interval.to; + current = current < interval.to ? interval.to : current; }); if (current < deadline) { spareIntervals.push({ @@ -109,7 +111,7 @@ function padNumberLeft(number, length) { * @returns {Object} */ exports.getAppropriateMoment = function (schedule, duration, workingHours) { - var bankTimezone = parseInt(/\+(\d+)$/.exec(workingHours.from)[1], 10); + var bankTimezone = getTimezone(workingHours.from); var weekStart = dateToTimestamp('ПН 00:00+' + bankTimezone); var deadline = dateToTimestamp('СР 23:59+' + bankTimezone); @@ -142,7 +144,7 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {String} */ format: function (template) { - if (robberyIntervals.length === 0) { + if (!this.exists()) { return ''; } @@ -164,21 +166,19 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {Boolean} */ tryLater: function () { - if (!this.exists()) { - return false; - } - - var halfHourInMilliseconds = 30 * 60 * 1000; - var delayedRobberyStart = robberyIntervals[0].from + halfHourInMilliseconds; - if (robberyIntervals[0].to - delayedRobberyStart >= durationInMilliseconds) { - robberyIntervals[0].from = delayedRobberyStart; - - return true; - } - if (robberyIntervals.length > 1) { - robberyIntervals.shift(); - - return true; + if (this.exists()) { + var halfHourInMilliseconds = 30 * 60 * 1000; + var delayedRobberyStart = robberyIntervals[0].from + halfHourInMilliseconds; + if (robberyIntervals[0].to - delayedRobberyStart >= durationInMilliseconds) { + robberyIntervals[0].from = delayedRobberyStart; + + return true; + } + if (robberyIntervals.length > 1) { + robberyIntervals.shift(); + + return true; + } } return false; From cf94374837f31b29470c08a17faed4f21c10d87e Mon Sep 17 00:00:00 2001 From: irrygan Date: Mon, 24 Oct 2016 20:40:11 +0500 Subject: [PATCH 7/9] bug fix + refactoring --- robbery.js | 61 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/robbery.js b/robbery.js index 2d93c19..f244d38 100644 --- a/robbery.js +++ b/robbery.js @@ -16,13 +16,13 @@ function dateToTimestamp(date) { /* Будем считать, что понедельник - 1 января 1970 года. соответственно банк меняет сигнализацию 4 января 1970 года. */ - isoDate = isoDate.replace(/(\d) (\d{2}:\d{2})(\+\d+)?/, '1 $1 1970 $2 GMT$3'); + isoDate = isoDate.replace(/^(\d) (\d{2}:\d{2})(\+\d+)$/, '1 $1 1970 $2 UTC$3'); return Date.parse(isoDate); } function getTimezone(time) { - var match = /\+(\d+)$/.exec(time); + var match = /^\d{2}:\d{2}\+(\d+)$/.exec(time); return match && Number(match[1]); } @@ -35,11 +35,10 @@ function toTimestampInterval(interval) { } function getBusyIntervals(schedule) { - return Object.keys(schedule).reduce(function (acc, thug) { - var busy = schedule[thug].map(toTimestampInterval); - acc = acc.concat(busy); - - return acc; + return Object.keys(schedule).reduce(function (busyIntervals, thugName) { + return busyIntervals.concat( + schedule[thugName].map(toTimestampInterval) + ); }, []); } @@ -57,7 +56,7 @@ function getWorkingDays(workingHours) { function invertBusyIntervals(busyIntervals, weekStart, deadline) { var sortedBusyIntervals = busyIntervals.slice().sort(function (one, another) { - return Math.sign(one.from - another.from); + return one.from - another.from; }); var spareIntervals = []; var current = weekStart; @@ -68,7 +67,7 @@ function invertBusyIntervals(busyIntervals, weekStart, deadline) { to: interval.from }); } - current = current < interval.to ? interval.to : current; + current = Math.max(interval.to, current); }); if (current < deadline) { spareIntervals.push({ @@ -84,12 +83,12 @@ function getRobberyIntervals(spareIntervals, workingDays, durationInMilliseconds var robberyIntervals = []; spareIntervals.forEach(function (interval) { workingDays.forEach(function (day) { - var minTo = Math.min(day.to, interval.to); - var maxFrom = Math.max(day.from, interval.from); - if (minTo - maxFrom >= durationInMilliseconds) { + var attemptTo = Math.min(day.to, interval.to); + var attemptFrom = Math.max(day.from, interval.from); + if (attemptTo - attemptFrom >= durationInMilliseconds) { robberyIntervals.push({ - from: maxFrom, - to: minTo + from: attemptFrom, + to: attemptTo }); } }); @@ -98,8 +97,8 @@ function getRobberyIntervals(spareIntervals, workingDays, durationInMilliseconds return robberyIntervals; } -function padNumberLeft(number, length) { - return number.toLocaleString(undefined, { 'minimumIntegerDigits': length }); +function twoDigitsFormat(number) { + return number.toLocaleString(undefined, { 'minimumIntegerDigits': 2 }); } /** @@ -150,8 +149,8 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { var hourInMilliseconds = 60 * 60 * 1000; var date = new Date(robberyIntervals[0].from + bankTimezone * hourInMilliseconds); - var minutes = padNumberLeft(date.getUTCMinutes(), 2); - var hours = padNumberLeft(date.getUTCHours(), 2); + var minutes = twoDigitsFormat(date.getUTCMinutes()); + var hours = twoDigitsFormat(date.getUTCHours()); var day = DAYS[date.getUTCDate() - 1]; return template @@ -166,16 +165,24 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { * @returns {Boolean} */ tryLater: function () { - if (this.exists()) { - var halfHourInMilliseconds = 30 * 60 * 1000; - var delayedRobberyStart = robberyIntervals[0].from + halfHourInMilliseconds; - if (robberyIntervals[0].to - delayedRobberyStart >= durationInMilliseconds) { - robberyIntervals[0].from = delayedRobberyStart; + if (!this.exists()) { + return false; + } - return true; - } - if (robberyIntervals.length > 1) { - robberyIntervals.shift(); + var halfHourInMilliseconds = 30 * 60 * 1000; + var delayedRobberyStart = robberyIntervals[0].from + halfHourInMilliseconds; + if (robberyIntervals[0].to - delayedRobberyStart >= durationInMilliseconds) { + robberyIntervals[0].from = delayedRobberyStart; + + return true; + } + for (var i = 1; i < robberyIntervals.length; i++) { + if (robberyIntervals[i].to - delayedRobberyStart >= durationInMilliseconds) { + robberyIntervals[i].from = Math.max( + delayedRobberyStart, + robberyIntervals[i].from + ); + robberyIntervals = robberyIntervals.slice(i); return true; } From 2cb3a422f9059f3020df64eba31b60fc1cd1f087 Mon Sep 17 00:00:00 2001 From: irrygan Date: Mon, 24 Oct 2016 21:58:49 +0500 Subject: [PATCH 8/9] refactoring 4 life --- robbery.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/robbery.js b/robbery.js index f244d38..4ad95ba 100644 --- a/robbery.js +++ b/robbery.js @@ -171,21 +171,19 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { var halfHourInMilliseconds = 30 * 60 * 1000; var delayedRobberyStart = robberyIntervals[0].from + halfHourInMilliseconds; - if (robberyIntervals[0].to - delayedRobberyStart >= durationInMilliseconds) { - robberyIntervals[0].from = delayedRobberyStart; - - return true; - } - for (var i = 1; i < robberyIntervals.length; i++) { - if (robberyIntervals[i].to - delayedRobberyStart >= durationInMilliseconds) { - robberyIntervals[i].from = Math.max( - delayedRobberyStart, - robberyIntervals[i].from - ); + for (var i = 0; i < robberyIntervals.length; i++) { + if (robberyIntervals[i].to - delayedRobberyStart < durationInMilliseconds) { + continue; + } + robberyIntervals[i].from = Math.max( + delayedRobberyStart, + robberyIntervals[i].from + ); + if (i > 0) { robberyIntervals = robberyIntervals.slice(i); - - return true; } + + return true; } return false; From 0c4bc7153d023a80cf87d16e37a32877e3843522 Mon Sep 17 00:00:00 2001 From: irrygan Date: Tue, 25 Oct 2016 21:20:07 +0500 Subject: [PATCH 9/9] no one will even read this --- robbery.js | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/robbery.js b/robbery.js index 4ad95ba..bd5f33b 100644 --- a/robbery.js +++ b/robbery.js @@ -124,6 +124,7 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { workingDays, durationInMilliseconds ); + var currentRobberyIndex = 0; return { @@ -148,7 +149,10 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { } var hourInMilliseconds = 60 * 60 * 1000; - var date = new Date(robberyIntervals[0].from + bankTimezone * hourInMilliseconds); + var date = new Date( + robberyIntervals[currentRobberyIndex].from + + bankTimezone * hourInMilliseconds + ); var minutes = twoDigitsFormat(date.getUTCMinutes()); var hours = twoDigitsFormat(date.getUTCHours()); var day = DAYS[date.getUTCDate() - 1]; @@ -170,18 +174,20 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) { } var halfHourInMilliseconds = 30 * 60 * 1000; - var delayedRobberyStart = robberyIntervals[0].from + halfHourInMilliseconds; - for (var i = 0; i < robberyIntervals.length; i++) { - if (robberyIntervals[i].to - delayedRobberyStart < durationInMilliseconds) { - continue; - } - robberyIntervals[i].from = Math.max( - delayedRobberyStart, - robberyIntervals[i].from - ); - if (i > 0) { - robberyIntervals = robberyIntervals.slice(i); + var i = currentRobberyIndex; + var delayedRobberyStart = robberyIntervals[i].from + halfHourInMilliseconds; + while (i < robberyIntervals.length && robberyIntervals[i].from < delayedRobberyStart) { + if (robberyIntervals[i].to - delayedRobberyStart >= durationInMilliseconds) { + robberyIntervals[i].from = delayedRobberyStart; + currentRobberyIndex = i; + + return true; } + i++; + } + + if (i < robberyIntervals.length) { + currentRobberyIndex = i; return true; }