adventofcode/2015/day18/main.go

212 lines
3.8 KiB
Go

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=<num>] [-speed=<num>]")
fmt.Println("\t-ticks=<num>\tSpecify how many iterations should be performed")
fmt.Println("\t\t\t\tIf not manually set, run forever.")
fmt.Println("\t-speed=<num>\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
}