2020-day24: hex coordinates are tough. 1240/668

This commit is contained in:
alexchao26
2020-12-24 00:45:35 -05:00
parent f78cd9fb07
commit 46a418393c
2 changed files with 149 additions and 42 deletions
+120 -23
View File
@@ -15,32 +15,129 @@ func main() {
flag.Parse()
fmt.Println("Running part", part)
if part == 1 {
ans := part1(util.ReadFile("./input.txt"))
util.CopyToClipboard(fmt.Sprintf("%v", ans))
fmt.Println("Output:", ans)
} else {
ans := part2(util.ReadFile("./input.txt"))
util.CopyToClipboard(fmt.Sprintf("%v", ans))
fmt.Println("Output:", ans)
ans := part1(util.ReadFile("./input.txt"), part)
fmt.Println("Output:", ans)
}
// 1240/668
func part1(input string, part int) int {
instructions := strings.Split(input, "\n")
tileIsBlack := map[[6]int]bool{}
for _, inst := range instructions {
// tally the steps taken in each of the hex directions
var tallyDirections [6]int
// iterate thorugh the NONDELIMITED instructions
for i := 0; i < len(inst); {
// set the direction to the next two characters if possible
dir := string(inst[i])
if i+2 <= len(inst) {
dir = inst[i : i+2]
}
// if the two character direction is se, sw, nw or ne, both characters
// must be used, because using one is invalid ("n" or "s")
switch dir {
case "se", "sw", "nw", "ne":
tallyDirections[dirIndices[dir]]++
i += 2
default:
tallyDirections[dirIndices[dir[0:1]]]++
i++
}
// collapse and directions that cancel out, such as sw/nw -> w
tallyDirections = zeroOutHexDirections(tallyDirections)
}
// flip that tile
tileIsBlack[tallyDirections] = !tileIsBlack[tallyDirections]
}
}
func part1(input string) int {
parsed := parseInput(input)
_ = parsed
// for part 2, play game of life 100 times
if part == 2 {
for i := 0; i < 100; i++ {
// flip based on neighbors
nextState := map[[6]int]bool{}
return 0
}
// collect all coordinates to check
toCheck := map[[6]int]bool{}
for i := 0; i < 6; i++ {
for k := range tileIsBlack {
k[i]++
toCheck[zeroOutHexDirections(k)] = true
}
}
func part2(input string) int {
return 0
}
func parseInput(input string) (ans []int) {
lines := strings.Split(input, "\n")
for _, l := range lines {
ans = append(ans, mathutil.StrToInt(l))
for coord := range toCheck {
// count neighbors
var neighbors int
for i := 0; i < 6; i++ {
clone := coord // don't want to modify the original coord
clone[i]++ // generates the six directions around coord
clone = zeroOutHexDirections(clone)
if tileIsBlack[clone] {
neighbors++
}
}
// flipping logic:
// back with zero or more than 2 neighbors becomes white
if tileIsBlack[coord] && (neighbors == 0 || neighbors > 2) {
nextState[coord] = false
} else if !tileIsBlack[coord] && neighbors == 2 {
// white with exactly 2 neighbors becomes black
nextState[coord] = true
} else {
// stays the same
nextState[coord] = tileIsBlack[coord]
}
}
tileIsBlack = nextState
}
}
return ans
var count int
for _, b := range tileIsBlack {
if b {
count++
}
}
return count
}
var dirIndices = map[string]int{
"e": 0,
"se": 1,
"sw": 2,
"w": 3,
"nw": 4,
"ne": 5,
}
// borrowed from my 2017 day 11 code which calculated hex coordinate manhattan distances
func zeroOutHexDirections(tally [6]int) [6]int {
// zero out opposite indices
for i := range tally {
if tally[i] != 0 {
oppositeIndex := (i + 3) % 6
smaller := mathutil.MinInt(tally[oppositeIndex], tally[i])
tally[oppositeIndex] -= smaller
tally[i] -= smaller
}
}
// handle neighbors which collapse into the current direction
// e.g. sw,se == s
for i := range tally {
toLeft := (i + 5) % 6
toRight := (i + 1) % 6
if tally[toLeft] > 0 && tally[toRight] > 0 {
smaller := mathutil.MinInt(tally[toLeft], tally[toRight])
tally[toLeft] -= smaller
tally[toRight] -= smaller
tally[i] += smaller
}
}
return tally
}
+29 -19
View File
@@ -2,38 +2,48 @@ package main
import (
"testing"
"github.com/alexchao26/advent-of-code-go/util"
)
var example = `sesenwnenenewseeswwswswwnenewsewsw
neeenesenwnwwswnenewnwwsewnenwseswesw
seswneswswsenwwnwse
nwnwneseeswswnenewneswwnewseswneseene
swweswneswnenwsewnwneneseenw
eesenwseswswnenwswnwnwsewwnwsene
sewnenenenesenwsewnenwwwse
wenwwweseeeweswwwnwwe
wsweesenenewnwwnwsenewsenwwsesesenwne
neeswseenwwswnwswswnw
nenwswwsewswnenenewsenwsenwnesesenew
enewnwewneswsewnwswenweswnenwsenwsw
sweneswneswneneenwnewenewwneswswnese
swwesenesewenwneswnwwneseswwne
enesenwswwswneneswsenwnewswseenwsese
wnwnesenesenenwwnenwsewesewsesesew
nenewswnwewswnenesenwnesewesw
eneswnwswnwsenenwnwnwwseeswneewsenese
neswnwewnwnwseenwseesewsenwsweewe
wseweeenwnesenwwwswnew`
func Test_part1(t *testing.T) {
tests := []struct {
name string
input string
part int
want int
}{
// {"actual", util.ReadFile("input.txt"), ACTUAL_ANSWER},
{"part1_example", example, 1, 10},
{"part1_actual", util.ReadFile("input.txt"), 1, 277},
{"part2_example", example, 2, 2208},
{"part2_actual", util.ReadFile("input.txt"), 2, 3531},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := part1(tt.input); got != tt.want {
if got := part1(tt.input, tt.part); got != tt.want {
t.Errorf("part1() = %v, want %v", got, tt.want)
}
})
}
}
func Test_part2(t *testing.T) {
tests := []struct {
name string
input string
want int
}{
// {"actual", util.ReadFile("input.txt"), ACTUAL_ANSWER},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := part2(tt.input); got != tt.want {
t.Errorf("part2() = %v, want %v", got, tt.want)
}
})
}
}