118 lines
2.1 KiB
Crystal
118 lines
2.1 KiB
Crystal
|
require "advent"
|
||
|
|
||
|
input = input(2020, 23).lines[0].chars.map &.to_i32
|
||
|
|
||
|
class Array(T)
|
||
|
def get(i)
|
||
|
self[i % size]
|
||
|
end
|
||
|
|
||
|
def del(i)
|
||
|
delete_at(i % size)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class Node
|
||
|
property next : Node
|
||
|
property int : Int32
|
||
|
|
||
|
def initialize(@int, @next)
|
||
|
end
|
||
|
|
||
|
def insert(other : Node, n = 1)
|
||
|
set_next = other
|
||
|
(n-1).times { set_next = set_next.@next }
|
||
|
set_next.next = @next
|
||
|
@next = other
|
||
|
end
|
||
|
|
||
|
def remove(n = 1)
|
||
|
curr = self
|
||
|
to_return = self.next
|
||
|
n.times { curr = curr.@next }
|
||
|
@next = curr.@next
|
||
|
to_return
|
||
|
end
|
||
|
|
||
|
def find(n)
|
||
|
start = self
|
||
|
while start.int != n
|
||
|
start = start.next
|
||
|
end
|
||
|
return start
|
||
|
end
|
||
|
|
||
|
def to_s(n)
|
||
|
return "" if n < 0
|
||
|
return "#{@int} -> #{@next.to_s(n-1)}"
|
||
|
end
|
||
|
|
||
|
def includes?(n, count)
|
||
|
return false if count <= 0
|
||
|
return @int == n || @next.includes?(n, count-1)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
class Cups
|
||
|
getter size : Int32
|
||
|
getter head : Node
|
||
|
|
||
|
def initialize(list : Array(Int32))
|
||
|
@cache = {} of Int32 => Node
|
||
|
h = list.delete_at(0)
|
||
|
temp = uninitialized Node
|
||
|
@cache[h] = @head = Node.new(h, temp)
|
||
|
@size = list.size
|
||
|
@local_min = list.min.as(Int32)
|
||
|
@local_max = list.max.as(Int32)
|
||
|
@head.next = @head
|
||
|
curr = @head
|
||
|
list.each do |n|
|
||
|
@cache[n] = new = Node.new(n, curr.next)
|
||
|
curr.insert(new)
|
||
|
curr = new
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def to_s
|
||
|
@head.to_s(@size)
|
||
|
end
|
||
|
|
||
|
def step
|
||
|
first = @head
|
||
|
after = first.remove(3)
|
||
|
m = first.int - 1
|
||
|
while after.includes?(m, 3) || m < @local_min
|
||
|
m = (m < @local_min) ? @local_max : (m - 1)
|
||
|
end
|
||
|
@cache[m].insert(after, 3)
|
||
|
@head = @head.next
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def play(input, count)
|
||
|
cups = Cups.new input
|
||
|
count.times { |n| cups.step }
|
||
|
cups
|
||
|
end
|
||
|
|
||
|
def part1(input)
|
||
|
cups = play(input.clone, 100)
|
||
|
cups.head.find(1).next.to_s(cups.size - 1).gsub(" -> ", "")
|
||
|
end
|
||
|
|
||
|
def part2(input)
|
||
|
list = input.clone
|
||
|
max = input.max
|
||
|
(1000000 - input.size).times do
|
||
|
max += 1
|
||
|
list << max
|
||
|
end
|
||
|
cups = play(list, 10000000)
|
||
|
one = cups.head.find(1)
|
||
|
one.next.int.to_i64 * one.next.next.int
|
||
|
end
|
||
|
|
||
|
puts "Part 1: #{part1(input)}"
|
||
|
puts "Part 2: #{part2(input)}"
|