2018 day 18 Done
This commit is contained in:
202
2018/day18/day18.go
Normal file
202
2018/day18/day18.go
Normal file
@@ -0,0 +1,202 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DIR_N = -1i
|
||||
DIR_NE = 1 - 1i
|
||||
DIR_E = 1
|
||||
DIR_SE = 1 + 1i
|
||||
DIR_S = 1i
|
||||
DIR_SW = -1 + 1i
|
||||
DIR_W = -1
|
||||
DIR_NW = -1 - 1i
|
||||
|
||||
CLEAR_SCREEN = "\033[H\033[2J"
|
||||
)
|
||||
|
||||
var scan []byte
|
||||
var next []byte
|
||||
var prevScans [][]byte
|
||||
var width, height int
|
||||
|
||||
func main() {
|
||||
stdinToByteSlice()
|
||||
part1()
|
||||
part2()
|
||||
}
|
||||
|
||||
func part1() {
|
||||
printScan()
|
||||
for i := 0; i < 10; i++ {
|
||||
fmt.Print(CLEAR_SCREEN)
|
||||
scan = tickToNext()
|
||||
printScan()
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
}
|
||||
var ttlOpen, ttlTrees, ttlLmbr int
|
||||
for i := range scan {
|
||||
switch getByte(getPosFromInt(i)) {
|
||||
case '.':
|
||||
ttlOpen++
|
||||
case '|':
|
||||
ttlTrees++
|
||||
case '#':
|
||||
ttlLmbr++
|
||||
}
|
||||
}
|
||||
_ = ttlOpen
|
||||
fmt.Println("= Part 1 =")
|
||||
fmt.Println(ttlTrees * ttlLmbr)
|
||||
}
|
||||
|
||||
// 191080?
|
||||
func part2() {
|
||||
var isDupe bool
|
||||
var i int
|
||||
target := 1000000000
|
||||
for i = 0; i < target; i++ {
|
||||
//fmt.Print(CLEAR_SCREEN, target)
|
||||
next := tickToNext()
|
||||
if isDupe, prevScans = checkDuplicateState(next, prevScans); isDupe {
|
||||
i++
|
||||
scan = next
|
||||
break
|
||||
}
|
||||
prevScans = append(prevScans, next)
|
||||
scan = next
|
||||
}
|
||||
// We need to find the state after `target` increments
|
||||
scan = prevScans[(target-i)%len(prevScans)]
|
||||
var ttlOpen, ttlTrees, ttlLmbr int
|
||||
for i := range scan {
|
||||
switch getByte(getPosFromInt(i)) {
|
||||
case '.':
|
||||
ttlOpen++
|
||||
case '|':
|
||||
ttlTrees++
|
||||
case '#':
|
||||
ttlLmbr++
|
||||
}
|
||||
}
|
||||
_ = ttlOpen
|
||||
fmt.Println("= Part 2 =")
|
||||
fmt.Println(ttlTrees * ttlLmbr)
|
||||
}
|
||||
|
||||
// checkDuplicateState returns the slice of prev that has all remaining available states
|
||||
func checkDuplicateState(s []byte, prev [][]byte) (bool, [][]byte) {
|
||||
for i, v := range prev {
|
||||
if areasAreEqual(s, v) {
|
||||
return true, prev[i:]
|
||||
}
|
||||
}
|
||||
return false, prev
|
||||
}
|
||||
|
||||
func areasAreEqual(a1, a2 []byte) bool {
|
||||
for i := range a1 {
|
||||
if a1[i] != a2[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func tickToNext() []byte {
|
||||
var ret []byte
|
||||
for i := 0; i < len(scan); i++ {
|
||||
c := getPosFromInt(i)
|
||||
_, sTree, sLmbr := getSurroundingCounts(c)
|
||||
b := getByte(c)
|
||||
switch b {
|
||||
case '.':
|
||||
if sTree >= 3 {
|
||||
ret = append(ret, '|')
|
||||
} else {
|
||||
ret = append(ret, '.')
|
||||
}
|
||||
case '|':
|
||||
if sLmbr >= 3 {
|
||||
ret = append(ret, '#')
|
||||
} else {
|
||||
ret = append(ret, '|')
|
||||
}
|
||||
case '#':
|
||||
if sLmbr > 0 && sTree > 0 {
|
||||
ret = append(ret, '#')
|
||||
} else {
|
||||
ret = append(ret, '.')
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// getSurroundingCounts takes a pos and returns:
|
||||
// Number of open areas
|
||||
// Number of trees
|
||||
// Number of lumberyards
|
||||
// Surrounding that spot
|
||||
func getSurroundingCounts(c complex64) (int, int, int) {
|
||||
var sOpen, sTree, sLmbr int
|
||||
for _, v := range []complex64{DIR_NW, DIR_N, DIR_NE, DIR_W, DIR_E, DIR_SW, DIR_S, DIR_SE} {
|
||||
switch getByte(c + v) {
|
||||
case '.':
|
||||
sOpen++
|
||||
case '|':
|
||||
sTree++
|
||||
case '#':
|
||||
sLmbr++
|
||||
}
|
||||
}
|
||||
return sOpen, sTree, sLmbr
|
||||
}
|
||||
|
||||
func printScan() {
|
||||
for i := 0; i < len(scan)/width; i++ {
|
||||
fmt.Println(string(scan[i*width : (i+1)*width]))
|
||||
}
|
||||
}
|
||||
|
||||
// getByte pulls a byte from the given position in the scan
|
||||
func getByte(pos complex64) byte {
|
||||
//idx := int(real(pos)) + int(imag(pos))*width
|
||||
if int(real(pos)) < 0 || int(imag(pos)) < 0 || int(real(pos)) >= width || int(imag(pos)) >= height {
|
||||
return 0
|
||||
}
|
||||
return scan[int(real(pos))+int(imag(pos))*width]
|
||||
}
|
||||
|
||||
func getPosComplex(x, y int) complex64 {
|
||||
return complex(float32(x), float32(y))
|
||||
}
|
||||
|
||||
func getPosFromInt(i int) complex64 {
|
||||
return complex(float32(i%width), float32(i/width))
|
||||
}
|
||||
|
||||
func getIdxFromPos(pos complex64) int {
|
||||
return int(real(pos)) + int(imag(pos))*width
|
||||
}
|
||||
|
||||
func getCoordString(p complex64) string {
|
||||
return fmt.Sprintf("(%d,%d [%d])", int(real(p)), int(imag(p)), getIdxFromPos(p))
|
||||
}
|
||||
|
||||
func stdinToByteSlice() {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for scanner.Scan() {
|
||||
s := scanner.Bytes()
|
||||
if width == 0 {
|
||||
width = len(s)
|
||||
}
|
||||
scan = append(scan, s...)
|
||||
height++
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user