adventofcode/2016/day11/main.go

158 lines
3.9 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"time"
"github.com/fatih/color"
)
// This is a purely mathematical solution to this problem
// We don't care about what the elements are.
// Loop on each floor and consider:
// 1: We have less than 3 items on the floor
// So move them all up; 1 total move
// 2: We have more than 3 items on the floor
// So move two up and one back down; 2 total moves
// Setting visual to true will output what's happening
var visual bool
func main() {
input := stdinToStringSlice()
var numMoves int
if !visual {
var lvlItmCnts []int
for i := range input {
lvlItmCnts = append(lvlItmCnts, strings.Count(input[i], "generator")+strings.Count(input[i], "microchip"))
}
for i := 0; i < 3; i++ {
for lvlItmCnts[i] > 0 {
if lvlItmCnts[i] < 3 {
lvlItmCnts[i+1] = lvlItmCnts[i+1] + lvlItmCnts[i]
lvlItmCnts[i] = 0
numMoves++
} else {
lvlItmCnts[i] = lvlItmCnts[i] - 1
lvlItmCnts[i+1] = lvlItmCnts[i+1] + 1
numMoves = numMoves + 2
}
}
}
} else {
// Visual mode spits a lot more stuff out, so it has
// to track a lot more things...
numMoves = VisualMode(input)
}
fmt.Println("Number of moves:", numMoves)
}
func VisualMode(input []string) int {
// This code requires oxford commas in the input :)
var elevatorFloor int
var floorInv [][]string
var componentRegistry []string
for i := range input {
listIdx := strings.Index(input[i], "a ")
if listIdx == -1 {
floorInv = append(floorInv, []string{})
continue
}
input[i] = input[i][listIdx:]
floorInv = append(floorInv, strings.Split(input[i], ", "))
}
for i := range floorInv {
elevatorFloor = i
for j := range floorInv[i] {
tp := "G"
if strings.Contains(floorInv[i][j], "microchip") {
tp = "M"
}
floorInv[i][j] = strings.TrimPrefix(floorInv[i][j], "a ")
floorInv[i][j] = strings.TrimPrefix(floorInv[i][j], "and a ")
ele := strings.ToUpper(floorInv[i][j][:2])
floorInv[i][j] = ele + ":" + tp
componentRegistry = append(componentRegistry, floorInv[i][j])
}
}
var numMoves int
var pt1, pt2 string
for i := 0; i < len(floorInv)-1; i++ {
for len(floorInv[i]) > 1 {
if len(floorInv[i]) > 1 {
// If there are exactly two items on the floor, move them up
if len(floorInv[i]) == 2 {
pt1, pt2, floorInv[i] = floorInv[i][0], floorInv[i][1], floorInv[i][2:]
floorInv[i+1] = append(floorInv[i+1], pt1, pt2)
numMoves++
} else if len(floorInv[i]) > 2 {
// If more than two, move one up, but add 2 to the move
// To simulate, moving two up then one back down
pt1, floorInv[i] = floorInv[i][0], floorInv[i][1:]
floorInv[i+1] = append(floorInv[i+1], pt1)
numMoves = numMoves + 2
}
} else {
// Only one left on floor, move it up
pt1, floorInv[i] = floorInv[i][0], []string{}
floorInv[i+1] = append(floorInv[i+1], pt1, pt2)
numMoves++
}
if visual {
ClearScreen()
PrintScreen(floorInv, elevatorFloor, componentRegistry)
time.Sleep(time.Millisecond * 250)
}
}
}
return numMoves
}
func ClearScreen() {
fmt.Print("\033[H\033[2J")
}
func PrintScreen(floorInv [][]string, elevatorFloor int, componentRegistry []string) {
c := color.New(color.FgCyan)
w := color.New(color.FgWhite)
for i := len(floorInv); i > 0; i-- {
c.Printf("F%d ", i)
if elevatorFloor == i-1 {
c.Print("E ")
} else {
w.Print(". ")
}
for cr := range componentRegistry {
var fnd bool
for j := range floorInv[i-1] {
if floorInv[i-1][j] == componentRegistry[cr] {
fnd = true
fmt.Print(componentRegistry[cr] + " ")
break
}
}
if !fnd {
fmt.Print(". ")
}
}
fmt.Println()
}
}
func stdinToStringSlice() []string {
var input []string
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
input = append(input, scanner.Text())
}
return input
}
func itoa(i int) string {
return strconv.Itoa(i)
}