From 3c579214382726c96d89953711ef78075ca7c69b Mon Sep 17 00:00:00 2001 From: Patrick Auernig Date: Wed, 8 Dec 2021 01:05:17 +0100 Subject: [PATCH] Refactor 2015 days 01 to 10 Split parts into separate files and remove some unused files --- .gitignore | 4 + 2015/day-01/common.rb | 8 ++ 2015/day-01/main.rb | 41 -------- 2015/day-01/part_one.rb | 10 ++ 2015/day-01/part_two.rb | 15 +++ 2015/day-02/common.rb | 6 ++ 2015/day-02/inputs/{test.txt => sample.txt} | 0 2015/day-02/main.rb | 55 ----------- 2015/day-02/part_one.rb | 12 +++ 2015/day-02/part_two.rb | 17 ++++ 2015/day-03/common.rb | 18 ++++ 2015/day-03/inputs/{test.txt => sample.txt} | 0 2015/day-03/main.rb | 78 --------------- 2015/day-03/part_one.rb | 17 ++++ 2015/day-03/part_two.rb | 26 +++++ 2015/day-04/.gitignore | 1 - 2015/day-04/common.rs | 54 +++++++++++ 2015/day-04/{src => common}/md5.rs | 0 2015/day-04/{src => common}/threadpool.rs | 0 2015/day-04/inputs/{test.txt => sample.txt} | 0 2015/day-04/part_one.rs | 18 ++++ 2015/day-04/part_two.rs | 18 ++++ 2015/day-04/src/main.rs | 101 -------------------- 2015/day-05/common.rb | 9 ++ 2015/day-05/inputs/{test.txt => sample.txt} | 0 2015/day-05/main.rb | 86 ----------------- 2015/day-05/part_one.rb | 30 ++++++ 2015/day-05/part_two.rb | 36 +++++++ 2015/day-06/.ruby-version | 1 - 2015/day-06/common.rb | 33 +++++++ 2015/day-06/inputs/{test.txt => sample.txt} | 0 2015/day-06/main.rb | 75 --------------- 2015/day-06/part_one.rb | 11 +++ 2015/day-06/part_two.rb | 15 +++ 2015/day-07/.gitignore | 1 - 2015/day-07/{src/circuit.rs => common.rs} | 84 ++++++++++------ 2015/day-07/inputs/{test.txt => sample.txt} | 0 2015/day-07/part_one.rs | 23 +++++ 2015/day-07/part_two.rs | 32 +++++++ 2015/day-07/src/main.rs | 54 ----------- 2015/day-08/.ruby-version | 1 - 2015/day-08/inputs/{test.txt => sample.txt} | 0 2015/day-08/main.rb | 38 -------- 2015/day-08/part_one.rb | 7 ++ 2015/day-08/part_two.rb | 7 ++ 2015/day-09/.gitignore | 2 +- 2015/day-09/common.rs | 39 ++++++++ 2015/day-09/dot.rs | 53 ++++++++++ 2015/day-09/{src => }/graph.rs | 0 2015/day-09/inputs/{test.txt => sample.txt} | 0 2015/day-09/{src/part1.rs => part_one.rs} | 22 +++-- 2015/day-09/{src/part2.rs => part_two.rs} | 46 +++++---- 2015/day-09/src/main.rs | 34 ------- 2015/day-09/src/utils.rs | 58 ----------- 2015/day-10/.ruby-version | 1 - 2015/day-10/common.rb | 22 +++++ 2015/day-10/inputs/{test.txt => sample.txt} | 0 2015/day-10/main.rb | 42 -------- 2015/day-10/part_one.rb | 8 ++ 2015/day-10/part_two.rb | 8 ++ 60 files changed, 655 insertions(+), 722 deletions(-) create mode 100644 2015/day-01/common.rb delete mode 100755 2015/day-01/main.rb create mode 100755 2015/day-01/part_one.rb create mode 100755 2015/day-01/part_two.rb create mode 100644 2015/day-02/common.rb rename 2015/day-02/inputs/{test.txt => sample.txt} (100%) delete mode 100755 2015/day-02/main.rb create mode 100755 2015/day-02/part_one.rb create mode 100755 2015/day-02/part_two.rb create mode 100644 2015/day-03/common.rb rename 2015/day-03/inputs/{test.txt => sample.txt} (100%) delete mode 100755 2015/day-03/main.rb create mode 100755 2015/day-03/part_one.rb create mode 100755 2015/day-03/part_two.rb delete mode 100644 2015/day-04/.gitignore create mode 100644 2015/day-04/common.rs rename 2015/day-04/{src => common}/md5.rs (100%) rename 2015/day-04/{src => common}/threadpool.rs (100%) rename 2015/day-04/inputs/{test.txt => sample.txt} (100%) create mode 100644 2015/day-04/part_one.rs create mode 100644 2015/day-04/part_two.rs delete mode 100644 2015/day-04/src/main.rs create mode 100644 2015/day-05/common.rb rename 2015/day-05/inputs/{test.txt => sample.txt} (100%) delete mode 100755 2015/day-05/main.rb create mode 100755 2015/day-05/part_one.rb create mode 100755 2015/day-05/part_two.rb delete mode 100644 2015/day-06/.ruby-version create mode 100644 2015/day-06/common.rb rename 2015/day-06/inputs/{test.txt => sample.txt} (100%) delete mode 100755 2015/day-06/main.rb create mode 100755 2015/day-06/part_one.rb create mode 100755 2015/day-06/part_two.rb delete mode 100644 2015/day-07/.gitignore rename 2015/day-07/{src/circuit.rs => common.rs} (75%) rename 2015/day-07/inputs/{test.txt => sample.txt} (100%) create mode 100644 2015/day-07/part_one.rs create mode 100644 2015/day-07/part_two.rs delete mode 100644 2015/day-07/src/main.rs delete mode 100644 2015/day-08/.ruby-version rename 2015/day-08/inputs/{test.txt => sample.txt} (100%) delete mode 100755 2015/day-08/main.rb create mode 100755 2015/day-08/part_one.rb create mode 100755 2015/day-08/part_two.rb create mode 100644 2015/day-09/common.rs create mode 100644 2015/day-09/dot.rs rename 2015/day-09/{src => }/graph.rs (100%) rename 2015/day-09/inputs/{test.txt => sample.txt} (100%) rename 2015/day-09/{src/part1.rs => part_one.rs} (80%) rename 2015/day-09/{src/part2.rs => part_two.rs} (53%) delete mode 100644 2015/day-09/src/main.rs delete mode 100644 2015/day-09/src/utils.rs delete mode 100644 2015/day-10/.ruby-version create mode 100644 2015/day-10/common.rb rename 2015/day-10/inputs/{test.txt => sample.txt} (100%) delete mode 100755 2015/day-10/main.rb create mode 100755 2015/day-10/part_one.rb create mode 100755 2015/day-10/part_two.rb diff --git a/.gitignore b/.gitignore index 751553b..aec522b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ *.bak + +# build artifacts +part_one +part_two diff --git a/2015/day-01/common.rb b/2015/day-01/common.rb new file mode 100644 index 0000000..d46e6f9 --- /dev/null +++ b/2015/day-01/common.rb @@ -0,0 +1,8 @@ +INPUT = File.readlines(ARGV.first, chomp: true).first.chars + +def match_paren(char) + case char + when "(" then 1 + when ")" then -1 + end +end diff --git a/2015/day-01/main.rb b/2015/day-01/main.rb deleted file mode 100755 index f38397f..0000000 --- a/2015/day-01/main.rb +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env ruby - -require "pathname" - -INPUTS = ["inputs/sample.txt", "inputs/puzzle.txt"].map { |x| Pathname(x) } - -def match_paren(char) - case char - when "(" then 1 - when ")" then -1 - end -end - -def solve_part_1(content) - content.chars.sum { |x| match_paren(x) } -end - -def solve_part_2(content) - content.chars.each.with_index(1).reduce(0) do |acc, (char, index)| - acc += match_paren(char) - return index if acc == -1 - acc - end - nil -end - -def main(files) - files.each do |file| - puts "File: #{file}" - file.read.lines do |line| - next if line.empty? - result = solve_part_1(line.chomp) - puts " Floor: #{result}" - result = solve_part_2(line.chomp) - puts " Basement Floor Position: #{result}" - puts " -" * 15 - end - end -end - -main(INPUTS) diff --git a/2015/day-01/part_one.rb b/2015/day-01/part_one.rb new file mode 100755 index 0000000..9f181ad --- /dev/null +++ b/2015/day-01/part_one.rb @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby + +require_relative "common" + +def part_one(chars) + chars.sum { |x| match_paren(x) } +end + +result = part_one(INPUT) +puts result diff --git a/2015/day-01/part_two.rb b/2015/day-01/part_two.rb new file mode 100755 index 0000000..98d84c3 --- /dev/null +++ b/2015/day-01/part_two.rb @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby + +require_relative "common" + +def part_two(chars) + chars.each.with_index(1).reduce(0) do |acc, (char, index)| + acc += match_paren(char) + return index if acc == -1 + acc + end + nil +end + +result = part_two(INPUT) +puts result diff --git a/2015/day-02/common.rb b/2015/day-02/common.rb new file mode 100644 index 0000000..7f5779c --- /dev/null +++ b/2015/day-02/common.rb @@ -0,0 +1,6 @@ +INPUT = File.readlines(ARGV.first, chomp: true).lazy.map do |num| + dims = num.split("x").map(&:to_i) + [sides(*dims), *dims] +end + +def sides(l, w, h) = [l * w, w * h, h * l] diff --git a/2015/day-02/inputs/test.txt b/2015/day-02/inputs/sample.txt similarity index 100% rename from 2015/day-02/inputs/test.txt rename to 2015/day-02/inputs/sample.txt diff --git a/2015/day-02/main.rb b/2015/day-02/main.rb deleted file mode 100755 index 2c75420..0000000 --- a/2015/day-02/main.rb +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env ruby - -require "pathname" - -INPUTS = [ - Pathname("inputs/test.txt"), - Pathname("inputs/puzzle.txt"), -].freeze - -def parse_input(data) - data.chomp.split("x").map(&:to_i) -end - -def sides(length, width, height) - [length * width, width * height, height * length] -end - -def solve_part_1(input) - input.lines.sum do |line| - sides = sides(*parse_input(line)) - smallest = sides.min - sides.sum { |x| x * 2 } + smallest - end -end - -def solve_part_2(input) - input.lines.sum do |line| - length, width, height = parse_input(line) - sides = sides(length, width, height) - circumference = - case sides.map.with_index.min.last - when 0 then length * 2 + width * 2 - when 1 then width * 2 + height * 2 - when 2 then height * 2 + length * 2 - end - circumference + length * width * height - end -end - -def main(files) - files.each do |file| - puts "File: #{file}" - content = file.read - - result = solve_part_1(content.chomp) - puts " Wrapping Paper: #{result}" - puts " -" * 15 - - result = solve_part_2(content.chomp) - puts " Ribbon Length: #{result}" - puts " -" * 15 - end -end - -main(INPUTS) diff --git a/2015/day-02/part_one.rb b/2015/day-02/part_one.rb new file mode 100755 index 0000000..4259ade --- /dev/null +++ b/2015/day-02/part_one.rb @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby + +require_relative "common" + +def part_one(dims) + dims.sum do |sides, *| + smallest = sides.min + sides.sum { |x| x * 2 } + smallest + end +end + +puts part_one(INPUT) diff --git a/2015/day-02/part_two.rb b/2015/day-02/part_two.rb new file mode 100755 index 0000000..70e07e1 --- /dev/null +++ b/2015/day-02/part_two.rb @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby + +require_relative "common" + +def part_two(dims) + dims.sum do |sides, length, width, height| + circumference = + case sides.map.with_index.min.last + when 0 then length * 2 + width * 2 + when 1 then width * 2 + height * 2 + when 2 then height * 2 + length * 2 + end + circumference + length * width * height + end +end + +puts part_two(INPUT) diff --git a/2015/day-03/common.rb b/2015/day-03/common.rb new file mode 100644 index 0000000..921f7a4 --- /dev/null +++ b/2015/day-03/common.rb @@ -0,0 +1,18 @@ +INPUT = File + .readlines(ARGV.first, chomp: true) + .lazy.map do |line| + line.each_char.map { |d| position_modifier(d) } + end + +def position_modifier(direction) + case direction + when ">" then [1, 0] + when "<" then [-1, 0] + when "^" then [0, 1] + when "v" then [0, -1] + end +end + +def apply_direction(position, change) + position.map.with_index { |v, i| v + change[i] } +end diff --git a/2015/day-03/inputs/test.txt b/2015/day-03/inputs/sample.txt similarity index 100% rename from 2015/day-03/inputs/test.txt rename to 2015/day-03/inputs/sample.txt diff --git a/2015/day-03/main.rb b/2015/day-03/main.rb deleted file mode 100755 index 9319def..0000000 --- a/2015/day-03/main.rb +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env ruby - -require "pathname" -require "set" - -INPUTS = [ - Pathname("inputs/test.txt"), - Pathname("inputs/puzzle.txt"), -].freeze - -def position_modifier(direction) - case direction - when ">" then [1, 0] - when "<" then [-1, 0] - when "^" then [0, 1] - when "v" then [0, -1] - end -end - -def apply_direction(position, change) - position.map.with_index { |v, i| v + change[i] } -end - -def next_position(position, direction) - apply_direction(position, position_modifier(direction)) -end - -def solve_part_1(input) - input.lines.map do |line| - puts " " + "-" * 10 - - position = [0, 0] - - houses = - line.chomp.each_char.each_with_object(Set[position]) do |direction, visited| - next_pos = next_position(position, direction) - visited.add(next_pos) - position = next_pos - end - - puts " Houses: #{houses.size}" - end -end - -def solve_part_2(input) - input.lines.map do |line| - puts " " + "-" * 10 - - position_s = [0, 0] - position_r = position_s.dup - - houses = - line.chomp.each_char.each_with_object(Set[position_s.dup]).with_index(1) do |(direction, visited), index| - if index.even? - next_pos = next_position(position_s, direction) - visited.add(next_pos) - position_s = next_pos - else - next_pos = next_position(position_r, direction) - visited.add(next_pos) - position_r = next_pos - end - end - - puts " Houses: #{houses.size}" - end -end - -def main(files) - files.each do |file| - puts "File: #{file}" - solve_part_1(file.read.chomp) - puts "=" * 15 - solve_part_2(file.read.chomp) - end -end - -main(INPUTS) diff --git a/2015/day-03/part_one.rb b/2015/day-03/part_one.rb new file mode 100755 index 0000000..14b25b2 --- /dev/null +++ b/2015/day-03/part_one.rb @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby + +require "set" +require_relative "common" + +def part_one(chars) + position = [0, 0] + chars + .each_with_object(Set[position]) do |direction, visited| + next_pos = apply_direction(position, direction) + visited.add(next_pos) + position = next_pos + end + .size +end + +puts part_one(INPUT.first) diff --git a/2015/day-03/part_two.rb b/2015/day-03/part_two.rb new file mode 100755 index 0000000..98a29ab --- /dev/null +++ b/2015/day-03/part_two.rb @@ -0,0 +1,26 @@ +#!/usr/bin/env ruby + +require "set" +require_relative "common" + +def part_two(chars) + position_s = [0, 0] + position_r = position_s.dup + + chars + .each_with_object(Set[position_s.dup]) + .with_index(1) do |(direction, visited), index| + if index.even? + next_pos = apply_direction(position_s, direction) + visited.add(next_pos) + position_s = next_pos + else + next_pos = apply_direction(position_r, direction) + visited.add(next_pos) + position_r = next_pos + end + end + .size +end + +puts part_two(INPUT.first) diff --git a/2015/day-04/.gitignore b/2015/day-04/.gitignore deleted file mode 100644 index ba2906d..0000000 --- a/2015/day-04/.gitignore +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/2015/day-04/common.rs b/2015/day-04/common.rs new file mode 100644 index 0000000..0739a56 --- /dev/null +++ b/2015/day-04/common.rs @@ -0,0 +1,54 @@ +mod md5; +mod threadpool; + +pub type Result = std::result::Result>; +pub type ThreadPool = threadpool::ThreadPool>; + +pub fn extract_result(pool: &ThreadPool) -> Option { + let mut smallest = None; + while let Some(result) = pool.next_result().unwrap() { + let result = result.into_iter().min(); + if !result.is_none() && (smallest.is_none() || smallest > result) { + smallest = result; + } + } + smallest +} + +pub fn find_suffix_with_zeroes(input: &str, amount: usize) -> usize { + let pool = ThreadPool::with_threads(8); + + let mut start = 1; + let mut tries = 8; + + let test_string = "0".repeat(amount); + + loop { + if tries == 0 { + match extract_result(&pool) { + None => tries = 7, + Some(v) => return v, + } + } + + let test_string = test_string.clone(); + let input = input.to_owned(); + pool.add_task(move || { + (start..) + .into_iter() + .take(20_000) + .filter_map(|i| { + let secret = format!("{}{}", input, i); + let hexdigest = md5::hexdigest(&secret); + if hexdigest.starts_with(&test_string) { + Some(i) + } else { + None + } + }) + .collect::>() + }); + tries -= 1; + start += 20_000; + } +} diff --git a/2015/day-04/src/md5.rs b/2015/day-04/common/md5.rs similarity index 100% rename from 2015/day-04/src/md5.rs rename to 2015/day-04/common/md5.rs diff --git a/2015/day-04/src/threadpool.rs b/2015/day-04/common/threadpool.rs similarity index 100% rename from 2015/day-04/src/threadpool.rs rename to 2015/day-04/common/threadpool.rs diff --git a/2015/day-04/inputs/test.txt b/2015/day-04/inputs/sample.txt similarity index 100% rename from 2015/day-04/inputs/test.txt rename to 2015/day-04/inputs/sample.txt diff --git a/2015/day-04/part_one.rs b/2015/day-04/part_one.rs new file mode 100644 index 0000000..0cee92d --- /dev/null +++ b/2015/day-04/part_one.rs @@ -0,0 +1,18 @@ +mod common; + +use std::env; +use std::fs::read_to_string; + +use common::{find_suffix_with_zeroes, Result}; + +fn main() -> Result<()> { + let path = env::args().skip(1).next().unwrap(); + let input = read_to_string(path)?; + let input = input.lines().next().unwrap().to_owned(); + + let result = find_suffix_with_zeroes(&input, 5); + + println!("{}", result); + + Ok(()) +} diff --git a/2015/day-04/part_two.rs b/2015/day-04/part_two.rs new file mode 100644 index 0000000..e4afe64 --- /dev/null +++ b/2015/day-04/part_two.rs @@ -0,0 +1,18 @@ +mod common; + +use std::env; +use std::fs::read_to_string; + +use common::{find_suffix_with_zeroes, Result}; + +fn main() -> Result<()> { + let path = env::args().skip(1).next().unwrap(); + let input = read_to_string(path)?; + let input = input.lines().next().unwrap().to_owned(); + + let result = find_suffix_with_zeroes(&input, 6); + + println!("{}", result); + + Ok(()) +} diff --git a/2015/day-04/src/main.rs b/2015/day-04/src/main.rs deleted file mode 100644 index bb87732..0000000 --- a/2015/day-04/src/main.rs +++ /dev/null @@ -1,101 +0,0 @@ -mod md5; -mod threadpool; - -use threadpool::ThreadPool; - -macro_rules! infile { - [$path:literal] => { ($path, include_str!($path)) } -} - -const INPUTS: &[(&str, &str)] = &[ - infile!("../inputs/test.txt"), - infile!("../inputs/puzzle.txt"), -]; - -fn extract_result(pool: &ThreadPool>) -> Option { - let mut smallest = None; - while let Some(result) = pool.next_result().unwrap() { - let result = result.into_iter().min(); - if !result.is_none() && (smallest.is_none() || smallest > result) { - smallest = result; - } - } - smallest -} - -fn solve_part_1(pool: &ThreadPool>, input: &str) -> usize { - let mut start = 1; - let mut tries = 7; - - loop { - if tries == 0 { - match extract_result(&pool) { - None =>{ tries = 7 }, - Some(v) => return v, - } - } - - let input = input.to_string(); - pool.add_task(move || { - (start..).into_iter() - .take(20_000) - .filter_map(|i| { - let secret = format!("{}{}", input, i); - let hexdigest = md5::hexdigest(&secret); - if hexdigest.starts_with("00000") { Some(i) } else { None } - }) - .collect::>() - }); - tries -= 1; - start += 20_000; - } -} - -fn solve_part_2(pool: &ThreadPool>, input: &str) -> usize { - let mut start = 1; - let mut tries = 8; - - loop { - if tries == 0 { - match extract_result(&pool) { - None =>{ tries = 7 }, - Some(v) => return v, - } - } - - let input = input.to_string(); - pool.add_task(move || { - (start..).into_iter() - .take(20_000) - .filter_map(|i| { - let secret = format!("{}{}", input, i); - let hexdigest = md5::hexdigest(&secret); - if hexdigest.starts_with("000000") { Some(i) } else { None } - }) - .collect::>() - }); - - tries -= 1; - start += 20_000; - } -} - -fn main() { - let pool = ThreadPool::with_threads(8); - - for (path, input) in INPUTS { - println!("File: {}", path); - - for line in input.split('\n') { - if line.is_empty() { continue } - - println!("\tInput: {}", line); - - let solution = solve_part_1(&pool, &line); - println!("\t\tFive leading zeroes: {}", solution); - - let solution = solve_part_2(&pool, &line); - println!("\t\tSix leading zeroes: {}", solution); - } - } -} diff --git a/2015/day-05/common.rb b/2015/day-05/common.rb new file mode 100644 index 0000000..056f129 --- /dev/null +++ b/2015/day-05/common.rb @@ -0,0 +1,9 @@ +LINES = File.each_line(ARGV.first, chomp: true) + +def count_nice(lines) + LINES.sum do |line| + # line = line.chomp # chomp: true keyword argument emits warnings + next 0 if line.empty? + yield(line) ? 1 : 0 + end +end diff --git a/2015/day-05/inputs/test.txt b/2015/day-05/inputs/sample.txt similarity index 100% rename from 2015/day-05/inputs/test.txt rename to 2015/day-05/inputs/sample.txt diff --git a/2015/day-05/main.rb b/2015/day-05/main.rb deleted file mode 100755 index 6eed4dc..0000000 --- a/2015/day-05/main.rb +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env -S ruby - -require "pathname" -require "set" - -INPUTS = [ - Pathname("inputs/test.txt"), - Pathname("inputs/puzzle.txt"), -].freeze -VOWELS = %[a e i o u].freeze - -def vowel_count(input) - input.each_char.sum do |char| - VOWELS.include?(char) ? 1 : 0 - end -end - -def twin_letters(input) - input.each_char.each_cons(2).sum do |(char, next_char)| - char == next_char ? 1 : 0 - end -end - -def letter_pairs_count(input) - characters = input - .each_char - .each_cons(4) - .reject { |(a, b, c, d)| (a == b && b == c || b == c && c == d ) && a != d } - - last_index = characters.size - pairs = characters - .flat_map - .with_index(1) { |(a, b, c, d), i| i == last_index ? [a+b, b+c, c+d] : [a+b] } - - pairs.tally.values.max || 0 -end - -def surrounded_letter_count(input) - input - .each_char - .each_cons(3) - .count { |(a, _, b)| a == b } -end - -def is_nice?(input) - return false if input.match?(/ab|cd|pq|xy/) - return false unless vowel_count(input) >= 3 - return false unless twin_letters(input) >= 1 - - true -end - -def is_really_nice?(input) - return false if letter_pairs_count(input) < 2 - return false if surrounded_letter_count(input).zero? - - true -end - -def count_nice(file) - file.each_line.sum do |line| - line = line.chomp # chomp: true keyword argument emits warnings - next 0 if line.empty? - yield(line) ? 1 : 0 - end -end - -def solve_part_1(file) - nice_lines = count_nice(file) { |l| is_nice?(l) } - puts "\tThere are #{nice_lines} nice lines" -end - -def solve_part_2(file) - nice_lines = count_nice(file) { |l| is_really_nice?(l) } - puts "\tThere are #{nice_lines} really nice lines" -end - -def main(files) - files.each do |file| - puts "File: #{file}" - solve_part_1(file) - solve_part_2(file) - end -end - -main(INPUTS) diff --git a/2015/day-05/part_one.rb b/2015/day-05/part_one.rb new file mode 100755 index 0000000..6fd3aa2 --- /dev/null +++ b/2015/day-05/part_one.rb @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby + +VOWELS = %[a e i o u].freeze + +def vowel_count(input) + input.each_char.sum do |char| + VOWELS.include?(char) ? 1 : 0 + end +end + +def twin_letters(input) + input.each_char.each_cons(2).sum do |(char, next_char)| + char == next_char ? 1 : 0 + end +end + +def is_nice?(input) + return false if input.empty? + return false if input.match?(/ab|cd|pq|xy/) + return false unless vowel_count(input) >= 3 + return false unless twin_letters(input) >= 1 + + true +end + +result = File.readlines(ARGV.first, chomp: true).sum do |line| + is_nice?(line) ? 1 : 0 +end + +puts result diff --git a/2015/day-05/part_two.rb b/2015/day-05/part_two.rb new file mode 100755 index 0000000..ceb042e --- /dev/null +++ b/2015/day-05/part_two.rb @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby + +def letter_pairs_count(input) + characters = input + .each_char + .each_cons(4) + .reject { |(a, b, c, d)| (a == b && b == c || b == c && c == d ) && a != d } + + last_index = characters.size + pairs = characters + .flat_map + .with_index(1) { |(a, b, c, d), i| i == last_index ? [a+b, b+c, c+d] : [a+b] } + + pairs.tally.values.max || 0 +end + +def surrounded_letter_count(input) + input + .each_char + .each_cons(3) + .count { |(a, _, b)| a == b } +end + +def is_really_nice?(input) + return false if input.empty? + return false if letter_pairs_count(input) < 2 + return false if surrounded_letter_count(input).zero? + + true +end + +result = File.readlines(ARGV.first, chomp: true).sum do |line| + is_really_nice?(line) ? 1 : 0 +end + +puts result diff --git a/2015/day-06/.ruby-version b/2015/day-06/.ruby-version deleted file mode 100644 index 4a36342..0000000 --- a/2015/day-06/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -3.0.0 diff --git a/2015/day-06/common.rb b/2015/day-06/common.rb new file mode 100644 index 0000000..7d84e94 --- /dev/null +++ b/2015/day-06/common.rb @@ -0,0 +1,33 @@ +class Grid + def initialize + @area = Array.new(1000) { Array.new(1000) { 0 } } + @commands = { + turn_on: ->(area) { 1 }, + toggle: ->(area) { area ^ 0x1 }, + turn_off: -> (area) { 0 } + } + end + + def set_command(name, callback) = @commands[name.to_sym] = callback + + def apply(cmd, coords) + coords => [[x, y], [w, h]] + (y..h).each do |i| + (x..w).each do |j| + @area[i][j] = @commands[cmd.to_sym].(@area[i][j]) + end + end + end + + def lights_on = @area.sum { |r| r.count { |x| x != 0 }} + def brightness = @area.sum { |r| r.sum } +end + +def parse_instruction(input) + left, right = input.split("through") + cmd, _, start_coords = left.strip.rpartition(" ").map(&:strip) + start_coords = start_coords.split(",").map(&:to_i) + end_coords = right.strip.split(",").map(&:to_i) + + [cmd.tr(" ", "_"), [start_coords, end_coords]] +end diff --git a/2015/day-06/inputs/test.txt b/2015/day-06/inputs/sample.txt similarity index 100% rename from 2015/day-06/inputs/test.txt rename to 2015/day-06/inputs/sample.txt diff --git a/2015/day-06/main.rb b/2015/day-06/main.rb deleted file mode 100755 index 8d08cd2..0000000 --- a/2015/day-06/main.rb +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env ruby - -require "pathname" - -INPUTS = [ - Pathname("inputs/test.txt"), - Pathname("inputs/puzzle.txt"), -].freeze - -class Grid - def initialize = @area = Array.new(1000) { Array.new(1000) { 0 } } - - def apply(cmd, coords) - coords => [[x, y], [w, h]] - (y..h).each do |i| - (x..w).each do |j| - @area[i][j] = send(cmd, @area[i][j]) - end - end - end - - def lights_on = @area.sum { |r| r.count { |x| x != 0 }} - def brightness = @area.sum { |r| r.sum } - - private - - def turn_on(area) = 1 - def toggle(area) = area ^ 0x1 - def turn_off(area) = 0 - - def turn_on2(area) = area + 1 - def turn_off2(area) = [area - 1, 0].max() - def toggle2(area) = area + 2 -end - -def parse_instruction(input) - input = input.chomp - left, right = input.split("through") - cmd, _, start_coords = left.strip.rpartition(" ").map(&:strip) - start_coords = start_coords.split(",").map(&:to_i) - end_coords = right.strip.split(",").map(&:to_i) - - [cmd.tr(" ", "_"), [start_coords, end_coords]] -end - -def solve_part_1(file) - grid = Grid.new() - - file.each_line do |line| - grid.apply(*parse_instruction(line)) - end - - puts "\tLights on: #{grid.lights_on}" -end - -def solve_part_2(file) - grid = Grid.new() - - file.each_line do |line| - parse_instruction(line) => [cmd, coords] - grid.apply("#{cmd}2", coords) - end - - puts "\tBrightness: #{grid.brightness}" -end - -def main(files) - files.each do |file| - puts "File: #{file}" - solve_part_1(file) - solve_part_2(file) - end -end - -main(INPUTS) diff --git a/2015/day-06/part_one.rb b/2015/day-06/part_one.rb new file mode 100755 index 0000000..1854862 --- /dev/null +++ b/2015/day-06/part_one.rb @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby + +require_relative "common" + +grid = Grid.new() + +File.readlines(ARGV.first, chomp: true).each do |line| + grid.apply(*parse_instruction(line)) +end + +puts grid.lights_on diff --git a/2015/day-06/part_two.rb b/2015/day-06/part_two.rb new file mode 100755 index 0000000..06277cb --- /dev/null +++ b/2015/day-06/part_two.rb @@ -0,0 +1,15 @@ +#!/usr/bin/env ruby + +require_relative "common" + +grid = Grid.new() + +grid.set_command(:turn_on, ->(area) { area + 1 }) +grid.set_command(:turn_off, ->(area) { [area - 1, 0].max() }) +grid.set_command(:toggle, ->(area) { area + 2 }) + +File.readlines(ARGV.first, chomp: true).each do |line| + grid.apply(*parse_instruction(line)) +end + +puts grid.brightness diff --git a/2015/day-07/.gitignore b/2015/day-07/.gitignore deleted file mode 100644 index ba2906d..0000000 --- a/2015/day-07/.gitignore +++ /dev/null @@ -1 +0,0 @@ -main diff --git a/2015/day-07/src/circuit.rs b/2015/day-07/common.rs similarity index 75% rename from 2015/day-07/src/circuit.rs rename to 2015/day-07/common.rs index 835bfd2..cd606d2 100644 --- a/2015/day-07/src/circuit.rs +++ b/2015/day-07/common.rs @@ -40,8 +40,8 @@ pub struct Circuit { } impl Circuit { - pub fn add_instruction(&mut self, instruction: &str) { - let tokens = tokenize(instruction); + pub fn add_instruction(&mut self, input: &str) { + let tokens = tokenize(input); self.instructions.push_front(tokens); } @@ -52,8 +52,8 @@ impl Circuit { } fn execute_one(&mut self, tokens: Vec) { - use self::Token::*; use self::Op::*; + use self::Token::*; self.instruction_len = tokens.len(); @@ -62,7 +62,7 @@ impl Circuit { Ident(_) | Value(_) => { self.stack.push(token.clone()); continue; - }, + } Op(Assign) => self.op_assign(), Op(Not) => self.op_not(), Op(And) => self.binop(|a, b| a & b), @@ -75,26 +75,29 @@ impl Circuit { Err(Error::VariableNotFound) => { self.instructions.push_back(tokens); return; - }, + } Err(e) => panic!("{:?}", e), - _ => () + _ => (), } } } + #[allow(dead_code)] pub fn variable_override(&mut self, name: N, value: Value) - where N: Into + where + N: Into, { self.overrides.insert(name.into(), value); } #[allow(dead_code)] - pub fn variables(&self) -> &HashMap { + pub fn variables(&self) -> &HashMap { &self.variables } pub fn variable(&self, name: N) -> Option<&Value> - where N: AsRef + where + N: AsRef, { self.variables.get(name.as_ref()) } @@ -107,16 +110,26 @@ impl Circuit { let rhs = self.stack.pop().unwrap(); if let Ident(id) = lhs { - let replace = if self.instruction_len == 3 { self.overrides.get(&id) } else { None }; + let replace = if self.instruction_len == 3 { + self.overrides.get(&id) + } else { + None + }; match (rhs, replace) { - (Value(_), Some(val)) => { self.variables.insert(id, *val); }, - (Value(val), None) => { self.variables.insert(id, val); }, + (Value(_), Some(val)) => { + self.variables.insert(id, *val); + } + (Value(val), None) => { + self.variables.insert(id, val); + } (Ident(id2), _) => { - let tmp = *self.variables.get(&id2) + let tmp = *self + .variables + .get(&id2) .ok_or_else(|| Error::VariableNotFound)?; self.variables.insert(id, tmp); - }, - _ => return Err(Error::InvalidStack) + } + _ => return Err(Error::InvalidStack), } } @@ -132,20 +145,23 @@ impl Circuit { match token { Value(val) => { self.stack.push(Value(!val)); - }, + } Ident(id) => { - let val = self.variables.get(&id) + let val = self + .variables + .get(&id) .ok_or_else(|| Error::VariableNotFound)?; self.stack.push(Value(!val)); - }, - _ => return Err(Error::InvalidStack) + } + _ => return Err(Error::InvalidStack), } Ok(()) } fn binop(&mut self, fun: F) -> Result<()> - where F: Fn(Value, Value) -> Value + where + F: Fn(Value, Value) -> Value, { use self::Token::*; @@ -155,23 +171,31 @@ impl Circuit { match (lhs, rhs) { (Ident(id1), Value(val)) => { - let a = *self.variables.get(&id1) + let a = *self + .variables + .get(&id1) .ok_or_else(|| Error::VariableNotFound)?; self.stack.push(Value(fun(a, val))); - }, + } (Ident(id1), Ident(id2)) => { - let a = *self.variables.get(&id1) + let a = *self + .variables + .get(&id1) .ok_or_else(|| Error::VariableNotFound)?; - let b = *self.variables.get(&id2) + let b = *self + .variables + .get(&id2) .ok_or_else(|| Error::VariableNotFound)?; self.stack.push(Value(fun(a, b))); - }, + } (Value(val), Ident(id2)) => { - let b = *self.variables.get(&id2) + let b = *self + .variables + .get(&id2) .ok_or_else(|| Error::VariableNotFound)?; self.stack.push(Value(fun(val, b))); - }, - _ => return Err(Error::InvalidStack) + } + _ => return Err(Error::InvalidStack), } Ok(()) @@ -193,13 +217,13 @@ fn tokenize(input: &str) -> Vec { otherwise => match otherwise.parse::() { Ok(val) => Token::Value(val), Err(_) => Token::Ident(word.to_string()), - } + }, }; match token { Token::Op(_) => { operator = Some(token); - }, + } _ => { tokens.push(token); if let Some(op) = operator.take() { diff --git a/2015/day-07/inputs/test.txt b/2015/day-07/inputs/sample.txt similarity index 100% rename from 2015/day-07/inputs/test.txt rename to 2015/day-07/inputs/sample.txt diff --git a/2015/day-07/part_one.rs b/2015/day-07/part_one.rs new file mode 100644 index 0000000..a8b1c20 --- /dev/null +++ b/2015/day-07/part_one.rs @@ -0,0 +1,23 @@ +mod common; + +use std::env; +use std::fs::File; +use std::io::{self, BufRead}; + +use common::Circuit; + +fn main() -> io::Result<()> { + let path = env::args().nth(1).unwrap(); + let file = io::BufReader::new(File::open(path)?); + + let mut circuit = Circuit::default(); + for line in file.lines() { + circuit.add_instruction(&line?); + } + circuit.execute(); + let output = circuit.variable("a").unwrap(); + + println!("{}", output); + + Ok(()) +} diff --git a/2015/day-07/part_two.rs b/2015/day-07/part_two.rs new file mode 100644 index 0000000..dc209b2 --- /dev/null +++ b/2015/day-07/part_two.rs @@ -0,0 +1,32 @@ +mod common; + +use std::env; +use std::fs::File; +use std::io::{self, BufRead}; + +use common::Circuit; + +fn main() -> io::Result<()> { + let path = env::args().nth(1).unwrap(); + let file = io::BufReader::new(File::open(path)?); + let instructions = file.lines().map(|l| l.unwrap()).collect::>(); + + let mut circuit = Circuit::default(); + for tokens in &instructions { + circuit.add_instruction(tokens); + } + circuit.execute(); + let output = circuit.variable("a").copied().unwrap(); + + circuit = Circuit::default(); + for tokens in &instructions { + circuit.add_instruction(tokens); + } + circuit.variable_override("b", output); + circuit.execute(); + let output = circuit.variable("a").unwrap(); + + println!("{}", output); + + Ok(()) +} diff --git a/2015/day-07/src/main.rs b/2015/day-07/src/main.rs deleted file mode 100644 index 479973b..0000000 --- a/2015/day-07/src/main.rs +++ /dev/null @@ -1,54 +0,0 @@ -mod circuit; - -use std::{ - io::{self, BufRead}, - fs::File, -}; -use circuit::Circuit; - -const FILE_PATHS: &[&str] = &[ - "inputs/test.txt", - "inputs/puzzle.txt", -]; - -fn solve_part_1(file_path: &str) -> io::Result{ - let mut circuit = Circuit::default(); - - let file = io::BufReader::new(File::open(file_path)?); - for line in file.lines() { - circuit.add_instruction(&line?); - } - circuit.execute(); - let a = circuit.variable("a").copied().unwrap_or_default(); - println!("\ta: {:?}", a); - - Ok(a) -} - -fn solve_part_2(file_path: &str, a: u16) -> io::Result<()> { - let mut circuit = Circuit::default(); - - let file = io::BufReader::new(File::open(file_path)?); - for line in file.lines() { - circuit.add_instruction(&line?); - } - circuit.variable_override("b", a); - circuit.execute(); - - if let Some(a) = circuit.variable("a") { - println!("\ta: {:?}", a); - } - - Ok(()) -} - -fn main() -> io::Result<()> { - for file_path in FILE_PATHS { - println!("File: {}", file_path); - - let a = solve_part_1(file_path)?; - solve_part_2(file_path, a)?; - } - - Ok(()) -} diff --git a/2015/day-08/.ruby-version b/2015/day-08/.ruby-version deleted file mode 100644 index 4a36342..0000000 --- a/2015/day-08/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -3.0.0 diff --git a/2015/day-08/inputs/test.txt b/2015/day-08/inputs/sample.txt similarity index 100% rename from 2015/day-08/inputs/test.txt rename to 2015/day-08/inputs/sample.txt diff --git a/2015/day-08/main.rb b/2015/day-08/main.rb deleted file mode 100755 index 8662102..0000000 --- a/2015/day-08/main.rb +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -require "pathname" - -INPUTS = [ - Pathname("inputs/test.txt"), - Pathname("inputs/puzzle.txt"), -].freeze - -def solve_part_1(file) - size = file.each_line.sum do |line| - line = line.chomp - line.size - line.undump.size - end - - puts "\tSize 1: #{size}" -end - -def solve_part_2(file) - size = file.each_line.sum do |line| - line = line.chomp - line.dump.size - line.size - end - - puts "\tSize 2: #{size}" -end - -def main(files) - files.each do |file| - puts "File: #{file}" - - solve_part_1(file) - solve_part_2(file) - end -end - -main(INPUTS) diff --git a/2015/day-08/part_one.rb b/2015/day-08/part_one.rb new file mode 100755 index 0000000..2bd0ae0 --- /dev/null +++ b/2015/day-08/part_one.rb @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +size = File.readlines(ARGV.first, chomp: true).sum do |line| + line.size - line.undump.size +end + +puts size diff --git a/2015/day-08/part_two.rb b/2015/day-08/part_two.rb new file mode 100755 index 0000000..018a97f --- /dev/null +++ b/2015/day-08/part_two.rb @@ -0,0 +1,7 @@ +#!/usr/bin/env ruby + +size = File.readlines(ARGV.first, chomp: true).sum do |line| + line.dump.size - line.size +end + +puts size diff --git a/2015/day-09/.gitignore b/2015/day-09/.gitignore index fba1994..28e9eeb 100644 --- a/2015/day-09/.gitignore +++ b/2015/day-09/.gitignore @@ -1,3 +1,3 @@ *.dot *.png -main +dot diff --git a/2015/day-09/common.rs b/2015/day-09/common.rs new file mode 100644 index 0000000..e59d13f --- /dev/null +++ b/2015/day-09/common.rs @@ -0,0 +1,39 @@ +use std::collections::HashSet; +use std::error::Error as StdError; +use std::fs::File; +use std::io::{self, BufRead, BufReader}; +use std::path::Path; +use std::result::Result as StdResult; + +use crate::graph; + +pub type Location = String; +pub type Distance = u64; +pub type Graph = graph::Graph; +pub type Node = graph::Node; +pub type NodeSet = HashSet; + +pub type Error = Box; +pub type Result = StdResult; + +pub fn parse_file

