Something went wrong. Try again.
Code for the Advent of Code event
aoc advent-of-code
Something went wrong. Try again.
4.4 kB · 156 lines
Ruby
at rust
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157#!/usr/bin/env ruby# frozen_string_literal: true
RESOURCES = %i[ore clay obsidian geode].freezeTIME = 24
class Blueprint attr_reader :id
def initialize(id, costs) @id = id @costs = costs @caps = { ore: [@costs[:ore][:ore], @costs[:clay][:ore], @costs[:obsidian][:ore], @costs[:geode][:ore]].max, clay: @costs[:obsidian][:clay], obsidian: @costs[:geode][:obsidian] } end
def self.from_array(nums) new nums[0], { ore: { ore: nums[1] }, clay: { ore: nums[2] }, obsidian: { ore: nums[3], clay: nums[4] }, geode: { ore: nums[5], obsidian: nums[6] } } end
def solve(time_left = TIME, stock = Hash.new(0), production = Hash.new(0).tap { _1[:ore] = 1 }, maxes = { 0 => 0 }, memory = {}) cache_key = [time_left, stock, production].hash if memory.key?(cache_key) # STDERR.puts "=== CACHE HIT ===" return memory[cache_key] end
if time_left == 0 if stock[:geode] > maxes[0] maxes[0] = stock[:geode] # STDERR.print "=== FINISHED ===" # print_stock(stock) end
memory[cache_key] = stock[:geode]
return stock[:geode] end
make_geode = production[:obsidian] != 0 && stock[:ore] >= @costs[:geode][:ore] && stock[:obsidian] >= @costs[:geode][:obsidian] make_ore = !make_geode && production[:ore] < @caps[:ore] && stock[:ore] >= @costs[:ore][:ore] make_clay = !make_geode && production[:clay] < @caps[:clay] && stock[:ore] >= @costs[:clay][:ore] make_obsidian = !make_geode && production[:clay] != 0 && production[:obsidian] < @caps[:obsidian] && stock[:ore] >= @costs[:obsidian][:ore] && stock[:clay] >= @costs[:obsidian][:clay]
stock[:ore] += production[:ore] stock[:clay] += production[:clay] stock[:obsidian] += production[:obsidian] stock[:geode] += production[:geode]
if maxes.key?(time_left) if stock[:geode] < maxes[time_left] memory[cache_key] = maxes[time_left] return maxes[time_left] else maxes[time_left] = stock[:geode] end else maxes[time_left] = stock[:geode] end
time_left -= 1
remaining_potential = (production[:geode] * time_left) + (time_left * (time_left + 1) / 2) if stock[:geode] + remaining_potential <= maxes[0] memory[cache_key] = 0 return 0 end
if make_geode new_prod = production.dup.tap { _1[:geode] += 1 } new_stock = stock.dup.tap do |h| h[:ore] -= @costs[:geode][:ore] h[:obsidian] -= @costs[:geode][:obsidian] end result = solve(time_left, new_stock, new_prod, maxes, memory) memory[cache_key] = result return result end
max = 0
if make_ore new_prod = production.dup.tap { _1[:ore] += 1 } new_stock = stock.dup.tap do |h| h[:ore] -= @costs[:ore][:ore] end result = solve(time_left, new_stock, new_prod, maxes, memory) max = result if result > max end
if make_clay new_prod = production.dup.tap { _1[:clay] += 1 } new_stock = stock.dup.tap do |h| h[:ore] -= @costs[:clay][:ore] end result = solve(time_left, new_stock, new_prod, maxes, memory) max = result if result > max end
if make_obsidian new_prod = production.dup.tap { _1[:obsidian] += 1 } new_stock = stock.dup.tap do |h| h[:ore] -= @costs[:obsidian][:ore] h[:clay] -= @costs[:obsidian][:clay] end result = solve(time_left, new_stock, new_prod, maxes, memory) max = result if result > max end
result = solve(time_left, stock, production, maxes, memory) max = result if result > max
memory[cache_key] = max end
def print_stock(stock) warn " STOCK: #{stock[:ore]} ore, #{stock[:clay]} clay, #{stock[:obsidian]} obsidian, #{stock[:geode]} geode" endend
BLUEPRINTS = ARGF.read.scan(/\d+/).map(&:to_i).each_slice(7).map { Blueprint.from_array(_1) }.freeze
def part1 BLUEPRINTS.sum do |blueprint| # STDERR.puts "=== TESTING BLUEPRINT #{blueprint.id}" blueprint.solve * blueprint.id endend
def part2 BLUEPRINTS.take(3).map do |blueprint| # STDERR.puts "=== TESTING BLUEPRINT #{blueprint.id}" blueprint.solve(32) end.reduce(:*)end
puts part1puts part2