advent-of-code

Solutions for Advent of Code.
git clone git://git.amin.space/advent-of-code.git
Log | Files | Refs | LICENSE

commit da0038c9cf0d5746b3bbe6ce52fd04e7b8b823eb
parent 57cdbf3caf3a49a8676e93746d8f22ed70f86c3f
Author: amin <dev@aminmesbah.com>
Date:   Sat,  8 Dec 2018 06:50:16 +0000

Add solution for 07-2

FossilOrigin-Name: 1dbbfcabebeb9d1e0d434b2a3ba5a690c0951f87ce297989d66f00022e4e7b3b
Diffstat:
Aday_07.zig | 395+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dday_07_1.zig | 235-------------------------------------------------------------------------------
2 files changed, 395 insertions(+), 235 deletions(-)

diff --git a/day_07.zig b/day_07.zig @@ -0,0 +1,395 @@ +const std = @import("std"); +const debug = std.debug; +const mem = std.mem; + +pub fn main() !void { + var allocator = &std.heap.DirectAllocator.init().allocator; + + const result1 = try step_dependency_order(allocator, dependency_hierarchy); + defer allocator.free(result1); + debug.warn("07-1: {}\n", result1); + + const result2 = try step_completion_time(allocator, dependency_hierarchy, 5, 60); + debug.warn("07-2: {}\n", result2); +} + +fn step_completion_time(allocator: *mem.Allocator, rules: []const Rule, num_workers: u32, base_step_time: u32) !u32 { + const step_range = set_of_all_steps(rules); + const largest_letter = step_range[step_range.len - 1]; + + var workers = try allocator.alloc(Worker, num_workers); + defer allocator.free(workers); + for (workers) |*w| { + w.step = Worker.idle; + w.seconds_worked = 0; + } + + var completed_steps = try allocator.alloc(u8, step_range.len); + defer allocator.free(completed_steps); + var num_steps_completed: usize = 0; + + var current_second: u32 = 0; + while (num_steps_completed < completed_steps.len) : (current_second += 1) { + //debug.warn("{}: ", current_second); + //for (workers) |w| { + // debug.warn("{c} ", w.step); + //} + //debug.warn("{}\n", completed_steps); + + for (workers) |*w| { + // do work for this second + if (w.step != Worker.idle) { + w.seconds_worked += 1; + debug.assert(w.seconds_worked <= step_time(w.step, base_step_time)); + + // check for completed steps + if (w.seconds_worked == step_time(w.step, base_step_time)) { + completed_steps[num_steps_completed] = w.step; + num_steps_completed += 1; + w.step = Worker.idle; + w.seconds_worked = 0; + } + } + } + + const awaiting_steps = try available_steps(allocator, completed_steps[0..num_steps_completed], workers, step_range, rules); + defer allocator.free(awaiting_steps); + var num_awaiting_steps_taken: u32 = 0; + + for (workers) |*w| { + if (w.step == Worker.idle) { + if (num_awaiting_steps_taken < awaiting_steps.len) { + w.step = awaiting_steps[num_awaiting_steps_taken]; + num_awaiting_steps_taken += 1; + } + } + } + } + + return current_second - 1; +} + +test "step completion time" { + var allocator = &std.heap.DirectAllocator.init().allocator; + debug.assert(15 == try step_completion_time(allocator, test_hierarchy, 2, 0)); +} + +fn available_steps(allocator: *mem.Allocator, completed_steps: []u8, workers: []Worker, step_range: []const u8, rules: []const Rule) ![]const u8 { + var steps_to_return = std.ArrayList(u8).init(allocator); + + if (completed_steps.len == step_range.len - 1) { + // We've reached the end. There's only one uncompleted step. + for (step_range) |s| { + var step_is_done = false; + for (completed_steps) |done| { + if (done == s) { + step_is_done = true; + } + } + if (!step_is_done) { + try steps_to_return.append(s); + return steps_to_return.toSliceConst(); + } + } + } + + debug.assert(rules.len < 1000); + var relevant_rules_array = []bool{true} ** 1000; + var relevant_rules = relevant_rules_array[0..rules.len]; + + // cull irrelevant rules + for (completed_steps) |s| { + for (rules) |r, i| { + if (r.p == s) { + relevant_rules[i] = false; + } + } + } + + // Make sure we didn't cull rules inconsistently + for (completed_steps) |s| { + for (rules) |r, i| { + if (relevant_rules[i]) { + debug.assert(r.p != s); + debug.assert(r.c != s); + } + } + } + + // an available step is one that: + // - exists in the rules as a parent + // - does not exist in the rules as a child + // - is not the current step of any worker + for(step_range) |step| { + var step_exists_as_parent: bool = false; + var step_exists_as_child: bool = false; + var step_is_being_worked_on: bool = false; + + for (rules) |r, i| { + if (relevant_rules[i]) { + if (step == r.p) { + step_exists_as_parent = true; + } else if (step == r.c) { + step_exists_as_child = true; + } + } + } + + for (workers) |w| { + if (w.step == step) { + step_is_being_worked_on = true; + } + } + + if (step_exists_as_parent and !step_exists_as_child and !step_is_being_worked_on) { + try steps_to_return.append(step); + } + } + + return steps_to_return.toSliceConst(); +} + +const Worker = struct { + step: u8, + seconds_worked: u32, + const idle: u8 = '.'; +}; + +fn step_time(step: u8, base_step_time: u32) u32 { + debug.assert(step >= 'A'); + debug.assert(step <= 'Z'); + const step_alphabet_number = step - 'A' + 1; + return step_alphabet_number + base_step_time; +} + +test "step time" { + debug.assert(61 == step_time('A', 60)); + debug.assert(86 == step_time('Z', 60)); + debug.assert(1 == step_time('A', 0)); + debug.assert(26 == step_time('Z', 0)); +} + +fn step_dependency_order(allocator: *mem.Allocator, rules: []const Rule) ![]const u8 { + const step_range = set_of_all_steps(rules); + const largest_letter = step_range[step_range.len - 1]; + + var steps = try allocator.alloc(u8, step_range.len); + for (steps) |*s, i| { + s.* = next_step(steps[0..i], step_range, rules); + } + + return steps; +} + +test "step dependency order" { + var allocator = &std.heap.DirectAllocator.init().allocator; + debug.assert(mem.eql(u8, "CABDFE", try step_dependency_order(allocator, test_hierarchy))); +} + +fn next_step(done_steps: []u8, step_range: []const u8, rules: []const Rule) u8 { + if (done_steps.len == step_range.len - 1) { + // We've reached the end. There's only one undone step. + for (step_range) |s| { + var step_is_done = false; + for (done_steps) |done| { + if (done == s) { + step_is_done = true; + } + } + if (!step_is_done) { + return s; + } + } + } + + debug.assert(rules.len < 1000); + var relevant_rules_array = []bool{true} ** 1000; + var relevant_rules = relevant_rules_array[0..rules.len]; + + // cull irrelevant rules + for (done_steps) |s| { + for (rules) |r, i| { + if (r.p == s) { + relevant_rules[i] = false; + } + } + } + + // Make sure we didn't cull rules inconsistently + for (done_steps) |s| { + for (rules) |r, i| { + if (relevant_rules[i]) { + debug.assert(r.p != s); + debug.assert(r.c != s); + } + } + } + + { + // the next step is the first one alphabetically that: + // - exists in the rules as a parent + // - does not exist in the rules as a child + var step: u8 = step_range[0]; + while (step <= step_range[step_range.len - 1]) : (step += 1) { + var step_exists_as_parent: bool = false; + var step_exists_as_child: bool = false; + for (rules) |r, i| { + if (relevant_rules[i]) { + if (step == r.p) { + step_exists_as_parent = true; + } else if (step == r.c) { + step_exists_as_child = true; + } + } + } + if (step_exists_as_parent and !step_exists_as_child) { + return step; + } + } + } + unreachable; +} + +fn set_of_all_steps(rules: []const Rule) []const u8 { + // This assumes no letters in the alphabetical range are skipped + const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + var largest_letter: u8 = 'A'; + for (rules) |r| { + if (r.p > largest_letter) { + largest_letter = r.p; + } + if (r.c > largest_letter) { + largest_letter = r.c; + } + } + var num_letters = largest_letter - 'A' + 1; + var step_range = letters[0..num_letters]; + debug.assert(step_range.len <= 26); + return step_range; +} + +const Rule = struct { + p: u8, + c: u8, +}; + +inline fn rule(parent: u8, child: u8) Rule { + return Rule { + .p = parent, + .c = child, + }; +} + +const test_hierarchy = []const Rule { + rule('C', 'A'), + rule('C', 'F'), + rule('A', 'B'), + rule('A', 'D'), + rule('B', 'E'), + rule('D', 'E'), + rule('F', 'E'), +}; + +const dependency_hierarchy = []const Rule { + rule('X', 'C'), + rule('C', 'G'), + rule('F', 'G'), + rule('U', 'Y'), + rule('O', 'S'), + rule('D', 'N'), + rule('M', 'H'), + rule('J', 'Q'), + rule('G', 'R'), + rule('I', 'N'), + rule('R', 'K'), + rule('A', 'Z'), + rule('Y', 'L'), + rule('H', 'P'), + rule('K', 'S'), + rule('Z', 'P'), + rule('T', 'S'), + rule('N', 'P'), + rule('E', 'S'), + rule('S', 'W'), + rule('W', 'V'), + rule('L', 'V'), + rule('P', 'B'), + rule('Q', 'V'), + rule('B', 'V'), + rule('P', 'Q'), + rule('S', 'V'), + rule('C', 'Q'), + rule('I', 'H'), + rule('A', 'E'), + rule('H', 'Q'), + rule('G', 'V'), + rule('N', 'L'), + rule('R', 'Q'), + rule('W', 'L'), + rule('X', 'L'), + rule('X', 'J'), + rule('W', 'P'), + rule('U', 'B'), + rule('P', 'V'), + rule('O', 'P'), + rule('W', 'Q'), + rule('S', 'Q'), + rule('U', 'Z'), + rule('Z', 'T'), + rule('M', 'T'), + rule('A', 'P'), + rule('Z', 'B'), + rule('N', 'S'), + rule('H', 'N'), + rule('J', 'E'), + rule('M', 'J'), + rule('R', 'A'), + rule('A', 'Y'), + rule('F', 'V'), + rule('L', 'P'), + rule('K', 'L'), + rule('F', 'P'), + rule('G', 'L'), + rule('I', 'Q'), + rule('C', 'L'), + rule('I', 'Y'), + rule('G', 'B'), + rule('H', 'L'), + rule('X', 'U'), + rule('I', 'K'), + rule('R', 'N'), + rule('I', 'L'), + rule('M', 'I'), + rule('K', 'V'), + rule('G', 'E'), + rule('F', 'B'), + rule('O', 'Y'), + rule('Y', 'Q'), + rule('F', 'K'), + rule('N', 'W'), + rule('O', 'R'), + rule('N', 'E'), + rule('M', 'V'), + rule('H', 'T'), + rule('Y', 'T'), + rule('F', 'J'), + rule('F', 'O'), + rule('W', 'B'), + rule('T', 'E'), + rule('T', 'P'), + rule('F', 'M'), + rule('U', 'I'), + rule('H', 'S'), + rule('S', 'P'), + rule('T', 'W'), + rule('A', 'N'), + rule('O', 'N'), + rule('L', 'B'), + rule('U', 'K'), + rule('Z', 'W'), + rule('X', 'D'), + rule('Z', 'L'), + rule('I', 'T'), + rule('O', 'W'), + rule('I', 'B'), +}; diff --git a/day_07_1.zig b/day_07_1.zig @@ -1,235 +0,0 @@ -const std = @import("std"); -const debug = std.debug; -const mem = std.mem; - -pub fn main() !void { - var allocator = &std.heap.DirectAllocator.init().allocator; - const result = try step_order(allocator, dependency_hierarchy); - defer allocator.free(result); - debug.warn("07-1: {}\n", result); -} - -fn step_order(allocator: *mem.Allocator, rules: []const Rule) ![]const u8 { - const step_range = set_of_all_steps(rules); - const largest_letter = step_range[step_range.len - 1]; - - var steps = try allocator.alloc(u8, step_range.len); - for (steps) |*s, i| { - s.* = next_step(steps[0..i], step_range, rules); - } - - return steps; -} - -test "step order" { - var allocator = &std.heap.DirectAllocator.init().allocator; - debug.assert(mem.eql(u8, "CABDFE", try step_order(allocator, test_hierarchy))); -} - -fn next_step(done_steps: []u8, step_range: []const u8, rules: []const Rule) u8 { - if (done_steps.len == step_range.len - 1) { - // We've reached the end. There's only one undone step. - for (step_range) |s| { - var step_is_done = false; - for (done_steps) |done| { - if (done == s) { - step_is_done = true; - } - } - if (!step_is_done) { - return s; - } - } - } - - debug.assert(rules.len < 1000); - var relevant_rules_array = []bool{true} ** 1000; - var relevant_rules = relevant_rules_array[0..rules.len]; - - // cull irrelevant rules - for (done_steps) |s| { - for (rules) |r, i| { - if (r.p == s) { - relevant_rules[i] = false; - } - } - } - - // Make sure we didn't cull rules inconsistently - for (done_steps) |s| { - for (rules) |r, i| { - if (relevant_rules[i]) { - debug.assert(r.p != s); - debug.assert(r.c != s); - } - } - } - - { - // the next step is the first one alphabetically that: - // - exists in the rules as a parent - // - does not exist in the rules as a child - var step: u8 = step_range[0]; - while (step <= step_range[step_range.len - 1]) : (step += 1) { - var step_exists_as_parent: bool = false; - var step_exists_as_child: bool = false; - for (rules) |r, i| { - if (relevant_rules[i]) { - if (step == r.p) { - step_exists_as_parent = true; - } else if (step == r.c) { - step_exists_as_child = true; - } - } - } - if (step_exists_as_parent and !step_exists_as_child) { - return step; - } - } - } - unreachable; -} - -fn set_of_all_steps(rules: []const Rule) []const u8 { - // This assumes no letters in the alphabetical range are skipped - const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - var largest_letter: u8 = 'A'; - for (rules) |r| { - if (r.p > largest_letter) { - largest_letter = r.p; - } - if (r.c > largest_letter) { - largest_letter = r.c; - } - } - var num_letters = largest_letter - 'A' + 1; - var step_range = letters[0..num_letters]; - debug.assert(step_range.len <= 26); - return step_range; -} - -const Rule = struct { - p: u8, - c: u8, -}; - -inline fn rule(parent: u8, child: u8) Rule { - return Rule { - .p = parent, - .c = child, - }; -} - -const test_hierarchy = []const Rule { - rule('C', 'A'), - rule('C', 'F'), - rule('A', 'B'), - rule('A', 'D'), - rule('B', 'E'), - rule('D', 'E'), - rule('F', 'E'), -}; - -const dependency_hierarchy = []const Rule { - rule('X', 'C'), - rule('C', 'G'), - rule('F', 'G'), - rule('U', 'Y'), - rule('O', 'S'), - rule('D', 'N'), - rule('M', 'H'), - rule('J', 'Q'), - rule('G', 'R'), - rule('I', 'N'), - rule('R', 'K'), - rule('A', 'Z'), - rule('Y', 'L'), - rule('H', 'P'), - rule('K', 'S'), - rule('Z', 'P'), - rule('T', 'S'), - rule('N', 'P'), - rule('E', 'S'), - rule('S', 'W'), - rule('W', 'V'), - rule('L', 'V'), - rule('P', 'B'), - rule('Q', 'V'), - rule('B', 'V'), - rule('P', 'Q'), - rule('S', 'V'), - rule('C', 'Q'), - rule('I', 'H'), - rule('A', 'E'), - rule('H', 'Q'), - rule('G', 'V'), - rule('N', 'L'), - rule('R', 'Q'), - rule('W', 'L'), - rule('X', 'L'), - rule('X', 'J'), - rule('W', 'P'), - rule('U', 'B'), - rule('P', 'V'), - rule('O', 'P'), - rule('W', 'Q'), - rule('S', 'Q'), - rule('U', 'Z'), - rule('Z', 'T'), - rule('M', 'T'), - rule('A', 'P'), - rule('Z', 'B'), - rule('N', 'S'), - rule('H', 'N'), - rule('J', 'E'), - rule('M', 'J'), - rule('R', 'A'), - rule('A', 'Y'), - rule('F', 'V'), - rule('L', 'P'), - rule('K', 'L'), - rule('F', 'P'), - rule('G', 'L'), - rule('I', 'Q'), - rule('C', 'L'), - rule('I', 'Y'), - rule('G', 'B'), - rule('H', 'L'), - rule('X', 'U'), - rule('I', 'K'), - rule('R', 'N'), - rule('I', 'L'), - rule('M', 'I'), - rule('K', 'V'), - rule('G', 'E'), - rule('F', 'B'), - rule('O', 'Y'), - rule('Y', 'Q'), - rule('F', 'K'), - rule('N', 'W'), - rule('O', 'R'), - rule('N', 'E'), - rule('M', 'V'), - rule('H', 'T'), - rule('Y', 'T'), - rule('F', 'J'), - rule('F', 'O'), - rule('W', 'B'), - rule('T', 'E'), - rule('T', 'P'), - rule('F', 'M'), - rule('U', 'I'), - rule('H', 'S'), - rule('S', 'P'), - rule('T', 'W'), - rule('A', 'N'), - rule('O', 'N'), - rule('L', 'B'), - rule('U', 'K'), - rule('Z', 'W'), - rule('X', 'D'), - rule('Z', 'L'), - rule('I', 'T'), - rule('O', 'W'), - rule('I', 'B'), -};