From 26fd8fbbfe9fc4d6977f5093c6b3d6048c5ca867 Mon Sep 17 00:00:00 2001 From: red Date: Thu, 22 Feb 2024 18:53:52 +0100 Subject: [PATCH] Year 2016: Day 05 --- README.md | 2 +- spec/year_2016/day_05_spec.rb | 29 +++++++++++++++++++++ year_2016.md | 15 +++++++++++ year_2016/day_05.rb | 49 +++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 spec/year_2016/day_05_spec.rb create mode 100644 year_2016/day_05.rb diff --git a/README.md b/README.md index b9f17bc..7d7cb26 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ I'm also adding notes that may be useful if you're learning Ruby. Notes for solving: * [2015, complete](year_2015.md) -* [2016, up to day 04](year_2016.md) +* [2016, up to day 05](year_2016.md) * [2023, up to day 03](year_2023.md) # How to use diff --git a/spec/year_2016/day_05_spec.rb b/spec/year_2016/day_05_spec.rb new file mode 100644 index 0000000..588d30c --- /dev/null +++ b/spec/year_2016/day_05_spec.rb @@ -0,0 +1,29 @@ +require 'year_2016/day_05' + +describe Year2016::Day05 do + context 'when Part 1' do + it 'gives a final result' do + expect(described_class.new('abc', true).code).to eq('18f47a30') + end + end + + context 'when Part 2' do + it 'gives a final result' do + expect(described_class.new('abc').code).to eq('05ace8e3') + end + end + + context 'when Results' do + subject(:input_data) do + 'ojvtpuvg' + end + + it 'correctly answers part 1' do + expect(described_class.new(input_data, true).code).to eq('4543c154') + end + + it 'correctly answers part 2' do + expect(described_class.new(input_data).code).to eq('1050cbbd') + end + end +end diff --git a/year_2016.md b/year_2016.md index 9fee42a..8e60ae0 100644 --- a/year_2016.md +++ b/year_2016.md @@ -54,3 +54,18 @@ Year2016::Day04 ``` The second part of this exercise involves implementing a [Caesar cipher](https://en.wikipedia.org/wiki/Caesar_cipher), which is not a hard concept to grasp. It's a bit annoying to work through ASCII values of characters and modulo properly to get the right number. + +## Day 05: How About a Nice Game of Chess? + +``` +Year2016::Day05 + when Part 1 + gives a final result + when Part 2 + gives a final result + when Results + correctly answers part 1 + correctly answers part 2 +``` + +Not gonna lie, brute-forcing [MD5 hashes](https://en.wikipedia.org/wiki/MD5) is not something interesting. diff --git a/year_2016/day_05.rb b/year_2016/day_05.rb new file mode 100644 index 0000000..a9f9f38 --- /dev/null +++ b/year_2016/day_05.rb @@ -0,0 +1,49 @@ +require 'digest' + +class Year2016 + class Day05 + def initialize(input_data, input_part_one = false) + @version = input_part_one ? 1 : 2 + @input = input_data.chomp + end + + def md5 + @md5 ||= Digest::MD5.new + end + + def hash(str) + md5.reset + md5 << str + md5.hexdigest + end + + # rubocop:disable Metrics/AbcSize, Metrics/MethodLength + def build_code + @code = '_' * 8 + added = 0 + 0.upto(100**100) do |i| + break if added == 8 + + digest = hash("#{@input}#{i}") + next unless digest.start_with?('0' * 5) + + if @version == 1 + @code[added] = digest[5] + next added += 1 + end + + pos = digest[5].ord - 48 + next if pos.negative? || pos > 7 || @code[pos] != '_' + + code[pos] = digest[6] + added += 1 + end + @code + end + # rubocop:enable Metrics/AbcSize, Metrics/MethodLength + + def code + @code ||= build_code + end + end +end