From 0e1d75e7a159182398421d2ade684e269a0ba117 Mon Sep 17 00:00:00 2001 From: Volkov Denis Date: Tue, 30 Oct 2018 13:56:03 +0500 Subject: [PATCH 1/4] =?UTF-8?q?=D1=83=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- robbery.js | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 2 deletions(-) diff --git a/robbery.js b/robbery.js index ed84b5d..217d7b7 100755 --- a/robbery.js +++ b/robbery.js @@ -16,6 +16,30 @@ const isStar = true; */ function getAppropriateMoment(schedule, duration, workingHours) { console.info(schedule, duration, workingHours); + let bankTime = parseInt(workingHours.from.slice(6)); + const workingDays = getWorkingDates(workingHours, bankTime); + // console.info('working:'); + // console.info(workingDays); + const dannyPossibleTimes = invertPeriods(schedule.Danny.map(x => createPeriod(x, bankTime)), bankTime); + // console.info('danny:'); + // console.info(dannyPossibleTimes); + const linusPossibleTimes = invertPeriods(schedule.Linus.map(x => createPeriod(x, bankTime)), bankTime); + // console.info('linus:'); + // console.info(linusPossibleTimes); + const rustyPossibleTimes = invertPeriods(schedule.Rusty.map(x => createPeriod(x, bankTime)), bankTime); + // console.info('rusty:'); + // console.info(rustyPossibleTimes); + // throw new Error(); + var possibleTimes = getTimeIntersections(dannyPossibleTimes, linusPossibleTimes); + + possibleTimes = getTimeIntersections(possibleTimes, rustyPossibleTimes); + possibleTimes = getTimeIntersections(possibleTimes, workingDays); + // console.info('kek'); + // console.info(possibleTimes); + var appropriateTimes = possibleTimes + .filter(t => t.to - t.from >= duration); + // console.info('kek'); + // console.info(appropriateTimes); return { @@ -24,7 +48,7 @@ function getAppropriateMoment(schedule, duration, workingHours) { * @returns {Boolean} */ exists: function () { - return false; + return appropriateTimes.length > 0; }, /** @@ -34,7 +58,12 @@ function getAppropriateMoment(schedule, duration, workingHours) { * @returns {String} */ format: function (template) { - return template; + if (appropriateTimes.length === 0) { + return ''; + } + const start = createCustomDateObject(appropriateTimes[0].from); + + return formatDate(start, template); }, /** @@ -43,11 +72,133 @@ function getAppropriateMoment(schedule, duration, workingHours) { * @returns {Boolean} */ tryLater: function () { + if (appropriateTimes.length === 0) { + return false; + } + var currentPeriod = appropriateTimes[0]; + if (currentPeriod.to - currentPeriod.from >= duration + 30) { + appropriateTimes[0].from += 30; + + return true; + } + + if (appropriateTimes.length > 1) { + appropriateTimes.shift(); + + return true; + } + return false; } }; } +function formatDate(customDate, template) { + const addLeadingZero = number => number.toString().length === 1 ? `0${number}` : number; + + return template + .replace('%HH', addLeadingZero(customDate.hours)) + .replace('%MM', addLeadingZero(customDate.minutes)) + .replace('%DD', addLeadingZero(customDate.day)); +} + +function createCustomDateObject(minutes) { + const dayNames = ['ПН', 'ВТ', 'СР']; + + return { + day: dayNames[Math.floor(minutes / (60 * 24))], + hours: Math.floor(minutes / 60) % 24, + minutes: minutes % 60 + }; +} + +function invertPeriods(periods, bankTimeZone) { + periods.sort((a, b)=>a.from - b.to); + const rightBorder = getMinutes(`СР 23:59+${bankTimeZone}`, bankTimeZone); + let leftBorder = getMinutes(`ПН 00:00+${bankTimeZone}`, bankTimeZone); + const newPeriods = []; + periods.forEach(period => { + newPeriods.push({ from: leftBorder, to: period.from }); + leftBorder = period.to; + }); + newPeriods.push({ from: leftBorder, to: rightBorder }); + + return newPeriods; +} + +function getPeriodsIntersection(firstPeriod, secondPeriod) { + if (isPeriodsNested(firstPeriod, secondPeriod)) { + return { + from: Math.max(firstPeriod.from, secondPeriod.from), + to: Math.min(firstPeriod.to, secondPeriod.to) + }; + } + + if (isPeriodsIntersect(firstPeriod, secondPeriod)) { + return { + from: Math.max(firstPeriod.from, secondPeriod.from), + to: Math.min(firstPeriod.to, secondPeriod.to) + }; + } +} + +function isPeriodsNested(period1, period2) { + return period1.from < period2.from && period1.to > period2.to || + period2.from < period1.from && period2.to > period1.to; +} + +function isPeriodsIntersect(period1, period2) { + return period1.to >= period2.from && period2.to >= period1.from; +} + +function getTimeIntersections(firstSchedule, secondSchedule) { + var commonTimes = []; + firstSchedule.forEach(first => { + secondSchedule.forEach(second => { + commonTimes.push(getPeriodsIntersection(first, second)); + }); + }); + + return commonTimes.filter(date => date !== undefined); +} + +function getWorkingDates(bankWorkingHours, bankTimeZone) { + return [ + { + from: getMinutes(`ПН ${bankWorkingHours.from}`, bankTimeZone), + to: getMinutes(`ПН ${bankWorkingHours.to}`, bankTimeZone) + }, + { + from: getMinutes(`ВТ ${bankWorkingHours.from}`, bankTimeZone), + to: getMinutes(`ВТ ${bankWorkingHours.to}`, bankTimeZone) + }, + { + from: getMinutes(`СР ${bankWorkingHours.from}`, bankTimeZone), + to: getMinutes(`СР ${bankWorkingHours.to}`, bankTimeZone) + } + ]; +} + +function createPeriod(stringPeriod, bankTimeZone) { + return { + from: getMinutes(stringPeriod.from, bankTimeZone), + to: getMinutes(stringPeriod.to, bankTimeZone) + }; +} + +const dayNameToHours = new Map( + [['ПН', 24 * 0], + ['ВТ', 24 * 1], + ['СР', 24 * 2]] +); + +function getMinutes(dateString, bankTimeZone) { + let day = dateString.slice(0, 2); + let hours = parseInt(dateString.slice(3, 5)) - parseInt(dateString.slice(9)) + bankTimeZone; + let minutes = parseInt(dateString.slice(6, 8)); + return (dayNameToHours.get(day) + hours) * 60 + minutes; +} + module.exports = { getAppropriateMoment, From c6f3c41a66a0e249e2eaec8fc03c8f049e2d0447 Mon Sep 17 00:00:00 2001 From: Volkov Denis Date: Tue, 30 Oct 2018 13:59:13 +0500 Subject: [PATCH 2/4] fix lint --- robbery.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/robbery.js b/robbery.js index 217d7b7..da94214 100755 --- a/robbery.js +++ b/robbery.js @@ -20,13 +20,16 @@ function getAppropriateMoment(schedule, duration, workingHours) { const workingDays = getWorkingDates(workingHours, bankTime); // console.info('working:'); // console.info(workingDays); - const dannyPossibleTimes = invertPeriods(schedule.Danny.map(x => createPeriod(x, bankTime)), bankTime); + const dannyPossibleTimes = invertPeriods(schedule.Danny + .map(x => createPeriod(x, bankTime)), bankTime); // console.info('danny:'); // console.info(dannyPossibleTimes); - const linusPossibleTimes = invertPeriods(schedule.Linus.map(x => createPeriod(x, bankTime)), bankTime); + const linusPossibleTimes = invertPeriods(schedule.Linus + .map(x => createPeriod(x, bankTime)), bankTime); // console.info('linus:'); // console.info(linusPossibleTimes); - const rustyPossibleTimes = invertPeriods(schedule.Rusty.map(x => createPeriod(x, bankTime)), bankTime); + const rustyPossibleTimes = invertPeriods(schedule.Rusty + .map(x => createPeriod(x, bankTime)), bankTime); // console.info('rusty:'); // console.info(rustyPossibleTimes); // throw new Error(); @@ -84,7 +87,7 @@ function getAppropriateMoment(schedule, duration, workingHours) { if (appropriateTimes.length > 1) { appropriateTimes.shift(); - + return true; } @@ -196,6 +199,7 @@ function getMinutes(dateString, bankTimeZone) { let day = dateString.slice(0, 2); let hours = parseInt(dateString.slice(3, 5)) - parseInt(dateString.slice(9)) + bankTimeZone; let minutes = parseInt(dateString.slice(6, 8)); + return (dayNameToHours.get(day) + hours) * 60 + minutes; } From 706adfba44a98eac37b677659c3659f646f6daa0 Mon Sep 17 00:00:00 2001 From: Volkov Denis Date: Tue, 30 Oct 2018 14:22:31 +0500 Subject: [PATCH 3/4] a little refactor --- robbery.js | 111 ++++++++++++++++++++++++++--------------------------- 1 file changed, 54 insertions(+), 57 deletions(-) diff --git a/robbery.js b/robbery.js index da94214..e4e649b 100755 --- a/robbery.js +++ b/robbery.js @@ -16,33 +16,16 @@ const isStar = true; */ function getAppropriateMoment(schedule, duration, workingHours) { console.info(schedule, duration, workingHours); - let bankTime = parseInt(workingHours.from.slice(6)); - const workingDays = getWorkingDates(workingHours, bankTime); - // console.info('working:'); - // console.info(workingDays); - const dannyPossibleTimes = invertPeriods(schedule.Danny - .map(x => createPeriod(x, bankTime)), bankTime); - // console.info('danny:'); - // console.info(dannyPossibleTimes); - const linusPossibleTimes = invertPeriods(schedule.Linus - .map(x => createPeriod(x, bankTime)), bankTime); - // console.info('linus:'); - // console.info(linusPossibleTimes); - const rustyPossibleTimes = invertPeriods(schedule.Rusty - .map(x => createPeriod(x, bankTime)), bankTime); - // console.info('rusty:'); - // console.info(rustyPossibleTimes); - // throw new Error(); - var possibleTimes = getTimeIntersections(dannyPossibleTimes, linusPossibleTimes); + let offset = parseInt(workingHours.from.slice(6)); + const bankTimes = getWorkingTimes(workingHours, offset); + const gangBusyTimes = { + Danny: schedule.Danny.map(x => createPeriod(x, offset)), + Linus: schedule.Linus.map(x => createPeriod(x, offset)), + Rusty: schedule.Rusty.map(x => createPeriod(x, offset)) + }; - possibleTimes = getTimeIntersections(possibleTimes, rustyPossibleTimes); - possibleTimes = getTimeIntersections(possibleTimes, workingDays); - // console.info('kek'); - // console.info(possibleTimes); - var appropriateTimes = possibleTimes + var robberyTimes = getRobberyTimes(gangBusyTimes, bankTimes, offset) .filter(t => t.to - t.from >= duration); - // console.info('kek'); - // console.info(appropriateTimes); return { @@ -51,7 +34,7 @@ function getAppropriateMoment(schedule, duration, workingHours) { * @returns {Boolean} */ exists: function () { - return appropriateTimes.length > 0; + return robberyTimes.length > 0; }, /** @@ -61,10 +44,10 @@ function getAppropriateMoment(schedule, duration, workingHours) { * @returns {String} */ format: function (template) { - if (appropriateTimes.length === 0) { + if (robberyTimes.length === 0) { return ''; } - const start = createCustomDateObject(appropriateTimes[0].from); + const start = createCustomDateObject(robberyTimes[0].from); return formatDate(start, template); }, @@ -75,18 +58,18 @@ function getAppropriateMoment(schedule, duration, workingHours) { * @returns {Boolean} */ tryLater: function () { - if (appropriateTimes.length === 0) { + if (robberyTimes.length === 0) { return false; } - var currentPeriod = appropriateTimes[0]; + var currentPeriod = robberyTimes[0]; if (currentPeriod.to - currentPeriod.from >= duration + 30) { - appropriateTimes[0].from += 30; + robberyTimes[0].from += 30; return true; } - if (appropriateTimes.length > 1) { - appropriateTimes.shift(); + if (robberyTimes.length > 1) { + robberyTimes.shift(); return true; } @@ -96,6 +79,29 @@ function getAppropriateMoment(schedule, duration, workingHours) { }; } +function getRobberyTimes(gangBusyTimes, workingTimes, offset) { + const dannyPossibleTimes = invertPeriods(gangBusyTimes.Danny, offset); + const linusPossibleTimes = invertPeriods(gangBusyTimes.Linus, offset); + const rustyPossibleTimes = invertPeriods(gangBusyTimes.Rusty, offset); + + var possibleTimes = getTimeIntersections(dannyPossibleTimes, linusPossibleTimes); + possibleTimes = getTimeIntersections(possibleTimes, rustyPossibleTimes); + possibleTimes = getTimeIntersections(possibleTimes, workingTimes); + + return possibleTimes; +} + +function getTimeIntersections(firstSchedule, secondSchedule) { + var commonTimes = []; + firstSchedule.forEach(first => { + secondSchedule.forEach(second => { + commonTimes.push(getPeriodsIntersection(first, second)); + }); + }); + + return commonTimes.filter(date => date !== undefined); +} + function formatDate(customDate, template) { const addLeadingZero = number => number.toString().length === 1 ? `0${number}` : number; @@ -154,30 +160,19 @@ function isPeriodsIntersect(period1, period2) { return period1.to >= period2.from && period2.to >= period1.from; } -function getTimeIntersections(firstSchedule, secondSchedule) { - var commonTimes = []; - firstSchedule.forEach(first => { - secondSchedule.forEach(second => { - commonTimes.push(getPeriodsIntersection(first, second)); - }); - }); - - return commonTimes.filter(date => date !== undefined); -} - -function getWorkingDates(bankWorkingHours, bankTimeZone) { +function getWorkingTimes(bankWorkingHours, offset) { return [ { - from: getMinutes(`ПН ${bankWorkingHours.from}`, bankTimeZone), - to: getMinutes(`ПН ${bankWorkingHours.to}`, bankTimeZone) + from: getMinutes(`ПН ${bankWorkingHours.from}`, offset), + to: getMinutes(`ПН ${bankWorkingHours.to}`, offset) }, { - from: getMinutes(`ВТ ${bankWorkingHours.from}`, bankTimeZone), - to: getMinutes(`ВТ ${bankWorkingHours.to}`, bankTimeZone) + from: getMinutes(`ВТ ${bankWorkingHours.from}`, offset), + to: getMinutes(`ВТ ${bankWorkingHours.to}`, offset) }, { - from: getMinutes(`СР ${bankWorkingHours.from}`, bankTimeZone), - to: getMinutes(`СР ${bankWorkingHours.to}`, bankTimeZone) + from: getMinutes(`СР ${bankWorkingHours.from}`, offset), + to: getMinutes(`СР ${bankWorkingHours.to}`, offset) } ]; } @@ -189,18 +184,20 @@ function createPeriod(stringPeriod, bankTimeZone) { }; } -const dayNameToHours = new Map( - [['ПН', 24 * 0], +const hoursByDayName = new Map( + [ + ['ПН', 24 * 0], ['ВТ', 24 * 1], - ['СР', 24 * 2]] + ['СР', 24 * 2] + ] ); -function getMinutes(dateString, bankTimeZone) { +function getMinutes(dateString, offset) { let day = dateString.slice(0, 2); - let hours = parseInt(dateString.slice(3, 5)) - parseInt(dateString.slice(9)) + bankTimeZone; + let hours = parseInt(dateString.slice(3, 5)) - parseInt(dateString.slice(9)) + offset; let minutes = parseInt(dateString.slice(6, 8)); - return (dayNameToHours.get(day) + hours) * 60 + minutes; + return (hoursByDayName.get(day) + hours) * 60 + minutes; } module.exports = { From 1babcd3afc071268757c48e4d254facc9821c9c7 Mon Sep 17 00:00:00 2001 From: Volkov Denis Date: Tue, 30 Oct 2018 14:43:01 +0500 Subject: [PATCH 4/4] some more refactor --- robbery.js | 63 ++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/robbery.js b/robbery.js index e4e649b..5720510 100755 --- a/robbery.js +++ b/robbery.js @@ -16,8 +16,8 @@ const isStar = true; */ function getAppropriateMoment(schedule, duration, workingHours) { console.info(schedule, duration, workingHours); - let offset = parseInt(workingHours.from.slice(6)); - const bankTimes = getWorkingTimes(workingHours, offset); + var offset = parseInt(workingHours.from.slice(6)); + const bankTimes = getBankWorkingTimes(workingHours, offset); const gangBusyTimes = { Danny: schedule.Danny.map(x => createPeriod(x, offset)), Linus: schedule.Linus.map(x => createPeriod(x, offset)), @@ -47,9 +47,8 @@ function getAppropriateMoment(schedule, duration, workingHours) { if (robberyTimes.length === 0) { return ''; } - const start = createCustomDateObject(robberyTimes[0].from); - return formatDate(start, template); + return formatDate(createCustomDateObject(robberyTimes[0].from), template); }, /** @@ -79,22 +78,22 @@ function getAppropriateMoment(schedule, duration, workingHours) { }; } -function getRobberyTimes(gangBusyTimes, workingTimes, offset) { +function getRobberyTimes(gangBusyTimes, bankTimes, offset) { const dannyPossibleTimes = invertPeriods(gangBusyTimes.Danny, offset); const linusPossibleTimes = invertPeriods(gangBusyTimes.Linus, offset); const rustyPossibleTimes = invertPeriods(gangBusyTimes.Rusty, offset); - var possibleTimes = getTimeIntersections(dannyPossibleTimes, linusPossibleTimes); + let possibleTimes = getTimeIntersections(dannyPossibleTimes, linusPossibleTimes); possibleTimes = getTimeIntersections(possibleTimes, rustyPossibleTimes); - possibleTimes = getTimeIntersections(possibleTimes, workingTimes); + possibleTimes = getTimeIntersections(possibleTimes, bankTimes); return possibleTimes; } -function getTimeIntersections(firstSchedule, secondSchedule) { +function getTimeIntersections(firstTime, secondTime) { var commonTimes = []; - firstSchedule.forEach(first => { - secondSchedule.forEach(second => { + firstTime.forEach(first => { + secondTime.forEach(second => { commonTimes.push(getPeriodsIntersection(first, second)); }); }); @@ -103,7 +102,7 @@ function getTimeIntersections(firstSchedule, secondSchedule) { } function formatDate(customDate, template) { - const addLeadingZero = number => number.toString().length === 1 ? `0${number}` : number; + const addLeadingZero = (number) => number.toString().length === 1 ? `0${number}` : number; return template .replace('%HH', addLeadingZero(customDate.hours)) @@ -121,11 +120,13 @@ function createCustomDateObject(minutes) { }; } -function invertPeriods(periods, bankTimeZone) { - periods.sort((a, b)=>a.from - b.to); - const rightBorder = getMinutes(`СР 23:59+${bankTimeZone}`, bankTimeZone); - let leftBorder = getMinutes(`ПН 00:00+${bankTimeZone}`, bankTimeZone); - const newPeriods = []; +function invertPeriods(periods, offset) { + periods.sort((a, b) => a.from - b.to); + + const rightBorder = getMinutes(`СР 23:59+${offset}`, offset); + let leftBorder = getMinutes(`ПН 00:00+${offset}`, offset); + + let newPeriods = []; periods.forEach(period => { newPeriods.push({ from: leftBorder, to: period.from }); leftBorder = period.to; @@ -135,32 +136,28 @@ function invertPeriods(periods, bankTimeZone) { return newPeriods; } -function getPeriodsIntersection(firstPeriod, secondPeriod) { - if (isPeriodsNested(firstPeriod, secondPeriod)) { +function getPeriodsIntersection(first, second) { + const isPeriodsNested = (a, b) => + a.from < b.from && a.to > b.to || b.from < a.from && b.to > a.to; + + const isPeriodsIntersect = (a, b) => a.to >= b.from && b.to >= a.from; + + if (isPeriodsNested(first, second)) { return { - from: Math.max(firstPeriod.from, secondPeriod.from), - to: Math.min(firstPeriod.to, secondPeriod.to) + from: Math.max(first.from, second.from), + to: Math.min(first.to, second.to) }; } - if (isPeriodsIntersect(firstPeriod, secondPeriod)) { + if (isPeriodsIntersect(first, second)) { return { - from: Math.max(firstPeriod.from, secondPeriod.from), - to: Math.min(firstPeriod.to, secondPeriod.to) + from: Math.max(first.from, second.from), + to: Math.min(first.to, second.to) }; } } -function isPeriodsNested(period1, period2) { - return period1.from < period2.from && period1.to > period2.to || - period2.from < period1.from && period2.to > period1.to; -} - -function isPeriodsIntersect(period1, period2) { - return period1.to >= period2.from && period2.to >= period1.from; -} - -function getWorkingTimes(bankWorkingHours, offset) { +function getBankWorkingTimes(bankWorkingHours, offset) { return [ { from: getMinutes(`ПН ${bankWorkingHours.from}`, offset),