mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-18 19:13:27 +02:00
added day14 solutions, weighted graph BF traversals
This commit is contained in:
@@ -19,3 +19,4 @@ Day | Name | Type of Algo & Notes
|
||||
11 | Space Police | - More Intcode stuff... <br> - __2D Array/Slice manipulation__ and a bit of maths/graphing <br> - Implemented a __RotateGrid__ algo
|
||||
12 | The N-Body Problem | I like to call this a _(harmonic) frequency_ algo. Finding the harmonic frequency of multiple bodies/items and then finding the Least Common Multiple of those frequencies will tell you when all the bodies have returned to their initial state. <br> - I've used this approach for a leetcode problem about prisoners in jail cells too
|
||||
13 | Care Package | Intcode again! It's basically every other day... <br> - part1: 2D array manipulation again <br> - part2: holy algo, some logic to basically play Bricks game. <br> - This is more of a design question for how you manage state
|
||||
14 | Space Stoichiometry | __Weighted Graph and Breadth First Traversals__ <br> - Because not all of the products have a quantity of 1, it complicates the graph's data model. I ended up mapping the product/chemical name to a map of its stoichiometry where the product's number is positive & reactants were negative. <br> - part2: not just a simple division because of "extra byproducts" of generating each piece of fuel. I just let this brute force thing run for ~30 seconds...
|
||||
@@ -0,0 +1,102 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"adventofcode/util"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
input := util.ReadFile("../input.txt")
|
||||
stoichiometryGraph := makeDependencyGraph(strings.Split(input, "\n"))
|
||||
|
||||
neededChemicals := map[string]int{"FUEL": 1}
|
||||
|
||||
// fmt.Println(stoichiometryGraph, neededChemicals)
|
||||
|
||||
// while the neededChemicals map has positive values for keys besides "ORE"
|
||||
for !isOnlyOres(neededChemicals) {
|
||||
// iterate through neededChemicals
|
||||
for neededChemical, quantityNeeded := range neededChemicals {
|
||||
// if a positive value is found for a neededChemical besides "ORE"
|
||||
if quantityNeeded > 0 && neededChemical != "ORE" {
|
||||
// find its reaction in the stoichiometryGraph
|
||||
reactionStoichiometry := stoichiometryGraph[neededChemical]
|
||||
|
||||
// determine the number of times the reactionStoichiometry must be run
|
||||
timesToRun := quantityNeeded / reactionStoichiometry[neededChemical]
|
||||
if quantityNeeded%reactionStoichiometry[neededChemical] > 0 {
|
||||
timesToRun++
|
||||
}
|
||||
|
||||
// decrement all of the values in neededChemicals map with this reaction's details (* timesToRun)
|
||||
for reactionChemical, chemicalStoich := range reactionStoichiometry {
|
||||
neededChemicals[reactionChemical] -= chemicalStoich * timesToRun
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Print final output
|
||||
fmt.Println("ORE needed", neededChemicals["ORE"])
|
||||
}
|
||||
|
||||
// Creates a graph that maps the products name to its full reaction stoichiometry
|
||||
func makeDependencyGraph(reactions []string) map[string]map[string]int {
|
||||
graph := make(map[string]map[string]int)
|
||||
|
||||
for _, reaction := range reactions {
|
||||
product, reactionStoichiometry := parseReaction(reaction)
|
||||
graph[product] = reactionStoichiometry
|
||||
}
|
||||
|
||||
return graph
|
||||
}
|
||||
|
||||
// parseReaction takes in a line of the input i.e. a reaction in a string
|
||||
// parses all its details and returns the generated product as a string
|
||||
// and a map of all products to the quantity used/produced by the reaction
|
||||
// for produced chemicals, map value will be > 0, inputs will be < 0
|
||||
func parseReaction(reaction string) (string, map[string]int) {
|
||||
reactionStoichiometry := make(map[string]int)
|
||||
|
||||
splitByArrow := strings.Split(reaction, " => ")
|
||||
productStr := splitByArrow[1]
|
||||
reactantsStr := splitByArrow[0]
|
||||
|
||||
// handle product
|
||||
productQty, productName := parseQtyAndName(productStr)
|
||||
|
||||
reactionStoichiometry[productName] = productQty
|
||||
|
||||
// split reactants via comma first
|
||||
reactantsSli := strings.Split(reactantsStr, ", ")
|
||||
for _, str := range reactantsSli {
|
||||
reactantQuantity, reactantName := parseQtyAndName(str)
|
||||
reactionStoichiometry[reactantName] = -1 * reactantQuantity
|
||||
}
|
||||
|
||||
return productName, reactionStoichiometry
|
||||
}
|
||||
|
||||
// parse an inputted string of the for "<number> <string>" and return the int & string
|
||||
func parseQtyAndName(input string) (int, string) {
|
||||
split := strings.Split(input, " ")
|
||||
|
||||
quantity, _ := strconv.Atoi(split[0])
|
||||
name := split[1]
|
||||
|
||||
return quantity, name
|
||||
}
|
||||
|
||||
// helper function to determine if the neededChemicals graph is "complete"
|
||||
// it is complete if there only positive value is for the chemical "ORE"
|
||||
func isOnlyOres(neededChemicals map[string]int) bool {
|
||||
for key, val := range neededChemicals {
|
||||
if key != "ORE" && val > 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"adventofcode/util"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// const will be comparable to any int type?
|
||||
const trillion int = 1000000000000
|
||||
|
||||
func main() {
|
||||
input := util.ReadFile("../input.txt")
|
||||
stoichiometryGraph := makeDependencyGraph(strings.Split(input, "\n"))
|
||||
|
||||
// give the brute force algo a big headstart? 1 million fuels to start?
|
||||
var fuelMade int = 1000000
|
||||
neededChemicals := map[string]int{"FUEL": fuelMade}
|
||||
|
||||
// brute force this while the ore count is below 1 trillion
|
||||
for neededChemicals["ORE"] <= trillion {
|
||||
neededChemicals["FUEL"]++
|
||||
// while the neededChemicals map has positive values for keys besides "ORE"
|
||||
for !isOnlyOres(neededChemicals) {
|
||||
// iterate through neededChemicals
|
||||
for neededChemical, quantityNeeded := range neededChemicals {
|
||||
// if a positive value is found for a neededChemical besides "ORE"
|
||||
if quantityNeeded > 0 && neededChemical != "ORE" {
|
||||
// find its reaction in the stoichiometryGraph
|
||||
reactionStoichiometry := stoichiometryGraph[neededChemical]
|
||||
|
||||
// determine the number of times the reactionStoichiometry must be run
|
||||
timesToRun := quantityNeeded / reactionStoichiometry[neededChemical]
|
||||
if quantityNeeded%reactionStoichiometry[neededChemical] > 0 {
|
||||
timesToRun++
|
||||
}
|
||||
|
||||
// decrement all of the values in neededChemicals map with this reaction's details (* timesToRun)
|
||||
for reactionChemical, chemicalStoich := range reactionStoichiometry {
|
||||
neededChemicals[reactionChemical] -= chemicalStoich * timesToRun
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if you don't exceed the 1 trillion ORE, increment fuelMade
|
||||
if neededChemicals["ORE"] < trillion {
|
||||
fuelMade++
|
||||
}
|
||||
fmt.Println("Making FUEL... Remaining ORE:", trillion-neededChemicals["ORE"])
|
||||
}
|
||||
|
||||
// Print final output
|
||||
fmt.Println("\nFinal amount of FUEL", fuelMade)
|
||||
}
|
||||
|
||||
// Creates a graph that maps the products name to its full reaction stoichiometry
|
||||
func makeDependencyGraph(reactions []string) map[string]map[string]int {
|
||||
graph := make(map[string]map[string]int)
|
||||
|
||||
for _, reaction := range reactions {
|
||||
product, reactionStoichiometry := parseReaction(reaction)
|
||||
graph[product] = reactionStoichiometry
|
||||
}
|
||||
|
||||
return graph
|
||||
}
|
||||
|
||||
// parseReaction takes in a line of the input i.e. a reaction in a string
|
||||
// parses all its details and returns the generated product as a string
|
||||
// and a map of all products to the quantity used/produced by the reaction
|
||||
// for produced chemicals, map value will be > 0, inputs will be < 0
|
||||
func parseReaction(reaction string) (string, map[string]int) {
|
||||
reactionStoichiometry := make(map[string]int)
|
||||
|
||||
splitByArrow := strings.Split(reaction, " => ")
|
||||
productStr := splitByArrow[1]
|
||||
reactantsStr := splitByArrow[0]
|
||||
|
||||
// handle product
|
||||
productQty, productName := parseQtyAndName(productStr)
|
||||
|
||||
reactionStoichiometry[productName] = productQty
|
||||
|
||||
// split reactants via comma first
|
||||
reactantsSli := strings.Split(reactantsStr, ", ")
|
||||
for _, str := range reactantsSli {
|
||||
reactantQuantity, reactantName := parseQtyAndName(str)
|
||||
reactionStoichiometry[reactantName] = -1 * reactantQuantity
|
||||
}
|
||||
|
||||
return productName, reactionStoichiometry
|
||||
}
|
||||
|
||||
// parse an inputted string of the for "<number> <string>" and return the int & string
|
||||
func parseQtyAndName(input string) (int, string) {
|
||||
split := strings.Split(input, " ")
|
||||
|
||||
quantity, _ := strconv.Atoi(split[0])
|
||||
name := split[1]
|
||||
|
||||
return quantity, name
|
||||
}
|
||||
|
||||
// helper function to determine if the neededChemicals graph is "complete"
|
||||
// it is complete if there only positive value is for the chemical "ORE"
|
||||
func isOnlyOres(neededChemicals map[string]int) bool {
|
||||
for key, val := range neededChemicals {
|
||||
if key != "ORE" && val > 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user