Day 5 (Golang)
This commit is contained in:
parent
313e74738c
commit
8fd630d6fd
11 changed files with 422 additions and 92 deletions
|
@ -63,9 +63,31 @@ Your puzzle answer was `548`.
|
|||
<details><summary>Script output</summary>
|
||||
|
||||
```
|
||||
❯ python .\main.py
|
||||
Part one: The highest seat ID is 989.
|
||||
Part two: Your seat ID is 548 (row 68, col 4).
|
||||
❯ python .\python\
|
||||
AoC 2020: day 5 - Binary Boarding
|
||||
Python 3.8.5
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
1.2 pass
|
||||
1.3 pass
|
||||
|
||||
Answers
|
||||
Part 1: 989
|
||||
Part 2: 548
|
||||
|
||||
❯ go run .\go\
|
||||
AoC 2020: day 5 - Binary Boarding
|
||||
Go go1.15.2
|
||||
|
||||
Test cases
|
||||
1.1 pass
|
||||
1.2 pass
|
||||
1.3 pass
|
||||
|
||||
Answers
|
||||
Part 1: 989
|
||||
Part 2: 548
|
||||
```
|
||||
|
||||
</details>
|
||||
|
|
57
05-binaryBoarding/go/challenge/common.go
Normal file
57
05-binaryBoarding/go/challenge/common.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package challenge
|
||||
|
||||
import "strings"
|
||||
|
||||
var (
|
||||
front = []rune("F")[0]
|
||||
back = []rune("B")[0]
|
||||
left = []rune("L")[0]
|
||||
right = []rune("R")[0]
|
||||
)
|
||||
|
||||
const (
|
||||
numRows = 128
|
||||
numCols = 8
|
||||
)
|
||||
|
||||
func parse(instr string) []string {
|
||||
return strings.Split(strings.TrimSpace(instr), "\n")
|
||||
}
|
||||
|
||||
func decodePosition(rowString string, decChar, incChar rune, maxVal int) int {
|
||||
minVal := 0
|
||||
maxVal -= 1
|
||||
|
||||
currentRange := (maxVal + 1) - minVal
|
||||
|
||||
for _, char := range strings.ToUpper(rowString) {
|
||||
|
||||
rangeModifier := int(currentRange / 2)
|
||||
|
||||
if char == decChar {
|
||||
maxVal -= rangeModifier
|
||||
} else if char == incChar {
|
||||
minVal += rangeModifier
|
||||
}
|
||||
|
||||
currentRange /= 2
|
||||
|
||||
}
|
||||
|
||||
if rune(rowString[len(rowString)-1]) == decChar {
|
||||
return minVal
|
||||
}
|
||||
|
||||
return maxVal
|
||||
}
|
||||
|
||||
func parseSeat(seatString string) (int, int) {
|
||||
row := decodePosition(seatString[:7], front, back, numRows)
|
||||
col := decodePosition(seatString[7:], left, right, numCols)
|
||||
|
||||
return row, col
|
||||
}
|
||||
|
||||
func getSeatId(row, col int) int {
|
||||
return (row * 8) + col
|
||||
}
|
16
05-binaryBoarding/go/challenge/partOne.go
Normal file
16
05-binaryBoarding/go/challenge/partOne.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package challenge
|
||||
|
||||
func PartOne(instr string) int {
|
||||
inputSlice := parse(instr)
|
||||
|
||||
var highestSeatId int
|
||||
for _, seat := range inputSlice {
|
||||
psr, psc := parseSeat(seat)
|
||||
seatId := getSeatId(psr, psc)
|
||||
if seatId > highestSeatId {
|
||||
highestSeatId = seatId
|
||||
}
|
||||
}
|
||||
|
||||
return highestSeatId
|
||||
}
|
36
05-binaryBoarding/go/challenge/partTwo.go
Normal file
36
05-binaryBoarding/go/challenge/partTwo.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package challenge
|
||||
|
||||
func PartTwo(instr string) int {
|
||||
inputSlice := parse(instr)
|
||||
|
||||
var seatMatrix [numRows][numCols]bool
|
||||
for _, seat := range inputSlice {
|
||||
row, col := parseSeat(seat)
|
||||
seatMatrix[row][col] = true
|
||||
}
|
||||
|
||||
var (
|
||||
lastOne bool
|
||||
lastTwo bool
|
||||
)
|
||||
|
||||
for row := 0; row < len(seatMatrix); row += 1 {
|
||||
for col := 0; col < len(seatMatrix[row]); col += 1 {
|
||||
this := seatMatrix[row][col]
|
||||
if (lastTwo && !lastOne && this) {
|
||||
// We need to get the previous item because at this point, we've already moved on one
|
||||
prevRow := row
|
||||
prevCol := col - 1
|
||||
if prevCol < 0 {
|
||||
prevRow -= 1
|
||||
prevCol += numCols
|
||||
}
|
||||
return getSeatId(prevRow, prevCol)
|
||||
}
|
||||
lastTwo = lastOne
|
||||
lastOne = this
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
106
05-binaryBoarding/go/main.go
Normal file
106
05-binaryBoarding/go/main.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"adventOfCode/05-binaryBoarding/go/challenge"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
const (
|
||||
year = "2020"
|
||||
day = "1"
|
||||
title = "Report Repair"
|
||||
)
|
||||
|
||||
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()
|
||||
|
||||
}
|
22
05-binaryBoarding/info.json
Normal file
22
05-binaryBoarding/info.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"year": "2020",
|
||||
"day": "5",
|
||||
"title": "Binary Boarding",
|
||||
"testCases": {
|
||||
"one": [
|
||||
{
|
||||
"input": "BFFFBBFRRR",
|
||||
"expected": 567
|
||||
},
|
||||
{
|
||||
"input": "FFFBBBFRRR",
|
||||
"expected": 119
|
||||
},
|
||||
{
|
||||
"input": "BBFFBBFRLL",
|
||||
"expected": 820
|
||||
}
|
||||
],
|
||||
"two": []
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
from typing import Tuple
|
||||
|
||||
input_list = open("input.txt").read().strip().split("\n")
|
||||
|
||||
front = "F"
|
||||
back = "B"
|
||||
left = "L"
|
||||
right = "R"
|
||||
|
||||
num_rows = 128
|
||||
num_cols = 8
|
||||
|
||||
def decode_position(row_string:str, dec_char:str, inc_char:str, max_val:int) -> int:
|
||||
min_val = 0
|
||||
max_val -= 1
|
||||
|
||||
current_range = (max_val + 1) - min_val
|
||||
|
||||
for char in row_string.upper():
|
||||
|
||||
range_modifier = current_range / 2
|
||||
|
||||
if char == dec_char:
|
||||
max_val -= range_modifier
|
||||
elif char == inc_char:
|
||||
min_val += range_modifier
|
||||
|
||||
current_range /= 2
|
||||
|
||||
if row_string[-1] == dec_char:
|
||||
return min_val
|
||||
else:
|
||||
return max_val
|
||||
|
||||
def parse_seat(seat_string:str) -> Tuple[int, int]:
|
||||
row = decode_position(seat_string[:7], front, back, num_rows)
|
||||
col = decode_position(seat_string[7:], left, right, num_cols)
|
||||
|
||||
return int(row), int(col)
|
||||
|
||||
def get_seat_id(row:int, col:int) -> int:
|
||||
return (row * 8) + col
|
||||
|
||||
# --- Part one ---
|
||||
|
||||
highest_seat_id = 0
|
||||
for seat in input_list:
|
||||
parsed_seat = parse_seat(seat)
|
||||
seat_id = get_seat_id(*parsed_seat)
|
||||
if seat_id > highest_seat_id:
|
||||
highest_seat_id = seat_id
|
||||
|
||||
print(f"Part one: The highest seat ID is {highest_seat_id}.")
|
||||
|
||||
# --- Part two ---
|
||||
|
||||
# Build a matrix to represent the entire plane
|
||||
# False represents an empty seat
|
||||
seat_matrix = []
|
||||
for _ in range(num_rows):
|
||||
x = []
|
||||
for _ in range(num_cols):
|
||||
x.append(False)
|
||||
seat_matrix.append(x)
|
||||
|
||||
# Populate that matrix
|
||||
for seat in input_list:
|
||||
row, col = parse_seat(seat)
|
||||
seat_matrix[row][col] = True
|
||||
|
||||
lastOne = None
|
||||
lastTwo = None
|
||||
|
||||
for row in range(len(seat_matrix)):
|
||||
for col in range(len(seat_matrix[row])):
|
||||
|
||||
this = seat_matrix[row][col]
|
||||
if [lastTwo, lastOne, this] == [True, False, True]:
|
||||
|
||||
# We need to get the previous item because at this point, we've already moved on one
|
||||
prev_row = row
|
||||
prev_col = col - 1
|
||||
if prev_col < 0:
|
||||
prev_row -= 1
|
||||
|
||||
print(f"Part two: Your seat ID is {get_seat_id(prev_row, prev_col)} (row {prev_row}, col {prev_col}).")
|
||||
|
||||
lastTwo = lastOne
|
||||
lastOne = this
|
64
05-binaryBoarding/python/__main__.py
Normal file
64
05-binaryBoarding/python/__main__.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
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))
|
43
05-binaryBoarding/python/common.py
Normal file
43
05-binaryBoarding/python/common.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
from typing import List, Tuple
|
||||
|
||||
front = "F"
|
||||
back = "B"
|
||||
left = "L"
|
||||
right = "R"
|
||||
|
||||
num_rows = 128
|
||||
num_cols = 8
|
||||
|
||||
def parse(instr:str) -> List:
|
||||
return instr.strip().split("\n")
|
||||
|
||||
def decode_position(row_string:str, dec_char:str, inc_char:str, max_val:int) -> int:
|
||||
min_val = 0
|
||||
max_val -= 1
|
||||
|
||||
current_range = (max_val + 1) - min_val
|
||||
|
||||
for char in row_string.upper():
|
||||
|
||||
range_modifier = current_range / 2
|
||||
|
||||
if char == dec_char:
|
||||
max_val -= range_modifier
|
||||
elif char == inc_char:
|
||||
min_val += range_modifier
|
||||
|
||||
current_range /= 2
|
||||
|
||||
if row_string[-1] == dec_char:
|
||||
return min_val
|
||||
else:
|
||||
return max_val
|
||||
|
||||
def parse_seat(seat_string:str) -> Tuple[int, int]:
|
||||
row = decode_position(seat_string[:7], front, back, num_rows)
|
||||
col = decode_position(seat_string[7:], left, right, num_cols)
|
||||
|
||||
return int(row), int(col)
|
||||
|
||||
def get_seat_id(row:int, col:int) -> int:
|
||||
return (row * 8) + col
|
13
05-binaryBoarding/python/partOne.py
Normal file
13
05-binaryBoarding/python/partOne.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from common import *
|
||||
|
||||
def partOne(instr:str) -> int:
|
||||
input_list = parse(instr)
|
||||
|
||||
highest_seat_id = 0
|
||||
for seat in input_list:
|
||||
parsed_seat = parse_seat(seat)
|
||||
seat_id = get_seat_id(*parsed_seat)
|
||||
if seat_id > highest_seat_id:
|
||||
highest_seat_id = seat_id
|
||||
|
||||
return highest_seat_id
|
40
05-binaryBoarding/python/partTwo.py
Normal file
40
05-binaryBoarding/python/partTwo.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
from common import *
|
||||
|
||||
def partTwo(instr:str) -> int:
|
||||
input_list = parse(instr)
|
||||
|
||||
# Build a matrix to represent the entire plane
|
||||
# False represents an empty seat
|
||||
seat_matrix = []
|
||||
for _ in range(num_rows):
|
||||
x = []
|
||||
for _ in range(num_cols):
|
||||
x.append(False)
|
||||
seat_matrix.append(x)
|
||||
|
||||
# Populate that matrix
|
||||
for seat in input_list:
|
||||
row, col = parse_seat(seat)
|
||||
seat_matrix[row][col] = True
|
||||
|
||||
lastOne = None
|
||||
lastTwo = None
|
||||
|
||||
for row in range(len(seat_matrix)):
|
||||
for col in range(len(seat_matrix[row])):
|
||||
|
||||
this = seat_matrix[row][col]
|
||||
if [lastTwo, lastOne, this] == [True, False, True]:
|
||||
|
||||
# We need to get the previous item because at this point, we've already moved on one
|
||||
prev_row = row
|
||||
prev_col = col - 1
|
||||
if prev_col < 0:
|
||||
prev_row -= 1
|
||||
|
||||
return get_seat_id(prev_row, prev_col)
|
||||
|
||||
lastTwo = lastOne
|
||||
lastOne = this
|
||||
|
||||
return 0
|
Loading…
Add table
Add a link
Reference in a new issue