(path: P) -> io::Result +where + P: AsRef, +{ + let file = BufReader::new(File::open(path)?); + let mut directions = Graph::default(); + + for line in file.lines() { + let line = line?; + let words = line.split(' ').collect::>(); + let location = ( + words[0].to_string(), + words[2].to_string(), + words[4].parse::().unwrap(), + ); + + directions.add_edge(&location); + } + + Ok(directions) +} diff --git a/2015/day-09/dot.rs b/2015/day-09/dot.rs new file mode 100644 index 0000000..3660176 --- /dev/null +++ b/2015/day-09/dot.rs @@ -0,0 +1,53 @@ +mod common; +mod graph; + +use std::env; +use std::fs::OpenOptions; +use std::io::Write; +use std::path::PathBuf; + +use common::{Graph, Result}; + +fn generate_dot(graph: &Graph, name: &str) -> Result { + use std::fmt::Write; + + let mut buf = String::new(); + + writeln!(buf, "strict graph {} {{", name)?; + for node in &graph.nodes { + for (outgoing, weight) in &node.borrow().outgoing { + writeln!( + buf, + "{} -- {} [ label = \"{}\" ];", + node.borrow().data, + outgoing.borrow().data, + weight + )?; + } + } + writeln!(buf, "}}")?; + + Ok(buf) +} + +fn main() -> Result<()> { + let path = PathBuf::from(env::args().nth(1).unwrap()); + let graph = common::parse_file(&path)?; + + let mut dot_path = path.clone(); + dot_path.set_extension("dot"); + let graph_name = dot_path.file_stem().unwrap().to_str().unwrap(); + + let dot = generate_dot(&graph, &graph_name)?; + + let out_path = dot_path.file_name().unwrap(); + let mut file = OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(out_path)?; + + write!(file, "{}", dot)?; + + Ok(()) +} diff --git a/2015/day-09/src/graph.rs b/2015/day-09/graph.rs similarity index 100% rename from 2015/day-09/src/graph.rs rename to 2015/day-09/graph.rs diff --git a/2015/day-09/inputs/test.txt b/2015/day-09/inputs/sample.txt similarity index 100% rename from 2015/day-09/inputs/test.txt rename to 2015/day-09/inputs/sample.txt diff --git a/2015/day-09/src/part1.rs b/2015/day-09/part_one.rs similarity index 80% rename from 2015/day-09/src/part1.rs rename to 2015/day-09/part_one.rs index f6ce59d..7d1330e 100644 --- a/2015/day-09/src/part1.rs +++ b/2015/day-09/part_one.rs @@ -1,7 +1,11 @@ -use std::collections::HashSet; -use crate::{Distance, Graph, Node}; +mod common; +pub mod graph; +mod utils; -type NodeSet = HashSet; +use std::cmp::min; +use std::env; + +use crate::common::{Distance, Node, NodeSet, Result}; // Only works with complete graphs (where each node leads to each other node) fn visit_all_shortest(start_node: &Node) -> Vec<(Node, Distance)> { @@ -45,9 +49,9 @@ fn visit_all_shortest(start_node: &Node) -> Vec<(Node, Distance)> { path } -/// Find shortest path that connects two points and visits all locations. -pub fn solve(directions: &Graph) -> Distance { - use std::cmp::min; +fn main() -> Result<()> { + let path = env::args().nth(1).unwrap(); + let directions = common::parse_file(path)?; let mut shortest_distance = None; @@ -58,12 +62,14 @@ pub fn solve(directions: &Graph) -> Distance { continue; } - let distance = path.iter().map(|p| p.1).sum(); + let distance: Distance = path.iter().map(|p| p.1).sum(); shortest_distance = match shortest_distance { None => Some(distance), Some(d) => Some(min(distance, d)), }; } - shortest_distance.unwrap_or_default() + println!("{}", shortest_distance.unwrap_or_default()); + + Ok(()) } diff --git a/2015/day-09/src/part2.rs b/2015/day-09/part_two.rs similarity index 53% rename from 2015/day-09/src/part2.rs rename to 2015/day-09/part_two.rs index d5dbc1a..e3f11a2 100644 --- a/2015/day-09/src/part2.rs +++ b/2015/day-09/part_two.rs @@ -1,7 +1,11 @@ -use std::collections::HashSet; -use crate::{Distance, Graph, Node}; +mod common; +pub mod graph; +mod utils; -type NodeSet = HashSet; +use std::cmp::max; +use std::env; + +use crate::common::{Distance, Node, NodeSet, Result}; struct Memo<'a> { max_dist: &'a mut Distance, @@ -18,11 +22,14 @@ fn depth_first_search(node: &Node, memo: Memo<'_>) { if !memo.visited.contains(&out_node) { distance = memo.prev_dist + out_weight; - depth_first_search(&out_node, Memo { - max_dist: &mut *memo.max_dist, - prev_dist: distance, - visited: &mut *memo.visited, - }); + depth_first_search( + &out_node, + Memo { + max_dist: &mut *memo.max_dist, + prev_dist: distance, + visited: &mut *memo.visited, + }, + ); } if *memo.max_dist < distance { @@ -38,17 +45,22 @@ fn visit_all_longest(start_node: &Node) -> Distance { let mut distance = 0; - depth_first_search(&start_node, Memo { - max_dist: &mut distance, - prev_dist: 0, - visited: &mut visited, - }); + depth_first_search( + &start_node, + Memo { + max_dist: &mut distance, + prev_dist: 0, + visited: &mut visited, + }, + ); distance } -pub fn solve(directions: &Graph) -> Distance { - use std::cmp::max; +fn main() -> Result<()> { + let path = env::args().nth(1).unwrap(); + + let directions = common::parse_file(path)?; let mut longest_distance = 0; @@ -57,5 +69,7 @@ pub fn solve(directions: &Graph) -> Distance { longest_distance = max(distance, longest_distance); } - longest_distance + println!("{}", longest_distance); + + Ok(()) } diff --git a/2015/day-09/src/main.rs b/2015/day-09/src/main.rs deleted file mode 100644 index e002e89..0000000 --- a/2015/day-09/src/main.rs +++ /dev/null @@ -1,34 +0,0 @@ -mod graph; -mod utils; -mod part1; -mod part2; - -type Graph = graph::Graph; -type Node = graph::Node; - -type Location = String; -type Distance = u64; - -fn main() -> Result<(), Box> { - use std::env; - - let file_paths = env::args().skip(1).collect::>(); - - for file_path in &file_paths { - let locations = utils::parse_file(file_path)?; - - let mut directions = Graph::default(); - - for location in &locations { - directions.add_edge(location); - } - - utils::write_dot(&directions, &file_path)?; - - println!("{} / solution 1 = {:?}", file_path, part1::solve(&directions)); - println!("{} / solution 2 = {:?}", file_path, part2::solve(&directions)); - } - - Ok(()) -} - diff --git a/2015/day-09/src/utils.rs b/2015/day-09/src/utils.rs deleted file mode 100644 index ecca925..0000000 --- a/2015/day-09/src/utils.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::{ - io::{self, BufRead}, - path::{Path, PathBuf}, -}; -use crate::{Location, Distance, Graph}; - -pub fn generate_dot(graph: &Graph, name: &str) -> Result> { - use std::fmt::Write; - - let mut buf = String::new(); - - writeln!(buf, "strict graph {} {{", name)?; - for node in &graph.nodes { - for (outgoing, weight) in &node.borrow().outgoing { - writeln!(buf, "{} -- {} [ label = \"{}\" ];", - node.borrow().data, - outgoing.borrow().data, - weight - )?; - } - } - writeln!(buf, "}}")?; - - Ok(buf) -} - -pub fn write_dot

