Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Филиппович Алексей #53

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
bb0bbc3
Первый вариант решения
feniwe Oct 26, 2016
e24fda2
Исправлены ошибки линтинга
feniwe Oct 26, 2016
48e35ff
Исправлено имя переменной в аргументе функции
feniwe Oct 26, 2016
f3c5246
robbery.js update
feniwe Oct 26, 2016
88b4a8e
robbey.js update
feniwe Oct 26, 2016
2610482
robbery.js update
feniwe Oct 29, 2016
91f4e53
Исправлены ошибки линтинга
feniwe Oct 29, 2016
90caf24
robbery.js update
feniwe Oct 29, 2016
2a524fb
Исправлена ошибка линтинга
feniwe Oct 29, 2016
1f781f8
Исправлены ошибки dateToMinutes()
feniwe Oct 29, 2016
b30bb59
robbery.js update
feniwe Oct 29, 2016
a5aa85f
robbery.js update
feniwe Oct 29, 2016
a712e5a
Исправлены ошибки линтинга
feniwe Oct 29, 2016
70b0eb0
Выполнены рекомендации
feniwe Oct 31, 2016
eb6e46c
Исправлены ошибки
feniwe Oct 31, 2016
083ea98
one more try
feniwe Oct 31, 2016
2710c6d
Гибрид старой и новой версий
feniwe Oct 31, 2016
efc10b6
Гибрид старой и новой версий #2
feniwe Oct 31, 2016
cab1115
Гибрид старой и новой версий #3
feniwe Oct 31, 2016
6027818
Гибрид старой и новой версий #3 fix
feniwe Oct 31, 2016
319f5f0
Гибрид старой и новой версий #4
feniwe Oct 31, 2016
747d366
Гибрид старой и новой версий #5
feniwe Oct 31, 2016
08fea25
Гибрид старой и новой версий #4
feniwe Oct 31, 2016
ce5f4d8
Выполнены рекомендации v1.01
feniwe Oct 31, 2016
7fc820d
Исправлены ошибки
feniwe Oct 31, 2016
1842c0c
Выполнены рекомендации v1.02
feniwe Oct 31, 2016
e724d84
Исправлены ошибки
feniwe Oct 31, 2016
25fbcb3
one more try
feniwe Nov 1, 2016
2211bac
one more try
feniwe Nov 1, 2016
87bbb9c
one more try
feniwe Nov 1, 2016
8ad5d08
one more try
feniwe Nov 1, 2016
aee6ad9
Мелкие правки
feniwe Nov 7, 2016
9cc39ae
Исправлены ошибки
feniwe Nov 7, 2016
17b3272
Мелкие правки
feniwe Nov 7, 2016
1def2f3
Мелкие правки
feniwe Nov 7, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
260 changes: 257 additions & 3 deletions robbery.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@
* Сделано задание на звездочку
* Реализовано оба метода и tryLater
*/
exports.isStar = true;
exports.isStar = false;

var BANK_TIMEZONE = 0; // временная зона банка
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

переменные нао определять максимально близко к тому месту, где они потом используются

var ROBBERY_DURATION = 0;
var MINUTES_IN_HOUR = 60;
var MINUTES_IN_DAY = 24 * MINUTES_IN_HOUR;
var DAYS_FOR_ROBBERY = 3;
var MAX_MINUTES = DAYS_FOR_ROBBERY * MINUTES_IN_DAY - 1; // макс. 3 дня на ограбление и -1 минута
var DATE_PATTERN = /(([БВНПРСТЧ]{2})\s)?(\d{2}):(\d{2})([+-]\d{1,2})/i;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

сам составил?

var WEEKDAYS = ['ПН', 'ВТ', 'СР', 'ЧТ', 'ПТ', 'СБ', 'ВС'];

