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) }