(graph: &Graph, path: P) -> Result<(), Box> - where P: Into -{ - use std::{fs::OpenOptions, io::Write}; - - let mut dot_path = path.into(); - dot_path.set_extension("dot"); - let graph_name = dot_path.file_stem().unwrap().to_str().unwrap(); - let dot = generate_dot(&graph, &graph_name)?; - let out_path = dot_path.file_name().unwrap(); - let mut file = OpenOptions::new().write(true).truncate(true).create(true).open(out_path)?; - - write!(file, "{}", dot)?; - Ok(()) -} - -pub fn parse_file

(path: P) -> io::Result> - where P: AsRef -{ - use std::{fs::File, io::BufReader}; - - let file = BufReader::new(File::open(path)?); - let dests = file.lines() - .map(|l| { - let line = l.unwrap(); - let words = line.split(' ').collect::>(); - (words[0].to_string(), words[2].to_string(), words[4].parse::().unwrap()) - }) - .collect(); - - Ok(dests) -} diff --git a/2015/day-10/.ruby-version b/2015/day-10/.ruby-version deleted file mode 100644 index 4a36342..0000000 --- a/2015/day-10/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -3.0.0 diff --git a/2015/day-10/common.rb b/2015/day-10/common.rb new file mode 100644 index 0000000..a4913f6 --- /dev/null +++ b/2015/day-10/common.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require "stringio" + +def look_and_say(input) + counter = 1 + + output = input.each_char.map(&:to_i).chain([nil]).each_cons(2).reduce(StringIO.new) do |acc, (val1, val2)| + if val1 == val2 + counter += 1 + else + acc.write counter + acc.write val1 + counter = 1 + end + + acc + end + + output.rewind + output +end diff --git a/2015/day-10/inputs/test.txt b/2015/day-10/inputs/sample.txt similarity index 100% rename from 2015/day-10/inputs/test.txt rename to 2015/day-10/inputs/sample.txt diff --git a/2015/day-10/main.rb b/2015/day-10/main.rb deleted file mode 100755 index 2ea1b2a..0000000 --- a/2015/day-10/main.rb +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true - -require "pathname" -require "stringio" - -def look_and_say(input) - counter = 1 - - output = input.each_char.map(&:to_i).chain([nil]).each_cons(2).reduce(StringIO.new) do |acc, (val1, val2)| - if val1 == val2 - counter += 1 - else - acc.write counter - acc.write val1 - counter = 1 - end - - acc - end - - output.rewind - output -end - -def solve_part1(content) - puts 40.times.reduce(StringIO.new(content)) { |acc| look_and_say(acc) }.size -end - -def solve_part2(content) - puts 50.times.reduce(StringIO.new(content)) { |acc, _| look_and_say(acc) }.size -end - -def main(files) - files.each do |file| - content = file.read.chomp - solve_part1(content) - solve_part2(content) - end -end - -main(ARGV.map { |x| Pathname(x) }) diff --git a/2015/day-10/part_one.rb b/2015/day-10/part_one.rb new file mode 100755 index 0000000..630a127 --- /dev/null +++ b/2015/day-10/part_one.rb @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "stringio" +require_relative "common" + +content = File.read(ARGV.first).chomp +puts 40.times.reduce(StringIO.new(content)) { |acc| look_and_say(acc) }.size diff --git a/2015/day-10/part_two.rb b/2015/day-10/part_two.rb new file mode 100755 index 0000000..43d5a7e --- /dev/null +++ b/2015/day-10/part_two.rb @@ -0,0 +1,8 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "stringio" +require_relative "common" + +content = File.read(ARGV.first).chomp +puts 50.times.reduce(StringIO.new(content)) { |acc| look_and_say(acc) }.size