package main import ( "bufio" "fmt" "os" "os/exec" "strconv" "strings" "time" ) var lights [][]bool func main() { ticks := -1 speed := 2 var hideSim, lockedCorners bool for i := range os.Args { if os.Args[i] == "-help" { fmt.Println("Usage: day18 [-ticks=] [-speed=]") fmt.Println("\t-ticks=\tSpecify how many iterations should be performed") fmt.Println("\t\t\t\tIf not manually set, run forever.") fmt.Println("\t-speed=\tSpecify how many times/second we iterate") fmt.Println("\t-hide\t\tHide the actual simulation (for AoC)") fmt.Println("\t-lockcorners\t\tLock the corner lights 'on' (for AoC pt 2)") os.Exit(1) } if j := strings.Index(os.Args[i], "="); j > 0 { flagKey := os.Args[i][:j] flagVal := os.Args[i][j+1:] if flagKey == "-ticks" { ticks = mustAtoi(flagVal) } else if flagKey == "-speed" { speed = mustAtoi(flagVal) } } if os.Args[i] == "-hide" { hideSim = true } if os.Args[i] == "-lockcorners" { lockedCorners = true } } if hideSim && ticks == -1 { // Doesn't make sense to run this configuration fmt.Println("You asked to run indefinitely and hide the simulation...") fmt.Println("Refusing to needlessly consume your CPU.") os.Exit(1) } var input []string scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { input = append(input, scanner.Text()) } for i := range input { var bldRow []bool for j := range input[i] { bldRow = append(bldRow, (input[i][j] == '#')) } lights = append(lights, bldRow) } if !hideSim { cls() printLights(lights) } for i := 0; i < ticks || ticks == -1; i++ { if lockedCorners { lights = lockCorners(lights) } lights = tick(lights) if lockedCorners { lights = lockCorners(lights) } if !hideSim { cls() printLights(lights) } if !hideSim { // No reason to sleep if we're hiding the simulation time.Sleep(time.Second / time.Duration(speed)) } } fmt.Println("After " + strconv.Itoa(ticks) + " ticks, " + strconv.Itoa(countLights(lights)) + " are on") } func lockCorners(c [][]bool) [][]bool { c[0][0] = true c[0][len(c[0])-1] = true c[len(c)-1][0] = true c[len(c)-1][len(c[0])-1] = true return c } func cls() { cmd := exec.Command("clear") cmd.Stdout = os.Stdout cmd.Run() } func printLights(curr [][]bool) { for i := range curr { for j := range curr { if curr[i][j] { fmt.Print("#") } else { fmt.Print(".") } } fmt.Println() } } func tick(curr [][]bool) [][]bool { var next [][]bool for i := range curr { var bldRow []bool for j := range curr[i] { num := checkNeighbors(curr, i, j) var newVal bool if curr[i][j] { // On proc if num == 2 || num == 3 { newVal = true } } else { // Off proc if num == 3 { newVal = true } } bldRow = append(bldRow, newVal) } next = append(next, bldRow) } return next } // Returns how many neighbors are on func checkNeighbors(curr [][]bool, i, j int) int { var ret int // nw if isOn(curr, (i - 1), (j - 1)) { ret++ } // n if isOn(curr, (i - 1), j) { ret++ } // ne if isOn(curr, (i - 1), (j + 1)) { ret++ } // w if isOn(curr, i, (j - 1)) { ret++ } // e if isOn(curr, i, (j + 1)) { ret++ } // sw if isOn(curr, (i + 1), (j - 1)) { ret++ } // s if isOn(curr, (i + 1), j) { ret++ } // se if isOn(curr, (i + 1), (j + 1)) { ret++ } return ret } func isOn(curr [][]bool, i, j int) bool { if i < 0 || i >= len(curr) { return false } if j < 0 || j >= len(curr[i]) { return false } return curr[i][j] } func countLights(c [][]bool) int { var ttl int for i := range c { for j := range c[i] { if c[i][j] { ttl++ } } } return ttl } func mustAtoi(s string) int { var i int var err error if i, err = strconv.Atoi(s); err != nil { fmt.Println("Tried to atoi " + s) os.Exit(1) } return i }