Skip to content

Instantly share code, notes, and snippets.

@coopermaruyama
Created September 16, 2016 22:41
Show Gist options
  • Save coopermaruyama/a7dd49749835c120c49a64c283f3a275 to your computer and use it in GitHub Desktop.
Save coopermaruyama/a7dd49749835c120c49a64c283f3a275 to your computer and use it in GitHub Desktop.
Finding an Appointment (JS)
// The businesspeople among you will know that it's often not easy to find an
// appointment. In this kata we want to find such an appointment automatically.
// You will be given the calendars of our businessperson and a duration for the
// meeting. Your task is to find the earliest time, when every businessperson is
// free for at least that duration.
//
// Example Schedule:
//
// Person | Meetings
// -------+-----------------------------------------------------------
// A | 09:00 - 11:30, 13:30 - 16:00, 16:00 - 17:30, 17:45 - 19:00
// B | 09:15 - 12:00, 14:00 - 16:30, 17:00 - 17:30
// C | 11:30 - 12:15, 15:00 - 16:30, 17:45 - 19:00
// Rules:
//
// All times in the calendars will be given in 24h format "hh:mm", the result
// must also be in that format
//
// A meeting is represented by its start time (inclusively) and end time
// (exclusively) -> if a meeting takes place from 09:00 - 11:00, the next
// possible start time would be 11:00
//
// The businesspeople work from 09:00 (inclusively) - 19:00 (exclusively), the
// appointment must start and end within that range.
//
// If the meeting does not fit into the schedules, return null or None as result
// The duration of the meeting will be provided as an integer in minutes
// Following these rules and looking at the example above the earliest time for
// a 60 minutes meeting would be 12:15.
//
// Data Format:
//
// The schedule will be provided as 3-dimensional array, in this format:
//
// var schedules = [
// [['09:00', '11:30'], ['13:30', '16:00'], ['16:00', '17:30'], ['17:45', '19:00]],
// [['09:15', '12:00'], ['14:00', '16:30'], ['17:00', '17:30']],
// [['11:30', '12:15'], ['15:00', '16:30'], ['17:45', '19:00']]
// ];
// -----------------------------------------------------------------------------
// SOLUTION
// -----------------------------------------------------------------------------
function getStartTime(schedules, duration) {
var overlapRanges = getOverlaps(schedules);
var available = overlapRanges.find(range => rangeToMinutes(range) >= duration);
return available && available[0] || null;
}
/**
* Given a time range in format ['09:15', '10:30'],
* return the length of the range in minutes.
* @param {Array<Number>} range
* @return {Number} The minutes in the range
*/
function rangeToMinutes(range) {
var minutes = 0;
var start = range[0];
var end = range[1];
var startParts = start.split(':');
var endParts = end.split(':');
var startHour = +startParts[0];
var endHour = +endParts[0];
var startMins = +startParts[1];
var endMins = +endParts[1];
if (startHour !== endHour) {
var hrMins = (endHour - startHour) * 60;
minutes += hrMins;
}
if (startMins !== endMins) {
minutes += (endMins - startMins)
}
return minutes;
}
/**
* Given a set of schedules of busy time ranges, return
* the time range of availabilities common to all schedules.
* @param {Array<Array>} schedules
* @return {Array<Array>} Time ranges which are available.
*/
function getOverlaps(schedules) {
var res = [];
return schedules.reduce((openSlots, schedule) => {
var open = getOpenSlots(schedule);
return intersectSchedules(openSlots, open);
}, [['09:00', '19:00']]);
return res;
}
/**
* Given 2 sets of available times, return the times available in both schedules.
* @param {Array<Array>} schedule1
* @param {Array<Array>} schedule2
* @return {Array<Array>}
*/
function intersectSchedules(schedule1, schedule2) {
var res = [];
schedule1.forEach(r1 => {
schedule2.forEach(r2 => {
var intersection = findIntersection(r1, r2);
if (intersection) {
res.push(intersection);
}
});
});
return res;
}
/**
* Given 2 ranges, find the interesction.
* @param {Array} a - 1st range e.g. ['11:30', '13:30']
* @param {Array} b - 2nd range e.g. ['12:00', '14:00']
* @return {Array} Interection range, or null if none.
*/
function findIntersection(a, b) {
var min = (a[0] < b[0]) ? a : b;
var max = (min === a) ? b : a;
if (min[1] < max[0]) return null;
return [max[0], (min[1] < max[1]) ? min[1] : max[1]];
}
/**
* Given a schedule of meetings, find the oen slots.
* @param {Array<Array>} schedule - busy times, e.g. [['09:00', '11:30'], ['13:30', '16:00']];
* @return {Array<Array>} available times, e.g. [['11:30', '13:30'], ['16:00', '19:00']] in above case.
*/
function getOpenSlots(schedule) {
var res = [];
var head = schedule[0] && schedule[0][0];
var tail = schedule[schedule.length - 1] &&schedule[schedule.length - 1][1];
if (schedule.length <= 1) {
return schedule;
}
// first slot
if (head !== '09:00') {
res.push(['09:00', head]);
}
schedule.forEach((curr, i) => {
var prev = schedule[i - 1];
var isTimeBetween = prev && prev[1] !== curr[0];
if (i > 0 && isTimeBetween) {
res.push([prev[1], curr[0]]);
}
});
// last slot
if (tail !== '19:00') {
res.push([tail, '19:00']);
}
return res;
}
@davework26
Copy link

davework26 commented Apr 27, 2021

// var schedules = [
// [['09:00', '11:30'], ['13:30', '16:00'], ['16:00', '17:30'], ['17:45', '19:00]],
// [['09:15', '12:00'], ['14:00', '16:30'], ['17:00', '17:30']],
// [['11:30', '12:15'], ['15:00', '16:30'], ['17:45', '19:00']]
// ];

Missing close quote at end of 1st line of times:
'19:00]],

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment