-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
133cfaf
commit ebed17e
Showing
4 changed files
with
1,695 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
class DataReader | ||
def initialize(file) | ||
@lines = File.readlines(file).map(&:strip) | ||
end | ||
|
||
def empty_line_index | ||
@lines.find_index { |line| line == "" } | ||
end | ||
|
||
def ordering_rules | ||
@lines[0...empty_line_index] || [] | ||
end | ||
|
||
def pages_to_produce | ||
return [] unless empty_line_index | ||
|
||
@lines[empty_line_index + 1..] || [] | ||
end | ||
|
||
def create_rules | ||
ordering_rules.map do |line| | ||
Rule.new(*line.split("|").map(&:to_i)) | ||
end | ||
end | ||
|
||
def create_page_updates | ||
pages_to_produce.map do |line| | ||
PageUpdate.new(line.split(",").map(&:to_i)) | ||
end | ||
end | ||
end | ||
|
||
class Rule | ||
attr_reader :page, :before_page | ||
|
||
def initialize(page, before_page) | ||
@page = page | ||
@before_page = before_page | ||
end | ||
end | ||
|
||
class PageUpdate | ||
attr_reader :numbers | ||
|
||
def initialize(numbers) | ||
@numbers = numbers | ||
end | ||
|
||
def middle_number | ||
numbers.empty? ? nil : numbers[numbers.length / 2] | ||
end | ||
end | ||
|
||
class RuleScanner | ||
def initialize(rules, page_updates) | ||
@rules = rules | ||
@page_updates = page_updates | ||
end | ||
|
||
def valid_updates | ||
@page_updates.select do |page_update| | ||
orderer = Orderer.new(@rules, page_update) | ||
orderer.in_order? | ||
end | ||
end | ||
|
||
def invalid_updates | ||
@page_updates.reject do |page_update| | ||
orderer = Orderer.new(@rules, page_update) | ||
orderer.in_order? | ||
end | ||
end | ||
|
||
def valid_total | ||
valid_updates.sum(&:middle_number) | ||
end | ||
|
||
def invalid_total | ||
invalid_updates.map do |page_update| | ||
orderer = Orderer.new(@rules, page_update) | ||
orderer.reorder | ||
end.sum(&:middle_number) | ||
end | ||
end | ||
|
||
class Orderer | ||
attr_reader :page_update | ||
|
||
def initialize(rules, page_update) | ||
@rules = rules | ||
@page_update = page_update | ||
end | ||
|
||
def rules_for(number) | ||
@rules.select { |r| r.page == number } | ||
end | ||
|
||
def scoped_rules_for(number) | ||
rules_for(number).select { |r| page_update.numbers.include? r.before_page } | ||
end | ||
|
||
def lower_priority_pages_for(number) | ||
scoped_rules_for(number).map(&:before_page).sort.uniq | ||
end | ||
|
||
def in_order? | ||
numbers = page_update.numbers | ||
|
||
numbers.each_with_index do |number, i| | ||
rest = numbers[i + 1..] | ||
return false unless lower_priority_pages_for(number).all? { |n| rest.include?(n) } | ||
end | ||
|
||
true | ||
end | ||
|
||
def reorder | ||
numbers = page_update.numbers | ||
return [] if numbers.empty? | ||
|
||
numbers.sort! do |a, b| | ||
lower_priority_pages_for(a).include?(b) ? -1 : 1 | ||
end | ||
|
||
PageUpdate.new(numbers) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
require "spec_helper" | ||
require "advent_05_print_queue" | ||
|
||
describe "Puzzle" do | ||
context "with sample data" do | ||
let(:data) do | ||
DataReader.new("./spec/fixtures/advent-05-sample.txt") | ||
end | ||
|
||
it "knows the ordering rules" do | ||
result = data.ordering_rules | ||
|
||
expected = [ | ||
"47|53", "97|13", "97|61", "97|47", "75|29", "61|13", "75|53", | ||
"29|13", "97|29", "53|29", "61|53", "97|53", "61|29", "47|13", | ||
"75|47", "97|75", "47|61", "75|61", "47|29", "75|13", "53|13" | ||
] | ||
|
||
expect(result).to eq(expected) | ||
end | ||
|
||
it "knows the pages to produce" do | ||
result = data.pages_to_produce | ||
|
||
expected = %w[ | ||
75,47,61,53,29 | ||
97,61,53,29,13 | ||
75,29,13 | ||
75,97,47,61,53 | ||
61,13,29 | ||
97,13,75,29,47 | ||
] | ||
|
||
expect(result).to eq(expected) | ||
end | ||
|
||
it "knows the rules for a number" do | ||
rules = data.create_rules | ||
page_update = PageUpdate.new([]) | ||
|
||
orderer = Orderer.new(rules, page_update) | ||
|
||
rules = orderer.rules_for(75) | ||
|
||
before_numbers = rules.map(&:before_page).sort | ||
|
||
expect(before_numbers).to eq([13, 29, 47, 53, 61]) | ||
end | ||
|
||
it "knows which pages a number goes before" do | ||
rules = data.create_rules | ||
page_update = PageUpdate.new([75, 47, 61, 53, 29]) | ||
|
||
orderer = Orderer.new(rules, page_update) | ||
|
||
expect(orderer.lower_priority_pages_for(75)).to eq([29, 47, 53, 61]) | ||
end | ||
|
||
it "knows if a page update is in the right order" do | ||
rules = data.create_rules | ||
page_update = PageUpdate.new([75, 47, 61, 53, 29]) | ||
|
||
orderer = Orderer.new(rules, page_update) | ||
|
||
expect(orderer.in_order?).to be(true) | ||
end | ||
|
||
it "knows if a page update is in the right order 2" do | ||
rules = data.create_rules | ||
page_update = PageUpdate.new([97, 61, 53, 29, 13]) | ||
|
||
orderer = Orderer.new(rules, page_update) | ||
|
||
expect(orderer.in_order?).to be(true) | ||
end | ||
|
||
it "knows if a page update is in the right order 3" do | ||
rules = data.create_rules | ||
page_update = PageUpdate.new([75, 29, 13]) | ||
|
||
orderer = Orderer.new(rules, page_update) | ||
|
||
expect(orderer.in_order?).to be(true) | ||
end | ||
|
||
it "knows when a page update is in the wrong order" do | ||
rules = data.create_rules | ||
page_update = PageUpdate.new([75, 97, 47, 61, 53]) | ||
|
||
orderer = Orderer.new(rules, page_update) | ||
|
||
expect(orderer.in_order?).to be(false) | ||
end | ||
|
||
it "knows when a page update is in the wrong order 2" do | ||
rules = data.create_rules | ||
page_update = PageUpdate.new([61, 13, 29]) | ||
|
||
orderer = Orderer.new(rules, page_update) | ||
|
||
expect(orderer.in_order?).to be(false) | ||
end | ||
|
||
it "knows when a page update is in the wrong order 3" do | ||
rules = data.create_rules | ||
page_update = PageUpdate.new([97, 13, 75, 29, 47]) | ||
|
||
orderer = Orderer.new(rules, page_update) | ||
|
||
expect(orderer.in_order?).to be(false) | ||
end | ||
|
||
it "knows the correctly-ordered updates" do | ||
rules = data.create_rules | ||
page_updates = data.create_page_updates | ||
|
||
scanner = RuleScanner.new(rules, page_updates) | ||
|
||
valid = scanner.valid_updates | ||
|
||
expect(valid.length).to be(3) | ||
|
||
expect(valid[0].numbers).to eq([75, 47, 61, 53, 29]) | ||
expect(valid[0].middle_number).to eq(61) | ||
|
||
expect(valid[1].numbers).to eq([97, 61, 53, 29, 13]) | ||
expect(valid[1].middle_number).to eq(53) | ||
|
||
expect(valid[2].numbers).to eq([75, 29, 13]) | ||
expect(valid[2].middle_number).to eq(29) | ||
end | ||
|
||
it "knows how to reorder" do | ||
rules = data.create_rules | ||
page_update = PageUpdate.new([75, 97, 47, 61, 53]) | ||
|
||
orderer = Orderer.new(rules, page_update) | ||
|
||
expect(orderer.reorder.numbers).to eq([97, 75, 47, 61, 53]) | ||
end | ||
end | ||
|
||
context "with puzzle data" do | ||
let(:data) do | ||
DataReader.new("./spec/fixtures/advent-05.txt") | ||
end | ||
|
||
it "solves part i" do | ||
rules = data.create_rules | ||
page_updates = data.create_page_updates | ||
|
||
scanner = RuleScanner.new(rules, page_updates) | ||
|
||
expect(scanner.valid_total).to eq(6260) | ||
end | ||
|
||
it "solves part ii" do | ||
rules = data.create_rules | ||
page_updates = data.create_page_updates | ||
|
||
scanner = RuleScanner.new(rules, page_updates) | ||
|
||
expect(scanner.invalid_total).to eq(5346) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
47|53 | ||
97|13 | ||
97|61 | ||
97|47 | ||
75|29 | ||
61|13 | ||
75|53 | ||
29|13 | ||
97|29 | ||
53|29 | ||
61|53 | ||
97|53 | ||
61|29 | ||
47|13 | ||
75|47 | ||
97|75 | ||
47|61 | ||
75|61 | ||
47|29 | ||
75|13 | ||
53|13 | ||
|
||
75,47,61,53,29 | ||
97,61,53,29,13 | ||
75,29,13 | ||
75,97,47,61,53 | ||
61,13,29 | ||
97,13,75,29,47 |
Oops, something went wrong.