Day 9
This commit is contained in:
parent
9031a9ec92
commit
987ab2f739
11 changed files with 451 additions and 27 deletions
54
.github/README.md
vendored
54
.github/README.md
vendored
|
@ -14,33 +14,33 @@ Puzzle inputs and descriptions are not included in this repository. You'll have
|
|||
|
||||
<!-- PARSE START -->
|
||||
|
||||
| Day | | Python | Go |
|
||||
| --------------------------- | ----------------------------- | ------------------------------------- | --------------------------------- |
|
||||
| [1](/01-reportRepair) | ![Completed][check] | [Link](/01-reportRepair/python) | [Link](/01-reportRepair/go) |
|
||||
| [2](/02-passwordPhilosophy) | ![Completed][check] | [Link](/02-passwordPhilosophy/python) | [Link](/02-passwordPhilosophy/go) |
|
||||
| [3](/03-tobogganTrajectory) | ![Completed][check] | [Link](/03-tobogganTrajectory/python) | [Link](/03-tobogganTrajectory/go) |
|
||||
| [4](/04-passportProcessing) | ![Completed][check] | [Link](/04-passportProcessing/python) | [Link](/04-passportProcessing/go) |
|
||||
| [5](/05-binaryBoarding) | ![Completed][check] | [Link](/05-binaryBoarding/python) | [Link](/05-binaryBoarding/go) |
|
||||
| [6](/06-customCustoms) | ![Completed][check] | [Link](/06-customCustoms/python) | [Link](/06-customCustoms/go) |
|
||||
| [7](/07-handyHaversacks) | ![Completed][check] | [Link](/07-handyHaversacks/python) | [Link](/07-handyHaversacks/go) |
|
||||
| [8](/08-handheldHalting) | ![Completed][check] | [Link](/08-handheldHalting/python) | [Link](/08-handheldHalting/go) |
|
||||
| 9 | ![Not yet attempted][pending] | | |
|
||||
| 10 | | | |
|
||||
| 11 | | | |
|
||||
| 12 | | | |
|
||||
| 13 | | | |
|
||||
| 14 | | | |
|
||||
| 15 | | | |
|
||||
| 16 | | | |
|
||||
| 17 | | | |
|
||||
| 18 | | | |
|
||||
| 19 | | | |
|
||||
| 20 | | | |
|
||||
| 21 | | | |
|
||||
| 22 | | | |
|
||||
| 23 | | | |
|
||||
| 24 | | | |
|
||||
| 25 | | | |
|
||||
| Day | | Python | Go |
|
||||
| --------------------------- | ------------------- | ------------------------------------- | --------------------------------- |
|
||||
| [1](/01-reportRepair) | ![Completed][check] | [Link](/01-reportRepair/python) | [Link](/01-reportRepair/go) |
|
||||
| [2](/02-passwordPhilosophy) | ![Completed][check] | [Link](/02-passwordPhilosophy/python) | [Link](/02-passwordPhilosophy/go) |
|
||||
| [3](/03-tobogganTrajectory) | ![Completed][check] | [Link](/03-tobogganTrajectory/python) | [Link](/03-tobogganTrajectory/go) |
|
||||
| [4](/04-passportProcessing) | ![Completed][check] | [Link](/04-passportProcessing/python) | [Link](/04-passportProcessing/go) |
|
||||
| [5](/05-binaryBoarding) | ![Completed][check] | [Link](/05-binaryBoarding/python) | [Link](/05-binaryBoarding/go) |
|
||||
| [6](/06-customCustoms) | ![Completed][check] | [Link](/06-customCustoms/python) | [Link](/06-customCustoms/go) |
|
||||
| [7](/07-handyHaversacks) | ![Completed][check] | [Link](/07-handyHaversacks/python) | [Link](/07-handyHaversacks/go) |
|
||||
| [8](/08-handheldHalting) | ![Completed][check] | [Link](/08-handheldHalting/python) | [Link](/08-handheldHalting/go) |
|
||||
| [9](/09-encodingError) | ![Completed][check] | [Link](/09-encodingError/python) | [Link](/09-encodingError/go) |
|
||||
| 10 | | | |
|
||||
| 11 | | | |
|
||||
| 12 | | | |
|
||||
| 13 | | | |
|
||||
| 14 | | | |
|
||||
| 15 | | | |
|
||||
| 16 | | | |
|
||||
| 17 | | | |
|
||||
| 18 | | | |
|
||||
| 19 | | | |
|
||||
| 20 | | | |
|
||||
| 21 | | | |
|
||||
| 22 | | | |
|
||||
| 23 | | | |
|
||||
| 24 | | | |
|
||||
| 25 | | | |
|
||||
|
||||
<!-- PARSE END -->
|
||||
|
||||
|
|
31
09-encodingError/README.md
Normal file
31
09-encodingError/README.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# [Day 9: Encoding Error](https://adventofcode.com/2020/day/9)
|
||||
|
||||
<details><summary>Script output</summary>
|
||||
|
||||
```
|
||||
❯ python .\python\
|
||||
AoC 2020: day 9 - Encoding Error
|
||||
Python 3.8.5
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 530627549
|
||||
Part 2: 77730285
|
||||
|
||||
❯ go run .\go\
|
||||
AoC 2020: day 9 - Encoding Error
|
||||
Go go1.15.2
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
2.1 pass
|
||||
|
||||
Answers
|
||||
Part 1: 530627549
|
||||
Part 2: 77730285
|
||||
```
|
||||
|
||||
</details>
|
17
09-encodingError/go/challenge/common.go
Normal file
17
09-encodingError/go/challenge/common.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package challenge
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func parse(instr string) (o []int) {
|
||||
for _, x := range strings.Split(strings.TrimSpace(instr), "\n") {
|
||||
i, err := strconv.Atoi(x)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
o = append(o, i)
|
||||
}
|
||||
return
|
||||
}
|
60
09-encodingError/go/challenge/partOne.go
Normal file
60
09-encodingError/go/challenge/partOne.go
Normal file
|
@ -0,0 +1,60 @@
|
|||
package challenge
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
func PartOne(instr string) int {
|
||||
inputSlice := parse(instr)
|
||||
|
||||
preambleLen := 25
|
||||
if len(inputSlice) < 30 { // This is for test inputs
|
||||
preambleLen = 5
|
||||
}
|
||||
|
||||
pointer := preambleLen
|
||||
for pointer < len(inputSlice) {
|
||||
if !hasCombinations(inputSlice[pointer-preambleLen:pointer], inputSlice[pointer]) {
|
||||
return inputSlice[pointer]
|
||||
}
|
||||
pointer += 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func hasCombinations(options []int, target int) bool {
|
||||
|
||||
// Remove duplicate options
|
||||
{
|
||||
keys := make(map[int]bool)
|
||||
var new []int
|
||||
|
||||
for _, entry := range options {
|
||||
if _, value := keys[entry]; !value {
|
||||
keys[entry] = true
|
||||
new = append(new, entry)
|
||||
}
|
||||
}
|
||||
|
||||
options = new
|
||||
}
|
||||
|
||||
sort.Ints(options) // sorts in place
|
||||
|
||||
var lPtr int
|
||||
rPtr := len(options) - 1
|
||||
|
||||
for lPtr < rPtr {
|
||||
v := options[lPtr] + options[rPtr]
|
||||
if v == target {
|
||||
return true
|
||||
} else if v < target {
|
||||
lPtr += 1
|
||||
} else {
|
||||
rPtr -= 1
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
49
09-encodingError/go/challenge/partTwo.go
Normal file
49
09-encodingError/go/challenge/partTwo.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package challenge
|
||||
|
||||
func PartTwo(instr string) int {
|
||||
inputSlice := parse(instr)
|
||||
|
||||
targetValue := PartOne(instr)
|
||||
if targetValue == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
var pointer int
|
||||
for pointer < len(inputSlice) {
|
||||
startPoint := pointer
|
||||
iptr := pointer
|
||||
var count int
|
||||
for iptr < len(inputSlice) {
|
||||
count += inputSlice[iptr]
|
||||
|
||||
if count == targetValue {
|
||||
if iptr-startPoint < 2 {
|
||||
break
|
||||
}
|
||||
|
||||
allValues := inputSlice[startPoint : iptr+1]
|
||||
min := allValues[0]
|
||||
max := allValues[0]
|
||||
for _, v := range allValues {
|
||||
if v < min {
|
||||
min = v
|
||||
}
|
||||
if v > max {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
return min + max
|
||||
}
|
||||
|
||||
if count > targetValue {
|
||||
break
|
||||
}
|
||||
|
||||
iptr += 1
|
||||
}
|
||||
|
||||
pointer += 1
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
100
09-encodingError/go/main.go
Normal file
100
09-encodingError/go/main.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"adventOfCode/09-encodingError/go/challenge"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var infoStruct info
|
||||
{
|
||||
inb, err := ioutil.ReadFile("info.json")
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not open info.json")
|
||||
os.Exit(-1)
|
||||
}
|
||||
err = json.Unmarshal(inb, &infoStruct)
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not parse info.json")
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
year = infoStruct.Year
|
||||
day = infoStruct.Day
|
||||
title = infoStruct.Title
|
||||
)
|
||||
|
||||
fmt.Fprintf(color.Output, "%s: day %s - %s\n", color.YellowString("AoC "+year), color.BlueString(day), title)
|
||||
fmt.Fprintf(color.Output, "Go %s\n\n", color.BlueString(runtime.Version()))
|
||||
|
||||
var challengeInput string
|
||||
{
|
||||
inb, err := ioutil.ReadFile("input.txt")
|
||||
if err != nil {
|
||||
fmt.Println("Error: could not open input.txt")
|
||||
os.Exit(-1)
|
||||
}
|
||||
challengeInput = string(inb)
|
||||
}
|
||||
|
||||
runTests(infoStruct)
|
||||
|
||||
fmt.Println("Answers")
|
||||
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("1"), color.BlueString(strconv.Itoa(challenge.PartOne(challengeInput))))
|
||||
fmt.Fprintf(color.Output, "Part %s: %s\n", color.BlueString("2"), color.BlueString(strconv.Itoa(challenge.PartTwo(challengeInput))))
|
||||
|
||||
}
|
||||
|
||||
type tc struct {
|
||||
Input string `json:"input"`
|
||||
Expected int `json:"expected"`
|
||||
}
|
||||
|
||||
type info struct {
|
||||
Year string `json:"year"`
|
||||
Day string `json:"day"`
|
||||
Title string `json:"title"`
|
||||
TestCases struct {
|
||||
One []tc `json:"one"`
|
||||
Two []tc `json:"two"`
|
||||
} `json:"testCases"`
|
||||
}
|
||||
|
||||
func runTests(infoStruct info) {
|
||||
|
||||
if len(infoStruct.TestCases.One) == 0 && len(infoStruct.TestCases.Two) == 0 {
|
||||
fmt.Println("Info: no test cases specified. Skipping tests")
|
||||
fmt.Println()
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Test cases")
|
||||
|
||||
rt := func(tcs []tc, f func(string) int, n string) {
|
||||
for i, tc := range tcs {
|
||||
fmt.Fprintf(color.Output, "%s ", color.BlueString(n+"."+strconv.Itoa(i+1)))
|
||||
result := f(tc.Input)
|
||||
if result == tc.Expected {
|
||||
fmt.Fprintf(color.Output, "%s", color.GreenString("pass"))
|
||||
} else {
|
||||
fmt.Fprintf(color.Output, "%s (got %s, expected %s)", color.RedString("fail"), color.BlueString(strconv.Itoa(result)), color.BlueString(strconv.Itoa(tc.Expected)))
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
rt(infoStruct.TestCases.One, challenge.PartOne, "1")
|
||||
rt(infoStruct.TestCases.Two, challenge.PartTwo, "2")
|
||||
|
||||
fmt.Println()
|
||||
|
||||
}
|
19
09-encodingError/info.json
Normal file
19
09-encodingError/info.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"year": "2020",
|
||||
"day": "9",
|
||||
"title": "Encoding Error",
|
||||
"testCases": {
|
||||
"one": [
|
||||
{
|
||||
"input": "35\n20\n15\n25\n47\n40\n62\n55\n65\n95\n102\n117\n150\n182\n127\n219\n299\n277\n309\n576",
|
||||
"expected": 127
|
||||
}
|
||||
],
|
||||
"two": [
|
||||
{
|
||||
"input": "35\n20\n15\n25\n47\n40\n62\n55\n65\n95\n102\n117\n150\n182\n127\n219\n299\n277\n309\n576",
|
||||
"expected": 62
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
66
09-encodingError/python/__main__.py
Normal file
66
09-encodingError/python/__main__.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
import json
|
||||
import platform
|
||||
import sys
|
||||
|
||||
from rich import print
|
||||
|
||||
from partOne import partOne
|
||||
from partTwo import partTwo
|
||||
|
||||
|
||||
def run_tests(test_cases):
|
||||
do_tests = True
|
||||
if len(test_cases) == 0:
|
||||
do_tests = False
|
||||
elif len(test_cases["one"]) == 0 and len(test_cases["two"]) == 0:
|
||||
do_tests = False
|
||||
|
||||
if not do_tests:
|
||||
print("Info: no test cases specified. Skipping tests\n")
|
||||
return
|
||||
|
||||
print("Test cases")
|
||||
|
||||
def rt(tcs, f, n):
|
||||
for i, tc in enumerate(tcs):
|
||||
print(f"{n}.{i+1} ", end="")
|
||||
expectedInt = tc["expected"]
|
||||
result = f(str(tc["input"]))
|
||||
if result == expectedInt:
|
||||
print("[green]pass[/green]")
|
||||
else:
|
||||
print(f"[red]fail[/red] (got {result}, expected {expectedInt})")
|
||||
|
||||
rt(test_cases["one"], partOne, 1)
|
||||
rt(test_cases["two"], partTwo, 2)
|
||||
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
info = open("info.json").read()
|
||||
except FileNotFoundError:
|
||||
print("Error: could not open info.json")
|
||||
sys.exit(-1)
|
||||
|
||||
info = json.loads(info)
|
||||
|
||||
year = info["year"]
|
||||
day = info["day"]
|
||||
title = info["title"]
|
||||
|
||||
print(f"[yellow]AoC {year}[/yellow]: day {day} - {title}")
|
||||
print(f"Python {platform.python_version()}\n")
|
||||
|
||||
try:
|
||||
challenge_input = open("input.txt").read()
|
||||
except FileNotFoundError:
|
||||
print("Error: could not open input.txt")
|
||||
sys.exit(-1)
|
||||
|
||||
run_tests(info["testCases"])
|
||||
|
||||
print("Answers")
|
||||
print("Part 1:", partOne(challenge_input))
|
||||
print("Part 2:", partTwo(challenge_input))
|
5
09-encodingError/python/common.py
Normal file
5
09-encodingError/python/common.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from typing import List
|
||||
|
||||
|
||||
def parse(instr: str) -> List[int]:
|
||||
return [int(x) for x in instr.strip().split("\n")]
|
41
09-encodingError/python/partOne.py
Normal file
41
09-encodingError/python/partOne.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
from typing import Set
|
||||
|
||||
from common import *
|
||||
|
||||
|
||||
def has_combinations(options: Set[int], target: int) -> bool:
|
||||
# Returns true of the options set has two values that sum to be the target, else returns false
|
||||
|
||||
options = sorted(options)
|
||||
|
||||
l_ptr = 0
|
||||
r_ptr = len(options) - 1
|
||||
|
||||
while l_ptr < r_ptr:
|
||||
v = options[l_ptr] + options[r_ptr]
|
||||
if v == target:
|
||||
return True
|
||||
elif v < target:
|
||||
l_ptr += 1
|
||||
else:
|
||||
r_ptr -= 1
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def partOne(instr: str) -> int:
|
||||
input_list = parse(instr)
|
||||
|
||||
preamble_len = 25
|
||||
if len(input_list) < 30: # This is for tests
|
||||
preamble_len = 5
|
||||
|
||||
pointer = preamble_len
|
||||
while pointer < len(input_list):
|
||||
if not has_combinations(
|
||||
set(input_list[pointer - preamble_len : pointer]), input_list[pointer]
|
||||
):
|
||||
return input_list[pointer]
|
||||
pointer += 1
|
||||
|
||||
return 0
|
36
09-encodingError/python/partTwo.py
Normal file
36
09-encodingError/python/partTwo.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
from common import *
|
||||
from partOne import partOne
|
||||
|
||||
|
||||
def partTwo(instr: str) -> int:
|
||||
input_list = parse(instr)
|
||||
|
||||
target_value = partOne(instr)
|
||||
if target_value == 0:
|
||||
return 0
|
||||
|
||||
pointer = 0
|
||||
while pointer < len(input_list):
|
||||
# iterate consecutive values from here
|
||||
start_point = pointer
|
||||
iptr = pointer # Internal PoinTeR
|
||||
count = 0
|
||||
while iptr < len(input_list):
|
||||
count += input_list[iptr]
|
||||
|
||||
if count == target_value:
|
||||
# must be at least two values
|
||||
if iptr - start_point < 2:
|
||||
break
|
||||
|
||||
all_values = input_list[start_point : iptr + 1]
|
||||
return min(all_values) + max(all_values)
|
||||
|
||||
if count > target_value:
|
||||
break
|
||||
|
||||
iptr += 1
|
||||
|
||||
pointer += 1
|
||||
|
||||
return 0
|
Loading…
Add table
Add a link
Reference in a new issue