package main import ( "fmt" "log" "os" "strconv" ) const ( MaxInt = int(^uint(0) >> 1) MinInt = -MaxInt - 1 ) var timeMachine *TimeMachine func main() { if len(os.Args) < 2 { fmt.Println("Usage: day11 ") os.Exit(1) } timeMachine = &TimeMachine{ serial: Atoi(os.Args[1]), fuelLevels: make(map[string]int), } timeMachine.fillGrid() part1() part2() } func part1() { top := MinInt topX, topY := 0, 0 for i := 1; i < 300; i++ { for j := 1; j < 300; j++ { w := timeMachine.getSquareFuelLevel(i, j, 3) if w > top { top = w topX, topY = i, j } } } fmt.Printf("%d,%d : %d\n", topX, topY, top) fmt.Println("= Part 1 =") timeMachine.printSquare(topX, topY, 3) } func part2() { top := MinInt topX, topY, topS := 1, 1, 1 for i := 1; i <= 300; i++ { for j := 1; j <= 300; j++ { maxSize := 300 - (i - 1) if i < j { maxSize = 300 - (j - 1) } for s := 1; s <= maxSize; s++ { wrk := timeMachine.getSquareFuelLevel(i, j, s) if wrk > top { top = wrk topX, topY, topS = i, j, s } } } } fmt.Println("= Part 2 =") fmt.Printf("%d,%d,%d : %d\n", topX, topY, topS, top) } type TimeMachine struct { serial int fuelLevels map[string]int } func (t *TimeMachine) printSquare(x, y, size int) { for j := y; j < y+size; j++ { for i := x; i < x+size; i++ { fmt.Printf("%2d ", t.getSquareFuelLevel(i, j, 1)) } fmt.Println("") } } func (t *TimeMachine) fillGrid() { for i := 1; i <= 300; i++ { for j := 1; j <= 300; j++ { t.fuelLevels[t.getKeyForSquare(i, j, 1)] = t.calcFuelLevel(i, j) } } } func (t *TimeMachine) getKeyForSquare(x, y, size int) string { bx := strconv.Itoa(x) by := strconv.Itoa(y) bs := strconv.Itoa(size) return bx + "," + by + "," + bs } func (t *TimeMachine) getSquareFuelLevel(x, y, size int) int { k := t.getKeyForSquare(x, y, size) if v, ok := t.fuelLevels[k]; ok { return v } if size == 1 { // We shouldn't be here if we filled the grid before running return 0 } var ret int ret = t.getSquareFuelLevel(x, y, size-1) // Add the right-most cells for i := 0; i < size; i++ { ret += t.calcFuelLevel(x+(size-1), y+i) } // Add the bottom cells for i := 0; i < size-1; i++ { ret += t.calcFuelLevel(x+i, y+(size-1)) } t.fuelLevels[k] = ret return ret } // calcFuelLevel calculates one cells fuel level func (t *TimeMachine) calcFuelLevel(x, y int) int { rackId := x + 10 startingLevel := rackId * y currLevel := startingLevel + t.serial currLevel *= rackId var ret int if currLevel < 100 { ret = -5 } else { ret = ((currLevel / 100) % 10) - 5 } return ret } // calcSquareFuelLevel calculates all cells from x, y -> x+size, y+size func (t *TimeMachine) calcSquareFuelLevel(x, y, size int) int { var ret int for i := 0; i < size; i++ { for j := 0; j < size; j++ { ret += t.calcFuelLevel(x+i, y+j) } } return ret } func Atoi(i string) int { var ret int var err error if ret, err = strconv.Atoi(i); err != nil { log.Fatal("Invalid Atoi") } return ret }