212 lines
3.8 KiB
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
|
||
|
}
|