mirror of
https://github.com/RussellChamp/advent-of-code-2021.git
synced 2026-10-27 21:52:32 +00:00
day 14 and 15
This commit is contained in:
1 parent
6e22bbe567
commit
4737afa383
12 files changed
+678
-3
No files matched your search
+2
-1
@@ -16,4 +16,5 @@
|
|||||||
|
|
||||||
# Other stuff
|
# Other stuff
|
||||||
*.log
|
*.log
|
||||||
input.txt
|
input.txt
|
||||||
|
.vscode
|
||||||
Executable
BIN
Binary file not shown.
+165
@@ -0,0 +1,165 @@
|
|||||||
|
/* Day 14: Extended Polymerization */
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"AoC2021/utils/args"
|
||||||
|
"AoC2021/utils/log"
|
||||||
|
"AoC2021/utils/timer"
|
||||||
|
"bufio"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
argMap := args.Parse(os.Args)
|
||||||
|
setLogLevel(argMap)
|
||||||
|
selectedPart, partSpecified := argMap["part"]
|
||||||
|
|
||||||
|
log.Println(log.NORMAL, "--- Day 14: Extended Polymerization ---")
|
||||||
|
timer.Start()
|
||||||
|
if !partSpecified || selectedPart == "1" {
|
||||||
|
part1()
|
||||||
|
timer.TickAtLevel(log.NORMAL)
|
||||||
|
log.Println(log.NORMAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !partSpecified || selectedPart == "2" {
|
||||||
|
part2()
|
||||||
|
timer.TickAtLevel(log.NORMAL)
|
||||||
|
log.Println(log.NORMAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func part1() {
|
||||||
|
log.Println(log.NORMAL, "* Part 1 *")
|
||||||
|
log.Println(log.NORMAL, " Goal: Apply 10 steps of pair insertion to the polymer template and find the most and least common elements in the result.")
|
||||||
|
log.Println(log.NORMAL, " Answer: What do you get if you take the quantity of the most common element and subtract the quantity of the least common element?")
|
||||||
|
|
||||||
|
doTheThing(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func part2() {
|
||||||
|
log.Println(log.NORMAL, "* Part 2 *")
|
||||||
|
log.Println(log.NORMAL, " Goal: Apply 40 steps of pair insertion to the polymer template and find the most and least common elements in the result.")
|
||||||
|
log.Println(log.NORMAL, " Answer: What do you get if you take the quantity of the most common element and subtract the quantity of the least common element?")
|
||||||
|
|
||||||
|
doTheThing(40)
|
||||||
|
}
|
||||||
|
|
||||||
|
func doTheThing(totalSteps int) {
|
||||||
|
|
||||||
|
template, pairs := readInput()
|
||||||
|
log.Println(log.DIAGNOSTIC, template, pairs)
|
||||||
|
|
||||||
|
// perform the loop 'totalSteps' times
|
||||||
|
for step := 0; step < totalSteps; step++ {
|
||||||
|
// starting from the front of the template, check two-letter pairs
|
||||||
|
for tIdx := 0; tIdx < len(template)-1; tIdx++ {
|
||||||
|
// the lookup key will be the next two letters in the template
|
||||||
|
key := template[tIdx : tIdx+2]
|
||||||
|
// if we find a match in the pairs map
|
||||||
|
value, found := pairs[key]
|
||||||
|
if found {
|
||||||
|
// insert the new character between the original two letters
|
||||||
|
template = template[:tIdx+1] + value + template[tIdx+1:]
|
||||||
|
// increment the idx counter once more so that we skip over the character that we just inserted
|
||||||
|
tIdx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Printf(log.DEBUG, "After step #%d template is length %d\n", step+1, len(template))
|
||||||
|
timer.TickAtLevel(log.DEBUG)
|
||||||
|
}
|
||||||
|
|
||||||
|
// COUNT all character occurances
|
||||||
|
countMap := make(map[byte]int)
|
||||||
|
|
||||||
|
for idx := 0; idx < len(template); idx++ {
|
||||||
|
countMap[template[idx]]++
|
||||||
|
}
|
||||||
|
log.Println(log.DIAGNOSTIC, "CountMap:", countMap)
|
||||||
|
|
||||||
|
mostCommonLetter, mostCommonCount := getMostCommon(countMap)
|
||||||
|
leastCommonLetter, leastCommonCount := getLeastCommon(countMap)
|
||||||
|
|
||||||
|
log.Printf(log.NORMAL, "After %d steps, the most common (%s=%d) minus the least common (%s=%d) is %d\n", totalSteps, mostCommonLetter, mostCommonCount, leastCommonLetter, leastCommonCount, mostCommonCount-leastCommonCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
log.Println(log.DEBUG, "Oh snap!")
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setLogLevel(argMap map[string]string) {
|
||||||
|
logLevelStr, found := argMap["log"]
|
||||||
|
if found {
|
||||||
|
logLevel, err := strconv.Atoi(logLevelStr)
|
||||||
|
check(err)
|
||||||
|
log.SetLogLevel(logLevel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func readInput() (string, map[string]string) {
|
||||||
|
input, err := os.Open("./input.txt")
|
||||||
|
check(err)
|
||||||
|
defer input.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(input)
|
||||||
|
lines := 0
|
||||||
|
|
||||||
|
// TEMPLATE LINE
|
||||||
|
if !scanner.Scan() {
|
||||||
|
panic("Error parsing input template")
|
||||||
|
}
|
||||||
|
template := scanner.Text()
|
||||||
|
lines++
|
||||||
|
|
||||||
|
// NEW LINE
|
||||||
|
if !scanner.Scan() {
|
||||||
|
panic("Error parsing input newline")
|
||||||
|
}
|
||||||
|
_ = scanner.Text()
|
||||||
|
lines++
|
||||||
|
|
||||||
|
// PAIRS
|
||||||
|
pairs := make(map[string]string)
|
||||||
|
for scanner.Scan() {
|
||||||
|
pair := strings.Split(scanner.Text(), " -> ")
|
||||||
|
if len(pair) != 2 {
|
||||||
|
panic("Error parsing input pairs")
|
||||||
|
}
|
||||||
|
pairs[pair[0]] = pair[1]
|
||||||
|
lines++
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf(log.NORMAL, "Read %d pairs from %d lines in input\n", len(pairs), lines)
|
||||||
|
|
||||||
|
return template, pairs
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMostCommon(countMap map[byte]int) (string, int) {
|
||||||
|
mostCommonStr := ""
|
||||||
|
mostCommonCount := -math.MaxInt
|
||||||
|
for key, value := range countMap {
|
||||||
|
if value > mostCommonCount {
|
||||||
|
mostCommonStr, mostCommonCount = string(key), value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mostCommonStr, mostCommonCount
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLeastCommon(countMap map[byte]int) (string, int) {
|
||||||
|
leastCommonStr := ""
|
||||||
|
leastCommonCount := math.MaxInt
|
||||||
|
for key, value := range countMap {
|
||||||
|
if value < leastCommonCount {
|
||||||
|
leastCommonStr, leastCommonCount = string(key), value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return leastCommonStr, leastCommonCount
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"AoC2021/utils/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDay14(t *testing.T) {
|
||||||
|
assert.IsTrue(t, true, "cool")
|
||||||
|
assert.EqualsStr(t, "foo", "bar", "baz")
|
||||||
|
}
|
||||||
+307
@@ -0,0 +1,307 @@
|
|||||||
|
/* Day 15: Chiton */
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"AoC2021/utils/arrays"
|
||||||
|
"AoC2021/utils/color"
|
||||||
|
"AoC2021/utils/log"
|
||||||
|
"AoC2021/utils/numbers"
|
||||||
|
"AoC2021/utils/timer"
|
||||||
|
"bufio"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
log.Println(log.DEBUG, "Oh snap!")
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
log.Println(log.NORMAL, "--- Day 15: Chiton ---")
|
||||||
|
timer.Start()
|
||||||
|
part1()
|
||||||
|
timer.Tick()
|
||||||
|
log.Println(log.NORMAL)
|
||||||
|
|
||||||
|
// TODO: Write a faster algorithm
|
||||||
|
// part2()
|
||||||
|
// timer.Tick()
|
||||||
|
// log.Println(log.NORMAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func part1() {
|
||||||
|
log.Println(log.NORMAL, "* Part 1 *")
|
||||||
|
log.Printf(log.NORMAL, color.Green)
|
||||||
|
log.Println(log.NORMAL, " Goal: Your goal is to find a path with the lowest total risk.")
|
||||||
|
log.Println(log.NORMAL, " Answer: What is the lowest total risk of any path from the top left to the bottom right?")
|
||||||
|
log.Printf(log.NORMAL, color.Reset)
|
||||||
|
|
||||||
|
risks := readRiskNodes()
|
||||||
|
costs := initCosts(risks)
|
||||||
|
|
||||||
|
calcCosts(risks, &costs)
|
||||||
|
lastRow := len(costs) - 1
|
||||||
|
lastCol := len(costs[lastRow]) - 1
|
||||||
|
exitCost := costs[lastRow][lastCol] - costs[0][0]
|
||||||
|
|
||||||
|
log.Printf(log.NORMAL, "The lowest risk cost from row=0 col=0 to row=%d col=%d is %d\n", lastRow, lastCol, exitCost)
|
||||||
|
walkPath(risks, costs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func part2() {
|
||||||
|
log.SetLogLevel(log.DEBUG)
|
||||||
|
|
||||||
|
log.Println(log.NORMAL, "* Part 2 *")
|
||||||
|
log.Printf(log.NORMAL, color.Green)
|
||||||
|
log.Println(log.NORMAL, " Goal: Calc using the full map")
|
||||||
|
log.Println(log.NORMAL, " Answer: What is the lowest total risk of any path from the top left to the bottom right?")
|
||||||
|
log.Printf(log.NORMAL, color.Reset)
|
||||||
|
|
||||||
|
risks := readRiskNodes()
|
||||||
|
expandRisks(&risks)
|
||||||
|
costs := initCosts(risks)
|
||||||
|
|
||||||
|
calcCosts(risks, &costs)
|
||||||
|
lastRow := len(costs) - 1
|
||||||
|
lastCol := len(costs[lastRow]) - 1
|
||||||
|
exitCost := costs[lastRow][lastCol] - costs[0][0]
|
||||||
|
|
||||||
|
log.Printf(log.NORMAL, "The lowest risk cost from row=0 col=0 to row=%d col=%d is %d\n", lastRow, lastCol, exitCost)
|
||||||
|
walkPath(risks, costs)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RiskNodes [][]int
|
||||||
|
|
||||||
|
func readRiskNodes() RiskNodes {
|
||||||
|
input, err := os.Open("./input.txt")
|
||||||
|
check(err)
|
||||||
|
defer input.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(input)
|
||||||
|
lines := 0
|
||||||
|
|
||||||
|
var risks RiskNodes
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
lines++
|
||||||
|
// We'll just hope that our input is well formed
|
||||||
|
risks = append(risks, arrays.MapStrToInt(strings.Split(line, ""), func(s string) int { i, _ := strconv.Atoi(s); return i }))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf(log.DEBUG, "Read %d lines from input\n", lines)
|
||||||
|
return risks
|
||||||
|
}
|
||||||
|
|
||||||
|
func expandRisks(risks *RiskNodes) {
|
||||||
|
multiplier := 5
|
||||||
|
// expand out all the lines to the new width
|
||||||
|
rowLen, colLen := len(*risks), len((*risks)[0])
|
||||||
|
|
||||||
|
// extend each row N times
|
||||||
|
for rIdx, row := range *risks {
|
||||||
|
for m := 1; m < multiplier; m++ {
|
||||||
|
(*risks)[rIdx] = append((*risks)[rIdx], row...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// copy each row N times
|
||||||
|
for m := 1; m < multiplier; m++ {
|
||||||
|
for rIdx := 0; rIdx < rowLen; rIdx++ {
|
||||||
|
(*risks) = append((*risks), (*risks)[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// increment the risk number in each cell
|
||||||
|
for rIdx, row := range *risks {
|
||||||
|
for cIdx, value := range row {
|
||||||
|
if rIdx < rowLen && cIdx < colLen {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// add 1 for every section right or down that we've copied
|
||||||
|
newVal := (value + rIdx/rowLen + cIdx/colLen) % 10
|
||||||
|
(*risks)[rIdx][cIdx] = newVal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Println(log.DIAGNOSTIC, "Expanded risk nodes to new size")
|
||||||
|
}
|
||||||
|
|
||||||
|
type CostNodes [][]int
|
||||||
|
|
||||||
|
func initCosts(risks RiskNodes) CostNodes {
|
||||||
|
var costs CostNodes
|
||||||
|
for _, row := range risks {
|
||||||
|
costs = append(costs, make([]int, len(row)))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf(log.DIAGNOSTIC, "Initialized costs node of size row=%d by col=%d\n", len(risks), len(risks[0]))
|
||||||
|
|
||||||
|
return costs
|
||||||
|
}
|
||||||
|
|
||||||
|
var filledNodes int
|
||||||
|
var recalcCount int
|
||||||
|
var totalNodes int
|
||||||
|
|
||||||
|
func calcCosts(risks RiskNodes, costs *CostNodes) {
|
||||||
|
// the goal is to MINIMIZE the risk cost from traveling from START to END
|
||||||
|
// starting from the current node check each adjacent valid node
|
||||||
|
// if the total cost on that node is 0 or if the toal cost is > the current node total cost + next node travel cost
|
||||||
|
// then update that next node's total and continue iterating at it
|
||||||
|
// otherwise just stop
|
||||||
|
(*costs)[0][0] = math.MaxInt // so that we don't go back to start
|
||||||
|
|
||||||
|
filledNodes = 1
|
||||||
|
totalNodes = len(*costs) * len((*costs)[0])
|
||||||
|
log.Println(log.DIAGNOSTIC, "Starting calc from (0,0)")
|
||||||
|
calcAllNeighbors(risks, costs, 0, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RowCol struct {
|
||||||
|
r int
|
||||||
|
c int
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcAllNeighbors(risks RiskNodes, costs *CostNodes, row, col, currentTotal int) {
|
||||||
|
if !nodeIsValid(*costs, row, col) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf(log.DIAGNOSTIC, "Calculating neighbors at row=%d col=%d\n", row, col)
|
||||||
|
if (*costs)[row][col] == 0 || (*costs)[row][col] > currentTotal+risks[row][col] {
|
||||||
|
if (*costs)[row][col] == 0 {
|
||||||
|
filledNodes++
|
||||||
|
if filledNodes%1000 == 0 {
|
||||||
|
log.Printf(log.DEBUG, "Calculated %d / %d nodes\n", filledNodes, totalNodes)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
recalcCount++
|
||||||
|
if recalcCount%10000 == 0 {
|
||||||
|
log.Printf(log.DEBUG, "Recalculated %d / ?? nodes\n", recalcCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(*costs)[row][col] = currentTotal + risks[row][col]
|
||||||
|
/* UP */ calcAllNeighbors(risks, costs, row-1, col, currentTotal+risks[row][col])
|
||||||
|
/* DOWN */ calcAllNeighbors(risks, costs, row+1, col, currentTotal+risks[row][col])
|
||||||
|
/* LEFT */ calcAllNeighbors(risks, costs, row, col-1, currentTotal+risks[row][col])
|
||||||
|
/* RIGHT */ calcAllNeighbors(risks, costs, row, col+1, currentTotal+risks[row][col])
|
||||||
|
} else {
|
||||||
|
log.Printf(log.DIAGNOSTIC, "Hit a calc dead end at row=%d, col=%d\n", row, col)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeIsValid(costs CostNodes, row, col int) bool {
|
||||||
|
switch {
|
||||||
|
case col < 0, col >= len(costs):
|
||||||
|
return false
|
||||||
|
case row < 0, row >= len(costs[col]):
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func walkPath(risks RiskNodes, costs CostNodes) {
|
||||||
|
// start from the end and go toward the beginning then flip the script
|
||||||
|
row := len(costs) - 1
|
||||||
|
col := len(costs[row]) - 1
|
||||||
|
|
||||||
|
log.Printf(log.DIAGNOSTIC, "Starting to walk path at row=%d, col=%d\n", row, col)
|
||||||
|
|
||||||
|
nodes := []RowCol{{row, col}}
|
||||||
|
|
||||||
|
sum := 0
|
||||||
|
for ; row != 0 || col != 0; row, col = lowestNeighbor(costs, row, col) {
|
||||||
|
nodes = append(nodes, RowCol{row, col})
|
||||||
|
sum += risks[row][col]
|
||||||
|
}
|
||||||
|
nodes = append(nodes, RowCol{row, col})
|
||||||
|
// don't count 0,0 in the sum
|
||||||
|
|
||||||
|
// print all the nodes and if they are on the path then color them
|
||||||
|
printColor := color.DarkGray
|
||||||
|
|
||||||
|
for row := 0; row < len(risks); row++ {
|
||||||
|
for col := 0; col < len(risks[row]); col++ {
|
||||||
|
// for the first and last node, print in yellow
|
||||||
|
// for nodes on the path, print in green
|
||||||
|
// else print in normal
|
||||||
|
if (row == 0 && col == 0) || (row == len(risks)-1 && col == len(risks[row])-1) {
|
||||||
|
printColor = color.YellowBold
|
||||||
|
log.Printf(log.NORMAL, printColor)
|
||||||
|
} else if inPath(nodes, row, col) {
|
||||||
|
if printColor != color.BlueBold {
|
||||||
|
printColor = color.BlueBold
|
||||||
|
log.Printf(log.NORMAL, printColor)
|
||||||
|
}
|
||||||
|
} else if printColor != color.DarkGray {
|
||||||
|
printColor = color.DarkGray
|
||||||
|
log.Printf(log.NORMAL, printColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf(log.NORMAL, "%d", risks[row][col])
|
||||||
|
}
|
||||||
|
log.Println(log.NORMAL)
|
||||||
|
}
|
||||||
|
log.Printf(log.NORMAL, color.Reset)
|
||||||
|
|
||||||
|
// iterate through backward to go from start node to end
|
||||||
|
row, col = nodes[len(nodes)-1].r, nodes[len(nodes)-1].c
|
||||||
|
log.Printf(log.NORMAL, color.Blue+"%d (%03d)"+color.Reset, risks[row][col], costs[row][col])
|
||||||
|
for nIdx := len(nodes) - 2; nIdx >= 0; nIdx-- {
|
||||||
|
row, col = nodes[nIdx].r, nodes[nIdx].c
|
||||||
|
log.Printf(log.NORMAL, " -> "+color.Blue+"%d (%03d)"+color.Reset, risks[row][col], costs[row][col])
|
||||||
|
if (len(nodes)-nIdx)%16 == 0 {
|
||||||
|
log.Println(log.NORMAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Println(log.NORMAL)
|
||||||
|
|
||||||
|
log.Printf(log.DEBUG, "Total risk cost is %d in %d steps\n", sum, len(nodes))
|
||||||
|
}
|
||||||
|
|
||||||
|
func lowestNeighbor(costs CostNodes, row, col int) (int, int) {
|
||||||
|
// if we're at 0,1 or 1,0 then just go to 0,0
|
||||||
|
if (row == 0 && col == 1) || (row == 1 && col == 0) {
|
||||||
|
return 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// compare UP, DOWN, LEFT, RIGHT
|
||||||
|
upCost, downCost, leftCost, rightCost := math.MaxInt, math.MaxInt, math.MaxInt, math.MaxInt
|
||||||
|
if nodeIsValid(costs, row-1, col) {
|
||||||
|
upCost = costs[row-1][col]
|
||||||
|
}
|
||||||
|
if nodeIsValid(costs, row+1, col) {
|
||||||
|
downCost = costs[row+1][col]
|
||||||
|
}
|
||||||
|
if nodeIsValid(costs, row, col-1) {
|
||||||
|
leftCost = costs[row][col-1]
|
||||||
|
}
|
||||||
|
if nodeIsValid(costs, row, col+1) {
|
||||||
|
rightCost = costs[row][col+1]
|
||||||
|
}
|
||||||
|
|
||||||
|
switch numbers.Min(upCost, downCost, leftCost, rightCost) {
|
||||||
|
case upCost:
|
||||||
|
return row - 1, col
|
||||||
|
case downCost:
|
||||||
|
return row + 1, col
|
||||||
|
case leftCost:
|
||||||
|
return row, col - 1
|
||||||
|
case rightCost:
|
||||||
|
return row, col + 1
|
||||||
|
default:
|
||||||
|
panic("at the disco!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func inPath(nodes []RowCol, row, col int) bool {
|
||||||
|
for _, n := range nodes {
|
||||||
|
if n.r == row && n.c == col {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"AoC2021/utils/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDay15(t *testing.T) {
|
||||||
|
assert.IsTrue(t, true, "cool")
|
||||||
|
assert.EqualsStr(t, "foo", "bar", "baz")
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ init:
|
|||||||
touch day-$(day)/input.txt;
|
touch day-$(day)/input.txt;
|
||||||
|
|
||||||
build:
|
build:
|
||||||
cd day-$(day); go run .
|
cd day-$(day); go run . log=$(log) part=$(part)
|
||||||
|
|
||||||
test:
|
test:
|
||||||
cd day-$(day); go test
|
cd day-$(day); go test
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package args
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func Parse(args []string) map[string]string {
|
||||||
|
argMap := make(map[string]string)
|
||||||
|
for _, arg := range args {
|
||||||
|
pair := strings.Split(arg, "=")
|
||||||
|
if len(pair) == 2 {
|
||||||
|
argMap[pair[0]] = pair[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return argMap
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package color
|
||||||
|
|
||||||
|
import "runtime"
|
||||||
|
|
||||||
|
var Reset = "\033[0m"
|
||||||
|
var Red = "\033[31m"
|
||||||
|
var Green = "\033[32m"
|
||||||
|
var Yellow = "\033[33m"
|
||||||
|
var Blue = "\033[34m"
|
||||||
|
var Purple = "\033[35m"
|
||||||
|
var Cyan = "\033[36m"
|
||||||
|
var LightGray = "\033[37m"
|
||||||
|
var DarkGray = "\033[30m"
|
||||||
|
var White = "\033[97m"
|
||||||
|
|
||||||
|
var BlackBold = "\033[1;30m"
|
||||||
|
var RedBold = "\033[1;31m"
|
||||||
|
var GreenBold = "\033[1;32m"
|
||||||
|
var YellowBold = "\033[1;33m"
|
||||||
|
var BlueBold = "\033[1;34m"
|
||||||
|
var PurpleBold = "\033[1;35m"
|
||||||
|
var CyanBold = "\033[1;36m"
|
||||||
|
var WhiteBold = "\033[1;37m"
|
||||||
|
|
||||||
|
var BlackUnderline = "\033[4;30m"
|
||||||
|
var RedUnderline = "\033[4;31m"
|
||||||
|
var GreenUnderline = "\033[4;32m"
|
||||||
|
var YellowUnderline = "\033[4;33m"
|
||||||
|
var BlueUnderline = "\033[4;34m"
|
||||||
|
var PurpleUnderline = "\033[4;35m"
|
||||||
|
var CyanUnderline = "\033[4;36m"
|
||||||
|
var WhiteUnderline = "\033[4;37m"
|
||||||
|
|
||||||
|
var BlackBackground = "\033[40m"
|
||||||
|
var RedBackground = "\033[41m"
|
||||||
|
var GreenBackground = "\033[42m"
|
||||||
|
var YellowBackground = "\033[43m"
|
||||||
|
var BlueBackground = "\033[44m"
|
||||||
|
var PurpleBackground = "\033[45m"
|
||||||
|
var CyanBackground = "\033[46m"
|
||||||
|
var WhiteBackground = "\033[47m"
|
||||||
|
|
||||||
|
var BlackHigh = "\033[0;90m"
|
||||||
|
var RedHigh = "\033[0;91m"
|
||||||
|
var GreenHigh = "\033[0;92m"
|
||||||
|
var YellowHigh = "\033[0;93m"
|
||||||
|
var BlueHigh = "\033[0;94m"
|
||||||
|
var PurpleHigh = "\033[0;95m"
|
||||||
|
var CyanHigh = "\033[0;96m"
|
||||||
|
var WhiteHigh = "\033[0;97m"
|
||||||
|
|
||||||
|
var BlackBoldHigh = "\033[1;90m"
|
||||||
|
var RedBoldHigh = "\033[1;91m"
|
||||||
|
var GreenBoldHigh = "\033[1;92m"
|
||||||
|
var YellowBoldHigh = "\033[1;93m"
|
||||||
|
var BlueBoldHigh = "\033[1;94m"
|
||||||
|
var PurpleBoldHigh = "\033[1;95m"
|
||||||
|
var CyanBoldHigh = "\033[1;96m"
|
||||||
|
var WhiteBoldHigh = "\033[1;97m"
|
||||||
|
|
||||||
|
var BlackHighBack = "\033[0;100m"
|
||||||
|
var RedHighBack = "\033[0;101m"
|
||||||
|
var GreenHighBack = "\033[0;102m"
|
||||||
|
var YellowHighBack = "\033[0;103m"
|
||||||
|
var BlueHighBack = "\033[0;104m"
|
||||||
|
var PurpleHighBack = "\033[0;105m"
|
||||||
|
var CyanHighBack = "\033[0;106m"
|
||||||
|
var WhiteHighBack = "\033[0;107m"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
Reset = ""
|
||||||
|
Red = ""
|
||||||
|
Green = ""
|
||||||
|
Yellow = ""
|
||||||
|
Blue = ""
|
||||||
|
Purple = ""
|
||||||
|
Cyan = ""
|
||||||
|
LightGray = ""
|
||||||
|
DarkGray = ""
|
||||||
|
White = ""
|
||||||
|
BlackBold = ""
|
||||||
|
RedBold = ""
|
||||||
|
GreenBold = ""
|
||||||
|
YellowBold = ""
|
||||||
|
BlueBold = ""
|
||||||
|
PurpleBold = ""
|
||||||
|
CyanBold = ""
|
||||||
|
WhiteBold = ""
|
||||||
|
BlackUnderline = ""
|
||||||
|
RedUnderline = ""
|
||||||
|
GreenUnderline = ""
|
||||||
|
YellowUnderline = ""
|
||||||
|
BlueUnderline = ""
|
||||||
|
PurpleUnderline = ""
|
||||||
|
CyanUnderline = ""
|
||||||
|
WhiteUnderline = ""
|
||||||
|
BlackBackground = ""
|
||||||
|
RedBackground = ""
|
||||||
|
GreenBackground = ""
|
||||||
|
YellowBackground = ""
|
||||||
|
BlueBackground = ""
|
||||||
|
PurpleBackground = ""
|
||||||
|
CyanBackground = ""
|
||||||
|
WhiteBackground = ""
|
||||||
|
BlackHigh = ""
|
||||||
|
RedHigh = ""
|
||||||
|
GreenHigh = ""
|
||||||
|
YellowHigh = ""
|
||||||
|
BlueHigh = ""
|
||||||
|
PurpleHigh = ""
|
||||||
|
CyanHigh = ""
|
||||||
|
WhiteHigh = ""
|
||||||
|
BlackBoldHigh = ""
|
||||||
|
RedBoldHigh = ""
|
||||||
|
GreenBoldHigh = ""
|
||||||
|
YellowBoldHigh = ""
|
||||||
|
BlueBoldHigh = ""
|
||||||
|
PurpleBoldHigh = ""
|
||||||
|
CyanBoldHigh = ""
|
||||||
|
WhiteBoldHigh = ""
|
||||||
|
BlackHighBack = ""
|
||||||
|
RedHighBack = ""
|
||||||
|
GreenHighBack = ""
|
||||||
|
YellowHighBack = ""
|
||||||
|
BlueHighBack = ""
|
||||||
|
PurpleHighBack = ""
|
||||||
|
CyanHighBack = ""
|
||||||
|
WhiteHighBack = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,20 @@ const (
|
|||||||
DIAGNOSTIC = 3
|
DIAGNOSTIC = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CONSOLE = 1
|
||||||
|
FILE = 2
|
||||||
|
)
|
||||||
|
|
||||||
var LOG_LEVEL = NORMAL
|
var LOG_LEVEL = NORMAL
|
||||||
|
var LOG_TIMESTAMP = false
|
||||||
|
var LOG_OUTPUT = CONSOLE
|
||||||
|
|
||||||
|
func SetLogLevel(level int) {
|
||||||
|
if level >= NONE && level <= DIAGNOSTIC {
|
||||||
|
LOG_LEVEL = level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Print(minLevel int, a ...interface{}) (int, error) {
|
func Print(minLevel int, a ...interface{}) (int, error) {
|
||||||
if LOG_LEVEL >= minLevel {
|
if LOG_LEVEL >= minLevel {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package numbers
|
||||||
|
|
||||||
|
func Min(i1 int, a ...int) int {
|
||||||
|
min := i1
|
||||||
|
for _, i := range a {
|
||||||
|
if i < min {
|
||||||
|
min = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min
|
||||||
|
}
|
||||||
+11
-1
@@ -1,6 +1,8 @@
|
|||||||
package timer
|
package timer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"AoC2021/utils/color"
|
||||||
|
"AoC2021/utils/log"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -13,6 +15,14 @@ func Start() {
|
|||||||
|
|
||||||
func Tick() {
|
func Tick() {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
fmt.Printf("[Time taken: %s]\n", now.Sub(lastTime).String())
|
fmt.Printf(color.Yellow+"[Time taken: %s]\n"+color.Reset, now.Sub(lastTime).String())
|
||||||
lastTime = now
|
lastTime = now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TickAtLevel(logLevel int) {
|
||||||
|
if log.LOG_LEVEL >= logLevel {
|
||||||
|
now := time.Now()
|
||||||
|
log.Printf(logLevel, color.Yellow+"[Time taken: %s]\n"+color.Reset, now.Sub(lastTime).String())
|
||||||
|
lastTime = now
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user