diff --git a/2017/day10/main.go b/2017/day10/main.go new file mode 100644 index 0000000..6ba0f7c --- /dev/null +++ b/2017/day10/main.go @@ -0,0 +1,116 @@ +package main + +import ( + "flag" + "fmt" + "strings" + + "github.com/alexchao26/advent-of-code-go/mathutil" + "github.com/alexchao26/advent-of-code-go/util" +) + +func main() { + var part int + flag.IntVar(&part, "part", 1, "part 1 or 2") + flag.Parse() + fmt.Println("Running part", part) + + if part == 1 { + ans := part1(util.ReadFile("./input.txt"), 256) + fmt.Println("Output:", ans) + } else { + ans := part2(util.ReadFile("./input.txt")) + fmt.Println("Output:", ans) + } +} + +func part1(input string, listLength int) int { + lengths := parseInput(input) + + nums := make([]int, listLength) + for i := range nums { + nums[i] = i + } + var position, skipSize int + for _, length := range lengths { + if length > 0 { + nums = reverse(nums, position, position+length-1) + } + position += skipSize + length + position %= len(nums) + skipSize++ + } + + return nums[0] * nums[1] +} + +func part2(input string) string { + lengths := parseInputASCII(input) + nums := make([]int, 256) + for i := range nums { + nums[i] = i + } + var position, skipSize int + + for round := 0; round < 64; round++ { + for _, length := range lengths { + if length > 0 { + nums = reverse(nums, position, position+length-1) + } + position += skipSize + length + position %= len(nums) + skipSize++ + } + } + + var denseHash []int + for i := 0; i < 16; i++ { + var xord int + for j := i * 16; j < (i+1)*16; j++ { + xord ^= nums[j] + } + denseHash = append(denseHash, xord) + } + + var hexdHash string + for _, dense := range denseHash { + // use %x to get hexadecimal version & 02 ensures leading 0 if needed + hexdHash += fmt.Sprintf("%02x", dense) + } + + return hexdHash +} + +func reverse(nums []int, left, right int) []int { + right %= len(nums) + if right < left { + right += len(nums) + } + + for left < right { + leftModded := left % len(nums) + rightModded := right % len(nums) + nums[leftModded], nums[rightModded] = nums[rightModded], nums[leftModded] + left++ + right-- + } + + return nums +} + +func parseInput(input string) (ans []int) { + nums := strings.Split(input, ",") + for _, num := range nums { + ans = append(ans, mathutil.StrToInt(num)) + } + return ans +} + +func parseInputASCII(input string) (ans []int) { + for _, char := range input { + ans = append(ans, int(char)) + } + // add default lengths to end + ans = append(ans, 17, 31, 73, 47, 23) + return ans +} diff --git a/2017/day10/main_test.go b/2017/day10/main_test.go new file mode 100644 index 0000000..32f6c8a --- /dev/null +++ b/2017/day10/main_test.go @@ -0,0 +1,44 @@ +package main + +import ( + "testing" + + "github.com/alexchao26/advent-of-code-go/util" +) + +func Test_part1(t *testing.T) { + tests := []struct { + name string + input string + listLength int + want int + }{ + {"example", "3,4,1,5", 5, 12}, + {"actual", util.ReadFile("input.txt"), 256, 212}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part1(tt.input, tt.listLength); 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 string + }{ + {"example", "1,2,3", "3efbe78a8d82f29979031a4aa0b16a9d"}, + {"actual", util.ReadFile("input.txt"), "96de9657665675b51cd03f0b3528ba26"}, + } + 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) + } + }) + } +} diff --git a/2020/day15/main.go b/2020/day15/main.go index bde80ba..b3ffce7 100644 --- a/2020/day15/main.go +++ b/2020/day15/main.go @@ -15,32 +15,47 @@ func main() { flag.Parse() fmt.Println("Running part", part) + var ans int if part == 1 { - ans := part1(util.ReadFile("./input.txt")) - util.CopyToClipboard(fmt.Sprintf("%v", ans)) - fmt.Println("Output:", ans) + ans = rambunctiousRecitation(util.ReadFile("./input.txt"), 2020) } else { - ans := part2(util.ReadFile("./input.txt")) - util.CopyToClipboard(fmt.Sprintf("%v", ans)) - fmt.Println("Output:", ans) + // brute force, takes ~5seconds to run + ans = rambunctiousRecitation(util.ReadFile("./input.txt"), 30000000) } + fmt.Println("Output:", ans) } -func part1(input string) int { - parsed := parseInput(input) - _ = parsed - - return 0 -} - -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)) +func rambunctiousRecitation(input string, turnToReturn int) int { + var startingNums []int + for _, num := range strings.Split(input, ",") { + startingNums = append(startingNums, mathutil.StrToInt(num)) } - return ans + + said := map[int][]int{} + var numSaidLast int + // populate the starting map with the numbers from the input + for i, num := range startingNums { + said[num] = append(said[num], i+1) + numSaidLast = num + } + + // then picking up from the next turn (len of input), continue until the + // desired turn is reached + for i := len(startingNums); i <= turnToReturn; i++ { + indexSlice := said[numSaidLast] + // if the length of the slice of incides is 1, that means it was only + // called once. Say zero, add to the zero slice of indices + if len(indexSlice) == 1 { + numSaidLast = 0 + said[0] = append(said[0], i) + } else { + // otherwise determine the diff between the last 2 times it was said + length := len(indexSlice) + numSaidLast = indexSlice[length-1] - indexSlice[length-2] + // add this index i to the indices slice for the number that is said + said[numSaidLast] = append(said[numSaidLast], i) + } + } + + return numSaidLast } diff --git a/2020/day15/main_test.go b/2020/day15/main_test.go index 22a4487..5bc8d4f 100644 --- a/2020/day15/main_test.go +++ b/2020/day15/main_test.go @@ -2,38 +2,28 @@ package main import ( "testing" + "time" + + "github.com/alexchao26/advent-of-code-go/util" ) -func Test_part1(t *testing.T) { +func Test_rambunctiousRecitation(t *testing.T) { tests := []struct { - name string - input string - want int + name string + input string + desiredStep int + want int }{ - // {"actual", util.ReadFile("input.txt"), ACTUAL_ANSWER}, + {"actual", util.ReadFile("input.txt"), 2020, 1259}, + {"actual", util.ReadFile("input.txt"), 30000000, 689}, } 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) - } - }) - } -} - -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) + startTime := time.Now() + if got := rambunctiousRecitation(tt.input, tt.desiredStep); got != tt.want { + t.Errorf("rambunctiousRecitation() = %v, want %v", got, tt.want) } + t.Log("Op time: ", time.Since(startTime)) }) } }