adventofcode/2018/day12/day12.go

275 lines
4.2 KiB
Go
Raw Normal View History

2018-12-12 17:44:28 +00:00
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
2018-12-12 22:55:33 +00:00
const (
MaxInt = int(^uint(0) >> 1)
MinInt = -MaxInt - 1
)
var lastState string
var garden *Garden
2018-12-12 17:44:28 +00:00
func main() {
inp := StdinToStringSlice()
2018-12-12 22:55:33 +00:00
garden = NewGarden(strings.Trim(inp[0], "intalsae: "), 0)
2018-12-12 17:44:28 +00:00
for _, v := range inp[2:] {
2018-12-12 22:55:33 +00:00
garden.transitions = append(garden.transitions, NewTransition(v))
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
generations := 50000000000
var i int
for i = 0; i < generations; i++ {
lastState = garden.string()
garden = garden.tick()
if garden.string() == lastState {
i++
break
}
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
garden.shiftPots(generations - i)
fmt.Println(garden.sum())
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
/**
* A Garden
*/
type Garden struct {
pots []*Pot
transitions []*Transition
}
func NewGarden(inp string, start int) *Garden {
g := &Garden{}
for k, v := range inp {
p := &Pot{
id: k + start,
value: rb(v),
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
g.pots = append(g.pots, p)
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
return g
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
func (g *Garden) shiftPots(val int) {
for i := range g.pots {
g.pots[i].id = g.pots[i].id + val
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
}
func (g *Garden) sum() int64 {
var ret int64
st, ed := g.getStartIndex(), g.getEndIndex()
for i := st; i <= ed; i++ {
if g.getPot(i).value {
ret += int64(i)
2018-12-12 17:44:28 +00:00
}
}
return ret
}
2018-12-12 22:55:33 +00:00
func (g *Garden) tick() *Garden {
earliest, latest := g.getStartIndex(), g.getEndIndex()
st := earliest - 2
ed := latest + 2
ret := &Garden{
transitions: g.transitions,
}
for i := st; i <= ed; i++ {
next := g.getNextStateForPot(i)
if next {
ret.pots = append(ret.pots, &Pot{
id: i,
value: next,
})
}
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
return ret
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
func (g *Garden) getNextStateForPot(id int) bool {
2018-12-12 17:44:28 +00:00
var ret byte
2018-12-12 22:55:33 +00:00
for i := id - 2; i <= id+2; i++ {
2018-12-12 17:44:28 +00:00
ret = ret << 1
2018-12-12 22:55:33 +00:00
if g.getPot(i).value {
2018-12-12 17:44:28 +00:00
ret = ret | 1
}
}
2018-12-12 22:55:33 +00:00
for _, v := range g.transitions {
if v.GetValue() == ret {
return v.next
}
}
return false //g.getPot(id).value
}
func (g *Garden) substring(st, ed int) string {
var ret string
for i := st; i <= ed; i++ {
ret += g.getPot(i).string()
}
2018-12-12 17:44:28 +00:00
return ret
}
2018-12-12 22:55:33 +00:00
func (g *Garden) string() string {
var ret string
for i := g.getStartIndex(); i <= g.getEndIndex(); i++ {
ret += g.getPot(i).string()
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
return ret
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
func (g *Garden) transitionStrings() string {
2018-12-12 17:44:28 +00:00
var ret string
2018-12-12 22:55:33 +00:00
for _, v := range g.transitions {
ret = ret + v.string() + "\n"
2018-12-12 17:44:28 +00:00
}
return ret
}
2018-12-12 22:55:33 +00:00
func (g *Garden) getStartIndex() int {
min := MaxInt
for _, v := range g.pots {
if v.id < min {
min = v.id
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
}
return min
}
func (g *Garden) getEndIndex() int {
max := MinInt
for _, v := range g.pots {
if v.id > max {
max = v.id
2018-12-12 17:44:28 +00:00
}
}
2018-12-12 22:55:33 +00:00
return max
}
func (g *Garden) getPot(idx int) *Pot {
for _, v := range g.pots {
if v.id == idx {
return v
2018-12-12 17:44:28 +00:00
}
}
2018-12-12 22:55:33 +00:00
return &Pot{
id: idx,
value: false,
}
}
/**
* A Pot
*/
type Pot struct {
id int
value bool
}
func (p *Pot) string() string {
return bs(p.value)
2018-12-12 17:44:28 +00:00
}
2018-12-12 22:55:33 +00:00
/**
* Transitions
*/
2018-12-12 17:44:28 +00:00
type Transition struct {
state []bool
next bool
}
func NewTransition(inp string) *Transition {
var state []bool
var next bool
pts := strings.Split(inp, " => ")
2018-12-12 22:55:33 +00:00
for i := range pts[0] {
2018-12-12 17:44:28 +00:00
state = append(state, bb(pts[0][i]))
}
2018-12-12 22:55:33 +00:00
//for i := len(pts[0]) - 1; i >= 0; i-- {
// state = append(state, bb(pts[0][i]))
//}
2018-12-12 17:44:28 +00:00
next = bb(pts[1][0])
t := &Transition{
state: state,
next: next,
}
return t
}
2018-12-12 22:55:33 +00:00
func (t *Transition) string() string {
var ret string
for _, v := range t.state {
ret += bs(v)
}
return ret + " => " + bs(t.next)
}
2018-12-12 17:44:28 +00:00
func (t *Transition) GetValue() byte {
var ret byte
for _, v := range t.state {
ret = ret << 1
if v {
ret = ret | 1
}
}
return ret
}
2018-12-12 22:55:33 +00:00
/**
* Helper Functions
*/
// Take a byte and return a string representation of the bits
func byteToString(b byte) string {
var ret string
for i := 0; i < 8; i++ {
if b&1 == 1 {
ret += "#"
} else {
ret += "."
}
b = b >> 1
}
return ret
}
// Take a string representation of a bits and return the byte
func stringToByte(n string) byte {
var b byte
for i := range n {
if n[i] == '#' {
b = b | 1
}
b = b << 1
}
return b
}
func bs(b bool) string {
if b {
return "#"
}
return "."
}
2018-12-12 17:44:28 +00:00
func rb(r rune) bool {
return bb(byte(r))
}
func bb(b byte) bool {
return b == '#'
}
func StdinToStringSlice() []string {
var input []string
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
input = append(input, scanner.Text())
}
return input
}