function read(done) { require("fs").readFile('./input', 'utf8', (err, data) => { var taskPool = new TaskPool(); data.split("\n").forEach((line) => { var arr = line.match(/\s([A-Z])\s.*\s([A-Z])\s/); if (arr) { var from = taskPool.getOrCreate(arr[1]), to = taskPool.getOrCreate(arr[2]); from.neededBy.push(to); to.needs.push(from); } }); done(taskPool); }); } function Task(taskId) { this.taskId = taskId; this.done = false; this.startedAt = -1; this.duration = 61 +taskId.charCodeAt(0) -"A".charCodeAt(0); this.needs = []; this.neededBy = []; } Task.prototype.isReady = function() { var c = true; this.needs.some(i => { c &= i.done; return !c; }); return c; } function TaskPool() { this.tasks = {}, this.getOrCreate = function(taskId) { if (this.tasks[taskId]) return this.tasks[taskId]; return this.tasks[taskId] = new Task(taskId); }; } Array.prototype.containsAll = function(arr) { var all = true; arr.some(i => { if (this.indexOf(i.taskId) == -1) all = false; return !all; }); return all; } function nextObj(taskPool) { var canDo = []; for (var i in taskPool.tasks) { var t = taskPool.tasks[i]; if (!t.done && t.startedAt < 0 && t.isReady()) canDo.push(i); } canDo.sort(); if (canDo.length) taskPool.tasks[canDo[0]].done = 1; return taskPool.tasks[canDo[0]]; } function nextObjTime(taskPool, currentTime, nbWorkers) { var remainTask = 0, taskToFinish = 0; for (var i in taskPool.tasks) { var t = taskPool.tasks[i]; if (!t.done && t.startedAt >= 0) { if (t.startedAt +t.duration <= currentTime) t.done = true; else --nbWorkers; } if (t.startedAt == -1) ++remainTask; if (!t.done) ++taskToFinish; } while (nbWorkers > 0 && remainTask) { var task = nextObj(taskPool); if (task) { task.done = false; task.startedAt = currentTime; --remainTask; } else return true; --nbWorkers; } return taskToFinish > 0; } function ex1() { read(function(taskPool){ var result = ""; while (true) { var step = nextObj(taskPool); if (!step) break; result += step.taskId; } console.log(result); }); } function ex2() { read(function(taskPool){ var time =0; while (true) { var step = nextObjTime(taskPool, time, 5); if (!step) break; ++time; } console.log(time); }); } ex1(); ex2();