diff --git a/2017/day25/main.go b/2017/day25/main.go new file mode 100644 index 0000000..9ef1746 --- /dev/null +++ b/2017/day25/main.go @@ -0,0 +1,74 @@ +package main + +import ( + "fmt" + "strings" + + "github.com/alexchao26/advent-of-code-go/mathutil" + "github.com/alexchao26/advent-of-code-go/util" +) + +func main() { + ans := part1(util.ReadFile("./input.txt")) + fmt.Println("Output:", ans) +} + +func part1(input string) int { + steps, stateRules := parseInput(input) + + // lazy, use a huge array and just start in the middle + bigArray := make([]int, steps) + index := steps / 2 + currentStateName := "A" + + for i := 0; i < steps; i++ { + currentVal := bigArray[index] + rulesToFollow := stateRules[currentStateName][currentVal] + // write + bigArray[index] = rulesToFollow.valToWrite + if rulesToFollow.direction == "left" { + index-- + } else { + index++ + } + currentStateName = rulesToFollow.nextState + } + + return mathutil.SumIntSlice(bigArray) +} + +type ruleset struct { + name string // for debugging only + valToWrite int + direction string + nextState string +} + +// assume all programs start in state A for now, one less thing to parse... +func parseInput(input string) (steps int, states map[string][2]ruleset) { + // a manual parse here would be faster... + blocks := strings.Split(input, "\n\n") + + fmt.Sscanf(strings.Split(blocks[0], "\n")[1], "Perform a diagnostic checksum after %d steps.", &steps) + + states = map[string][2]ruleset{} + for _, block := range blocks[1:] { + lines := strings.Split(block, "\n") + var stateName string + fmt.Sscanf(lines[0], "In state %1s:", &stateName) + + rulesIfZero := ruleset{name: stateName} + fmt.Sscanf(strings.Trim(lines[2], " -."), "Write the value %d", &rulesIfZero.valToWrite) + fmt.Sscanf(strings.Trim(lines[3], " -."), "Move one slot to the %s", &rulesIfZero.direction) + fmt.Sscanf(strings.Trim(lines[4], " -."), "Continue with state %1s", &rulesIfZero.nextState) + + rulesIfOne := ruleset{name: stateName} + fmt.Sscanf(strings.Trim(lines[6], " -."), "Write the value %d", &rulesIfOne.valToWrite) + fmt.Sscanf(strings.Trim(lines[7], " -."), "Move one slot to the %s", &rulesIfOne.direction) + fmt.Sscanf(strings.Trim(lines[8], " -."), "Continue with state %1s", &rulesIfOne.nextState) + + states[stateName] = [2]ruleset{rulesIfZero, rulesIfOne} + } + + return steps, states +} diff --git a/2017/day25/main_test.go b/2017/day25/main_test.go new file mode 100644 index 0000000..0e53bb9 --- /dev/null +++ b/2017/day25/main_test.go @@ -0,0 +1,48 @@ +package main + +import ( + "testing" + + "github.com/alexchao26/advent-of-code-go/util" +) + +var example = `Begin in state A. +Perform a diagnostic checksum after 6 steps. + +In state A: + If the current value is 0: + - Write the value 1. + - Move one slot to the right. + - Continue with state B. + If the current value is 1: + - Write the value 0. + - Move one slot to the left. + - Continue with state B. + +In state B: + If the current value is 0: + - Write the value 1. + - Move one slot to the left. + - Continue with state A. + If the current value is 1: + - Write the value 1. + - Move one slot to the right. + - Continue with state A.` + +func Test_part1(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + {"example", example, 3}, + {"actual", util.ReadFile("input.txt"), 5744}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part1(tt.input); got != tt.want { + t.Errorf("part1() = %v, want %v", got, tt.want) + } + }) + } +}