Lots of Ruby for 2016
This commit is contained in:
parent
7bc2c01242
commit
886def1a71
42
ruby/2016/1/problem.rb
Normal file
42
ruby/2016/1/problem.rb
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
require "set"
|
||||||
|
|
||||||
|
input = STDIN.read.chomp
|
||||||
|
commands = input.split ", "
|
||||||
|
|
||||||
|
position = [0, 0] # Cartesian coordinates, +x is right, +y is up
|
||||||
|
direction = 0 # North I guess
|
||||||
|
|
||||||
|
visited_positions = Set.new([position.clone])
|
||||||
|
first_revisited_position = nil
|
||||||
|
|
||||||
|
commands.each do |command|
|
||||||
|
turn = command[0] == "L" ? 1 : -1
|
||||||
|
distance = command[1..].to_i
|
||||||
|
direction += turn
|
||||||
|
direction = direction % 4
|
||||||
|
|
||||||
|
distance.times do
|
||||||
|
case direction
|
||||||
|
when 0
|
||||||
|
position[1] += 1
|
||||||
|
when 1
|
||||||
|
position[0] += 1
|
||||||
|
when 2
|
||||||
|
position[1] -= 1
|
||||||
|
when 3
|
||||||
|
position[0] -= 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if !visited_positions.add?(position.clone)
|
||||||
|
if first_revisited_position.nil?
|
||||||
|
first_revisited_position = position.clone
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
part_1 = position.map(&:abs).sum
|
||||||
|
part_2 = first_revisited_position.map(&:abs).sum
|
||||||
|
|
||||||
|
puts "Part 1: #{part_1}"
|
||||||
|
puts "Part 2: #{part_2}"
|
56
ruby/2016/2/problem.rb
Normal file
56
ruby/2016/2/problem.rb
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
class DirectionString
|
||||||
|
attr_reader :string, :start_position
|
||||||
|
|
||||||
|
def initialize(string, start_position=[1, 1])
|
||||||
|
@string = string
|
||||||
|
@start_position = start_position
|
||||||
|
end
|
||||||
|
|
||||||
|
def final_position
|
||||||
|
return start_position if string.empty?
|
||||||
|
|
||||||
|
self.class.new(string[1..], next_position).final_position
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_position
|
||||||
|
case string[0]
|
||||||
|
when "D"
|
||||||
|
[start_position[0], start_position[1] + 1]
|
||||||
|
when "U"
|
||||||
|
[start_position[0], start_position[1] - 1]
|
||||||
|
when "L"
|
||||||
|
[start_position[0] - 1, start_position[1]]
|
||||||
|
when "R"
|
||||||
|
[start_position[0] + 1, start_position[1]]
|
||||||
|
end.map{ |pos| pos.clamp(0, 2) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def reduce(array, initial_value)
|
||||||
|
acc = initial_value
|
||||||
|
array.each do |value|
|
||||||
|
acc = yield(acc, value)
|
||||||
|
end
|
||||||
|
acc
|
||||||
|
end
|
||||||
|
|
||||||
|
input = STDIN.read.chomp
|
||||||
|
direction_strings = input.split
|
||||||
|
|
||||||
|
KEYPAD = [[ 1, 2, 3 ],
|
||||||
|
[ 4, 5, 6 ],
|
||||||
|
[ 7, 8, 9 ]]
|
||||||
|
|
||||||
|
def keypad_digit(position)
|
||||||
|
x, y = position
|
||||||
|
KEYPAD[y][x]
|
||||||
|
end
|
||||||
|
|
||||||
|
digits = []
|
||||||
|
direction_strings.inject([1, 1]) do |acc, x|
|
||||||
|
y = DirectionString.new(x, acc).final_position
|
||||||
|
digits << keypad_digit(y)
|
||||||
|
y
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Part 1: #{digits.join}"
|
48
ruby/2016/3/problem.rb
Normal file
48
ruby/2016/3/problem.rb
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
class PotentialTriangle
|
||||||
|
attr_reader :sides
|
||||||
|
|
||||||
|
def initialize(line)
|
||||||
|
@sides = line.split.map(&:to_i)
|
||||||
|
end
|
||||||
|
|
||||||
|
%w[a b c].each_with_index do |side, index|
|
||||||
|
define_method("side_#{side}") do
|
||||||
|
sides[index]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid?
|
||||||
|
side_a_valid? && side_b_valid? && side_c_valid?
|
||||||
|
end
|
||||||
|
|
||||||
|
def side_a_valid?
|
||||||
|
side_a < side_b + side_c
|
||||||
|
end
|
||||||
|
|
||||||
|
def side_b_valid?
|
||||||
|
side_b < side_a + side_c
|
||||||
|
end
|
||||||
|
|
||||||
|
def side_c_valid?
|
||||||
|
side_c < side_b + side_a
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
input = STDIN.read.chomp
|
||||||
|
potential_triangle_lines = input.split("\n")
|
||||||
|
potential_triangles = potential_triangle_lines.map { |line| PotentialTriangle.new line }
|
||||||
|
valid_triangles = potential_triangles.count(&:valid?)
|
||||||
|
|
||||||
|
puts "Part 1: #{valid_triangles}"
|
||||||
|
|
||||||
|
grouped_triangle_lines = potential_triangle_lines.join(" ").split.each_with_index.each_with_object([[], [], []]) do |item_index, groups|
|
||||||
|
item, index = item_index
|
||||||
|
groups[index % 3] << item
|
||||||
|
groups
|
||||||
|
end
|
||||||
|
|
||||||
|
sideways_triangle_lines = grouped_triangle_lines.flatten.each_slice(3).to_a.map { |tri| tri.join " " }
|
||||||
|
sideways_triangles = sideways_triangle_lines.map { |line| PotentialTriangle.new line }
|
||||||
|
valid_sideways_triangles = sideways_triangles.count(&:valid?)
|
||||||
|
|
||||||
|
puts "Part 2: #{valid_sideways_triangles}"
|
36
ruby/2016/4/problem.rb
Normal file
36
ruby/2016/4/problem.rb
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
class Room
|
||||||
|
attr_reader :name, :sector_id, :checksum
|
||||||
|
|
||||||
|
def initialize(string)
|
||||||
|
@name = string.split("-")[..-2].join("-")
|
||||||
|
@sector_id = string.split("-")[-1].split("[")[0].to_i
|
||||||
|
@checksum = string.split("[")[1][..-2]
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculated_checksum
|
||||||
|
letter_counts.sort_by { |k, v| [-v, -k] }.map(&:first)[0...5].join
|
||||||
|
end
|
||||||
|
|
||||||
|
def real?
|
||||||
|
calculated_checksum == checksum
|
||||||
|
end
|
||||||
|
|
||||||
|
def letter_counts
|
||||||
|
(name.chars - ["-"]).group_by(&:itself).to_h { |k, v| [k, v.count] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def rotated_name
|
||||||
|
1.upto(sector_id % 26).reduce(name) { |n, _| n.codepoints.map{ |c| ((((c + 1) - 97) % 26) + 97).chr }.join("") }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
input = STDIN.read.chomp
|
||||||
|
room_lines = input.split("\n")
|
||||||
|
rooms = room_lines.map { |line| Room.new line }
|
||||||
|
part_1 = rooms.select(&:real?).sum(&:sector_id)
|
||||||
|
|
||||||
|
puts "Part 1: #{part_1}"
|
||||||
|
|
||||||
|
part_2 = rooms.find { |room| room.rotated_name.include? "northpole" }.sector_id
|
||||||
|
|
||||||
|
puts "Part 2: #{part_2}"
|
39
ruby/2016/5/problem.rb
Normal file
39
ruby/2016/5/problem.rb
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
require "digest"
|
||||||
|
|
||||||
|
input = STDIN.read.chomp
|
||||||
|
salt = 0
|
||||||
|
password = []
|
||||||
|
|
||||||
|
loop do
|
||||||
|
digest = Digest::MD5.hexdigest("#{input}#{salt}")
|
||||||
|
if digest[0...5] == "00000"
|
||||||
|
password << digest[5]
|
||||||
|
puts password.join("")
|
||||||
|
break if password.length >= 8
|
||||||
|
end
|
||||||
|
salt += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
part_1 = password.join("")
|
||||||
|
|
||||||
|
puts "Part 1: #{part_1}"
|
||||||
|
|
||||||
|
salt = 0
|
||||||
|
to_solve = 8
|
||||||
|
password = "--------"
|
||||||
|
loop do
|
||||||
|
digest = Digest::MD5.hexdigest("#{input}#{salt}")
|
||||||
|
if digest[0...5] == "00000"
|
||||||
|
if digest[5].to_i.to_s == digest[5] && digest[5].to_i < 8 && password[digest[5].to_i] == "-"
|
||||||
|
password[digest[5].to_i] = digest[6]
|
||||||
|
to_solve -= 1
|
||||||
|
puts password
|
||||||
|
end
|
||||||
|
break if to_solve <= 0
|
||||||
|
end
|
||||||
|
salt += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
part_2 = password
|
||||||
|
|
||||||
|
puts "Part 2: #{part_2}"
|
23
ruby/2016/6/problem.rb
Normal file
23
ruby/2016/6/problem.rb
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
input = STDIN.read.chomp
|
||||||
|
columns = input
|
||||||
|
.split("\n")
|
||||||
|
.map{ |line| line.split("") }
|
||||||
|
.transpose
|
||||||
|
|
||||||
|
part_1 = columns.map do |column|
|
||||||
|
column
|
||||||
|
.group_by(&:itself)
|
||||||
|
.sort_by { |k, v| v.count }
|
||||||
|
.last[0]
|
||||||
|
end.join
|
||||||
|
|
||||||
|
puts "Part 1: #{part_1}"
|
||||||
|
|
||||||
|
part_2 = columns.map do |column|
|
||||||
|
column
|
||||||
|
.group_by(&:itself)
|
||||||
|
.sort_by { |k, v| v.count }
|
||||||
|
.first[0]
|
||||||
|
end.join
|
||||||
|
|
||||||
|
puts "Part 2: #{part_2}"
|
71
ruby/2016/7/problem.rb
Normal file
71
ruby/2016/7/problem.rb
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
class String
|
||||||
|
def to_ip
|
||||||
|
IP.new self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class IP < String
|
||||||
|
def initialize(s)
|
||||||
|
super s
|
||||||
|
end
|
||||||
|
|
||||||
|
def supports_tls?
|
||||||
|
!has_abba_in_hypernet_sequences? && has_abba?
|
||||||
|
end
|
||||||
|
|
||||||
|
def abba?
|
||||||
|
self[0] == self[3] && self[2] == self[1] && self[0] != self[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_abba?
|
||||||
|
chars.each_cons(4).map(&:join).map(&:to_ip).any?(&:abba?)
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_abba_in_hypernet_sequences?
|
||||||
|
hypernet_sequences.any? &:has_abba?
|
||||||
|
end
|
||||||
|
|
||||||
|
def hypernet_sequences
|
||||||
|
supernet_and_hypernet_sequences.each_with_index.select do |seq, i|
|
||||||
|
i % 2 == 1
|
||||||
|
end.map(&:first)
|
||||||
|
end
|
||||||
|
|
||||||
|
def supernet_sequences
|
||||||
|
supernet_and_hypernet_sequences.each_with_index.select do |seq, i|
|
||||||
|
i % 2 == 0
|
||||||
|
end.map(&:first)
|
||||||
|
end
|
||||||
|
|
||||||
|
def supernet_and_hypernet_sequences
|
||||||
|
split("[").map{ |chunk| chunk.split("]") }.flatten.map(&:to_ip)
|
||||||
|
end
|
||||||
|
|
||||||
|
def abas
|
||||||
|
@abas ||= chars.each_cons(3).select { |triple| triple[0] == triple[2] && triple[0] != triple[1] }.map(&:join).map(&:to_ip)
|
||||||
|
end
|
||||||
|
|
||||||
|
def bab?(abas_to_match)
|
||||||
|
abas_to_match.any? { |aba| aba[0] == self[1] && self[0] == aba[1] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def babs(abas_to_match)
|
||||||
|
abas.select { |aba| aba.bab?(abas_to_match) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def supports_ssl?
|
||||||
|
supernet_abas = supernet_sequences.map(&:abas).flatten
|
||||||
|
hypernet_sequences.any? { |seq| seq.babs(supernet_abas).length > 0 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
input = STDIN.read.chomp
|
||||||
|
lines = input.split("\n").map(&:to_ip)
|
||||||
|
|
||||||
|
part_1 = lines.count(&:supports_tls?)
|
||||||
|
|
||||||
|
puts "Part 1: #{part_1}"
|
||||||
|
|
||||||
|
part_2 = lines.count(&:supports_ssl?)
|
||||||
|
|
||||||
|
puts "Part 2: #{part_2}"
|
217
ruby/2016/8/problem.rb
Normal file
217
ruby/2016/8/problem.rb
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
class Command
|
||||||
|
def self.for(line)
|
||||||
|
if line.split.first == "rect"
|
||||||
|
RectCommand
|
||||||
|
elsif line.split[1] == "row"
|
||||||
|
RotateRowCommand
|
||||||
|
elsif line.split[1] == "column"
|
||||||
|
RotateColumnCommand
|
||||||
|
end.new line
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RectCommand < Command
|
||||||
|
attr_reader :width, :height
|
||||||
|
|
||||||
|
def initialize(line)
|
||||||
|
@width, @height = line.split.last.split("x").map(&:to_i)
|
||||||
|
end
|
||||||
|
|
||||||
|
def apply(screen)
|
||||||
|
screen.rect!(width, height)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RotateRowCommand < Command
|
||||||
|
attr_reader :row, :by
|
||||||
|
|
||||||
|
def initialize(line)
|
||||||
|
@row = line.split[2].split("=")[1].to_i
|
||||||
|
@by = line.split[4].to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
def apply(screen)
|
||||||
|
screen.rotate_row!(row, by)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RotateColumnCommand < Command
|
||||||
|
attr_reader :column, :by
|
||||||
|
|
||||||
|
def initialize(line)
|
||||||
|
@column = line.split[2].split("=")[1].to_i
|
||||||
|
@by = line.split[4].to_i
|
||||||
|
end
|
||||||
|
|
||||||
|
def apply(screen)
|
||||||
|
screen.rotate_column!(column, by)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Screen
|
||||||
|
attr_reader :pixels
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@pixels = Array.new(height) { Array.new(width, " ") }
|
||||||
|
end
|
||||||
|
|
||||||
|
def width
|
||||||
|
50
|
||||||
|
end
|
||||||
|
|
||||||
|
def height
|
||||||
|
6
|
||||||
|
end
|
||||||
|
|
||||||
|
def rect!(width, height)
|
||||||
|
width.times { |x| height.times { |y| pixels[y][x] = "#" } }
|
||||||
|
end
|
||||||
|
|
||||||
|
def rotate_row!(row, by)
|
||||||
|
by.times { rotate_row_once! row }
|
||||||
|
end
|
||||||
|
|
||||||
|
def rotate_row_once!(row)
|
||||||
|
last = pixels[row].pop
|
||||||
|
pixels[row].unshift(last)
|
||||||
|
end
|
||||||
|
|
||||||
|
def rotate_column!(column, by)
|
||||||
|
by.times { rotate_column_once! column }
|
||||||
|
end
|
||||||
|
|
||||||
|
def rotate_column_once!(column)
|
||||||
|
last = pixels[height - 1][column]
|
||||||
|
(height - 1).downto(1) do |y|
|
||||||
|
pixels[y][column] = pixels[y - 1][column]
|
||||||
|
end
|
||||||
|
|
||||||
|
pixels[0][column] = last
|
||||||
|
end
|
||||||
|
|
||||||
|
def print
|
||||||
|
puts pixels.map(&:join)
|
||||||
|
end
|
||||||
|
|
||||||
|
def lit_pixel_count
|
||||||
|
pixels.flatten.count { |pixel| pixel == "#" }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ScreenLetter
|
||||||
|
attr_reader :pixels
|
||||||
|
|
||||||
|
def initialize(screen, position)
|
||||||
|
@pixels = screen.pixels.map { |line| line.slice(position * 5, 5) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def print
|
||||||
|
puts pixels.map(&:join)
|
||||||
|
puts " "
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
pixels.map(&:join).join("\n").to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def letter_value
|
||||||
|
case to_s
|
||||||
|
when LETTER_E.chomp
|
||||||
|
"E"
|
||||||
|
when LETTER_F.chomp
|
||||||
|
"F"
|
||||||
|
when LETTER_Y.chomp
|
||||||
|
"Y"
|
||||||
|
when LETTER_K.chomp
|
||||||
|
"K"
|
||||||
|
when LETTER_R.chomp
|
||||||
|
"R"
|
||||||
|
when LETTER_I.chomp
|
||||||
|
"I"
|
||||||
|
when LETTER_J.chomp
|
||||||
|
"J"
|
||||||
|
else
|
||||||
|
"?"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
LETTER_E = <<-E
|
||||||
|
####
|
||||||
|
#
|
||||||
|
###
|
||||||
|
#
|
||||||
|
#
|
||||||
|
####
|
||||||
|
E
|
||||||
|
|
||||||
|
LETTER_F = <<-F
|
||||||
|
####
|
||||||
|
#
|
||||||
|
###
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
F
|
||||||
|
|
||||||
|
LETTER_Y = <<-Y
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
Y
|
||||||
|
|
||||||
|
LETTER_K = <<-K
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
##
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
K
|
||||||
|
|
||||||
|
LETTER_R = <<-R
|
||||||
|
###
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
###
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
R
|
||||||
|
|
||||||
|
LETTER_I = <<-I
|
||||||
|
###
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
###
|
||||||
|
I
|
||||||
|
|
||||||
|
LETTER_J = <<-J
|
||||||
|
##
|
||||||
|
#
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# #
|
||||||
|
##
|
||||||
|
J
|
||||||
|
|
||||||
|
input = STDIN.read.chomp
|
||||||
|
commands = input.split("\n").map { |line| Command.for line }
|
||||||
|
screen = Screen.new
|
||||||
|
commands.each { |command| command.apply screen }
|
||||||
|
|
||||||
|
part_1 = screen.lit_pixel_count
|
||||||
|
|
||||||
|
puts "Part 1: #{part_1}"
|
||||||
|
|
||||||
|
letters = 0.upto(9).map do |position|
|
||||||
|
ScreenLetter.new screen, position
|
||||||
|
end
|
||||||
|
|
||||||
|
part_2 = letters.map(&:letter_value).join
|
||||||
|
|
||||||
|
puts "Part 2: #{part_2}"
|
Loading…
Reference in New Issue
Block a user