/**
* @param {Object} schedule – Расписание Банды
Expand All @@ -15,16 +24,24 @@ exports.isStar = true;
* @returns {Object}
*/
exports.getAppropriateMoment = function (schedule, duration, workingHours) {
BANK_TIMEZONE = getBaseTimeZone(workingHours);
console.info(schedule, duration, workingHours);
ROBBERY_DURATION = duration;
var robberyEvent = getRobberyEvent(schedule, workingHours);

return {

ready: robberyEvent.ready,
day: robberyEvent.day,
hours: robberyEvent.hours,
minutes: robberyEvent.minutes,

/**
* Найдено ли время
* @returns {Boolean}
*/
exists: function () {
return false;
return this.ready;
},

/**
Expand All @@ -35,7 +52,14 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) {
* @returns {String}
*/
format: function (template) {
return template;
if (!this.ready) {
return '';
}

return template
.replace('%DD', this.day)
.replace('%HH', this.hours)
.replace('%MM', this.minutes);
},

/**
Expand All @@ -48,3 +72,233 @@ exports.getAppropriateMoment = function (schedule, duration, workingHours) {
}
};
};

function getBaseTimeZone(workingHours) {
return parseInt(DATE_PATTERN.exec(workingHours.from)[5], 10);
}

function getRobberyEvent(schedule, workingHours) {
// Диапазоны времени когда грабители могут пойти на ограбление
var robberyIntervals = {};
// Высчитываем диапазоны, когда грабители могут пойти на ограбление
parseGangIntervals(robberyIntervals, schedule);
// Составляем диапазоны времени работы банка
var bankSchedule = getBankSchedule(workingHours);
// Делаем пересечение всех диапазонов свободного времени грабителей
// и времени работы банка
robberyIntervals.Gang = getRobberyIntervals(robberyIntervals, bankSchedule);
// Из готовых диапазонов получаем время, когда можно ограбить банк
// с учётом продолжительности ограбления (если вообще можно)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

за комментарии от души спасибо 👍

var robberyTime = getRobberyTime(robberyIntervals);
var robberyEvent = findRobberyEvent(robberyTime);

return robberyEvent;
}

function parseGangIntervals(robberyIntervals, schedule) {
for (var robber in schedule) {
if (schedule.hasOwnProperty(robber)) {
robberyIntervals[robber] = getFreeIntervals(schedule[robber]);
}
}
}

// Высчитываем диапазоны, когда грабитель может совершить ограбление
// без учёта времени работы банка
function getFreeIntervals(schedule) {
var freeIntervals = [];
if (schedule.length === 0) {
freeIntervals.push(getInterval(0, MAX_MINUTES));

return freeIntervals;
}
var busyIntervals = getBusyIntervals(schedule);
var from = 0;
for (var i = 0; i < busyIntervals.length; i++) {
// Если грабитель занят с в ПН 00:00, то интервала с ПН 00:00 до ПН 00:00 нет
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

вообще непонятный комментарий. Он совсем запутывает. И на самом деле вот это сомнительное место
getFreeIntervals и getBusyIntervals. Подумай как оптимизировать это?

if (i === 0 && busyIntervals[i].from === 0) {
continue;
}
from = (i === 0) ? 0 : busyIntervals[i - 1].to;
freeIntervals.push(getInterval(from, busyIntervals[i].from));
}
// Если последний интервал, когда рабитель занят, не приходится на СР 23:59
// то добавляем интервал с конца рабочего времени грабителя по СР 23:59
if (busyIntervals[busyIntervals.length - 1].to !== MAX_MINUTES) {
from = busyIntervals[busyIntervals.length - 1].to;
freeIntervals.push(getInterval(from, MAX_MINUTES));
}

return freeIntervals;
}

function getBusyIntervals(schedule) {
var intervals = schedule.reduce(function (accumulator, scheduleItem) {
var interval = getInterval(dateToMinutes(scheduleItem.from),
dateToMinutes(scheduleItem.to));
for (var i = 0; i < accumulator.length; i++) {
var mergedInterval = getMergedInterval(accumulator[i], interval);
if (accumulator[i] !== mergedInterval) {
accumulator[i] = mergedInterval;

return accumulator;
}
}
accumulator.push(interval);

return accumulator;
}, []).sort(intervalsComparator);

return intervals;
}

function getMergedInterval(first, second) {
var from = 0;
var to = 0;
// Если первый содержится во втором или совпадает с ним, или
// Если второй содержится в первом или совпадает с ним
if (first.from >= second.from && first.to <= second.to ||
first.from <= second.from && first.to >= second.to) {
from = Math.min(first.from, second.from);
to = Math.max(first.to, second.to);

return getInterval(from, to);
}
// Если второй пересекает первого слева
if (first.from >= second.from && first.from <= second.to) {
from = second.from;
to = first.to;

return getInterval(from, to);
}
// Если второй пересекает первого справа
if (first.to <= second.to && first.to >= second.from) {
from = first.from;
to = second.to;

return getInterval(from, to);
}

return first;
}

function getBankSchedule(workingHours) {
var schedule = [];
for (var day = 0; day < 3; day++) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 в константу

var from = dateToMinutes(WEEKDAYS[day] + ' ' + workingHours.from);
var to = dateToMinutes(WEEKDAYS[day] + ' ' + workingHours.to);
schedule.push(getInterval(from, to));
}

return schedule;
}

// Строит пересечение всех диапазонов времени всех троих грабителей, когда они
// могут совершить ограбление и времени работы банка
function getRobberyIntervals(robberyIntervals, bankSchedule) {
var intervals = bankSchedule;
for (var robber in robberyIntervals) {
if (robberyIntervals.hasOwnProperty(robber)) {
intervals = getCrossedIntervals(intervals, robberyIntervals[robber]);
}
}

return intervals;
}

// Находит все общие диапазоны, когда грабители могут совершить ограбление
function getCrossedIntervals(firstIntervals, secondIntervals) {
var crossedIntervals = [];
for (var i = 0; i < firstIntervals.length; i++) {
for (var j = 0; j < secondIntervals.length; j++) {
crossTwoIntervals(firstIntervals[i], secondIntervals[j], crossedIntervals);
}
}

return crossedIntervals;
}

// Находим пересечение двух диапазонов времени
function crossTwoIntervals(first, second, crossedIntervals) {
if (first.from > second.to || first.to < second.from) {
return;
}
var maxFrom = Math.max(first.from, second.from);
var minTo = Math.min(first.to, second.to);
crossedIntervals.push(getInterval(maxFrom, minTo));
}

function getInterval(argFrom, argTo) {
return {
from: argFrom,
to: argTo
};
}

function intervalsComparator(first, second) {
if (first.from > second.from ||
first.from === second.from && first.to > second.to) {
return 1;
}
if (first.from < second.from ||
first.from === second.from && first.to < second.to) {
return -1;
}

return 0;
}

// Считаем количество минут, прошедших с ПН 00:00+5
// Например, СР 15:00+3 -> 3900 (2880 прошло с ПН по СР 00:00 и 17 часов = 1020)
function dateToMinutes(date) {
var timeZoneOffset = BANK_TIMEZONE - Number(DATE_PATTERN.exec(date)[5]);
var day = DATE_PATTERN.exec(date)[2];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

вынеси DATE_PATTERN.exec(date) в переменную, незачем делать это каждый раз

var hours = Number(DATE_PATTERN.exec(date)[3]) + timeZoneOffset;
var minutes = Number(DATE_PATTERN.exec(date)[4]);
var result = dayToMinutes(day) + hours * MINUTES_IN_HOUR + minutes;

return Math.min(result, MAX_MINUTES);
}

function dayToMinutes(day) {
if (WEEKDAYS.indexOf(day) !== -1) {
return WEEKDAYS.indexOf(day) * MINUTES_IN_DAY;
}

return 0;
}

// Вернёт количество минут, считая с ПН 00:00 до момента, когда можно
// совершить ограбление, либо undefined
function getRobberyTime(robberyIntervals) {
var filtered = robberyIntervals.Gang.filter(filterIntervals);

return (filtered.length > 0) ? filtered[0].from : undefined;
}

function filterIntervals(interval) {
return interval.to - interval.from >= ROBBERY_DURATION;
}

// Преобразуем количество минут, считая с ПН 00:00 до момента, когда можно
// совершить ограбление
function findRobberyEvent(robberyTime) {
if (robberyTime === undefined) {
return {
ready: false
};
}
var eventDay = WEEKDAYS[Math.floor(robberyTime / MINUTES_IN_DAY)];
robberyTime -= WEEKDAYS.indexOf(eventDay) * MINUTES_IN_DAY;
var eventMinutes = robberyTime % MINUTES_IN_HOUR;
eventMinutes = (eventMinutes < 10) ? '0' + eventMinutes : eventMinutes;
var eventHours = (robberyTime - eventMinutes) / MINUTES_IN_HOUR;
eventHours = (eventHours < 10) ? '0' + eventHours : eventHours;

return {
ready: true,
day: eventDay,
hours: eventHours,
minutes: eventMinutes
};
}