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