129 lines
2.4 KiB
Go
129 lines
2.4 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"os"
|
||
|
"sort"
|
||
|
)
|
||
|
|
||
|
func proccessLines(path string, f func(string) (stop bool, err error)) error {
|
||
|
file, err := os.Open(path)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer file.Close()
|
||
|
scanner := bufio.NewScanner(file)
|
||
|
for scanner.Scan() {
|
||
|
stop, err := f(scanner.Text())
|
||
|
if stop || err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
if err := scanner.Err(); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
type seat struct {
|
||
|
row, column, id int
|
||
|
}
|
||
|
|
||
|
func paritionSearch(partitions string, start, end float64, lower, upper string) (int, error) {
|
||
|
if start == end {
|
||
|
return int(start), nil
|
||
|
}
|
||
|
if partitions == "" {
|
||
|
return 0, fmt.Errorf("empty partitions are invalid")
|
||
|
}
|
||
|
if start > end {
|
||
|
return 0, fmt.Errorf("start cannot be greater than end")
|
||
|
}
|
||
|
if lower == "" || upper == "" {
|
||
|
return 0, fmt.Errorf("invalid upper and lower bounds")
|
||
|
}
|
||
|
|
||
|
mid := (end - start) / 2.0
|
||
|
direction := string(partitions[0])
|
||
|
switch direction {
|
||
|
case lower:
|
||
|
return paritionSearch(partitions[1:], start, mid+start-.5, lower, upper)
|
||
|
case upper:
|
||
|
return paritionSearch(partitions[1:], mid+start+.5, end, lower, upper)
|
||
|
}
|
||
|
|
||
|
return 0, fmt.Errorf("unknown direction %s", direction)
|
||
|
}
|
||
|
|
||
|
func parseSeat(code string) (seat, error) {
|
||
|
totalRows, totalCols := 128, 8
|
||
|
if len(code) != 10 {
|
||
|
return seat{}, fmt.Errorf("invalid code length %s", code)
|
||
|
}
|
||
|
row, err := paritionSearch(code[:7], 0.0, float64(totalRows-1), "F", "B")
|
||
|
if err != nil {
|
||
|
return seat{}, err
|
||
|
}
|
||
|
col, err := paritionSearch(code[7:], 0.0, float64(totalCols-1), "L", "R")
|
||
|
if err != nil {
|
||
|
return seat{}, err
|
||
|
}
|
||
|
|
||
|
return seat{
|
||
|
row: row,
|
||
|
column: col,
|
||
|
id: row*8 + col,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
func part1() {
|
||
|
max := -1
|
||
|
err := proccessLines("input.txt", func(line string) (stop bool, err error) {
|
||
|
s, err := parseSeat(line)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
if s.id > max {
|
||
|
max = s.id
|
||
|
}
|
||
|
return
|
||
|
})
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
|
||
|
fmt.Printf("Max id is %d\n", max)
|
||
|
}
|
||
|
|
||
|
func part2() {
|
||
|
seatIds := []int{}
|
||
|
err := proccessLines("input.txt", func(line string) (stop bool, err error) {
|
||
|
s, err := parseSeat(line)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
seatIds = append(seatIds, s.id)
|
||
|
return
|
||
|
})
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
|
||
|
sort.Ints(seatIds)
|
||
|
lastID := -3
|
||
|
for _, id := range seatIds {
|
||
|
if id == lastID+2 {
|
||
|
fmt.Printf("Found my seat! %d", lastID+1)
|
||
|
break
|
||
|
}
|
||
|
lastID = id
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
part1()
|
||
|
part2()
|
||
|
}
|