Intitial project scaffolding & day 1 solution
This commit is contained in:
commit
fccc444b53
|
|
@ -0,0 +1,2 @@
|
||||||
|
aoc2022
|
||||||
|
.idea
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
package day1_calorie_counting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Solver struct {
|
||||||
|
elves [][]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Solver) ParseInput(input []string) {
|
||||||
|
elves := make([][]int, 0)
|
||||||
|
|
||||||
|
elfIndex := 0
|
||||||
|
elves = append(elves, make([]int, 0))
|
||||||
|
for _, line := range input {
|
||||||
|
if line == "" {
|
||||||
|
elfIndex += 1
|
||||||
|
elves = append(elves, make([]int, 0))
|
||||||
|
} else {
|
||||||
|
n, _ := strconv.Atoi(line)
|
||||||
|
elves[elfIndex] = append(elves[elfIndex], n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.elves = elves
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Solver) SolvePart1() int {
|
||||||
|
mostCalories := 0
|
||||||
|
for _, calories := range s.elves {
|
||||||
|
sum := 0
|
||||||
|
for _, c := range calories {
|
||||||
|
sum += c
|
||||||
|
}
|
||||||
|
if sum > mostCalories {
|
||||||
|
mostCalories = sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mostCalories
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Solver) SolvePart2() int {
|
||||||
|
caloriesPerElf := make([]int, len(s.elves))
|
||||||
|
for i, calories := range s.elves {
|
||||||
|
sum := 0
|
||||||
|
for _, c := range calories {
|
||||||
|
sum += c
|
||||||
|
}
|
||||||
|
caloriesPerElf[i] = sum
|
||||||
|
}
|
||||||
|
sort.Ints(caloriesPerElf)
|
||||||
|
|
||||||
|
top3sum := 0
|
||||||
|
for i := len(caloriesPerElf) - 3; i < len(caloriesPerElf); i++ {
|
||||||
|
top3sum += caloriesPerElf[i]
|
||||||
|
}
|
||||||
|
return top3sum
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package day1_calorie_counting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"snikolov.me/aoc2022/testutils"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCorrectSolutions(t *testing.T) {
|
||||||
|
solver := &Solver{}
|
||||||
|
testutils.TestHelper(t, solver, 1, true, 24000, 45000)
|
||||||
|
testutils.TestHelper(t, solver, 1, false, 66306, 195292)
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,14 @@
|
||||||
|
1000
|
||||||
|
2000
|
||||||
|
3000
|
||||||
|
|
||||||
|
4000
|
||||||
|
|
||||||
|
5000
|
||||||
|
6000
|
||||||
|
|
||||||
|
7000
|
||||||
|
8000
|
||||||
|
9000
|
||||||
|
|
||||||
|
10000
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
day1_calorie_counting "snikolov.me/aoc2022/day1"
|
||||||
|
"snikolov.me/aoc2022/utils"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Args struct {
|
||||||
|
DayNumber int
|
||||||
|
PartNumber int
|
||||||
|
TestMode bool
|
||||||
|
DownloadInput bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var args Args
|
||||||
|
flag.IntVar(&args.DayNumber, "day", 0, "day number")
|
||||||
|
flag.IntVar(&args.PartNumber, "part", 0, "day part number")
|
||||||
|
flag.BoolVar(&args.TestMode, "test", false, "use test input")
|
||||||
|
flag.BoolVar(&args.DownloadInput, "download-input", false, "download production input")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
inputFileName := utils.GetInputFileName(args.DayNumber, args.TestMode)
|
||||||
|
|
||||||
|
if args.DownloadInput {
|
||||||
|
const sessionCookie = "53616c7465645f5f63d2a07212d6266c5e8de3664d5684dac31a6031e5ddf4c1ec004e5475bf45a16c9f9919fae43b7344135650408c9aec716880afd94bbc0b"
|
||||||
|
if err := utils.DownloadInput(sessionCookie, args.DayNumber, inputFileName); err != nil {
|
||||||
|
log.Fatalf("Could not download puzzle input: %s", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
solve(args, inputFileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func solve(args Args, inputFileName string) {
|
||||||
|
solvers := map[int]utils.Solver{
|
||||||
|
1: &day1_calorie_counting.Solver{},
|
||||||
|
}
|
||||||
|
solver, ok := solvers[args.DayNumber]
|
||||||
|
if !ok {
|
||||||
|
log.Fatalf("Could not find a solver for day %d", args.DayNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
startTime := time.Now()
|
||||||
|
|
||||||
|
if input, err := utils.ReadInput(inputFileName); err == nil {
|
||||||
|
solver.ParseInput(input)
|
||||||
|
} else {
|
||||||
|
log.Fatalf("Could not read input for day %d: %s", args.DayNumber, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var solution int
|
||||||
|
switch args.PartNumber {
|
||||||
|
case 1:
|
||||||
|
solution = solver.SolvePart1()
|
||||||
|
case 2:
|
||||||
|
solution = solver.SolvePart2()
|
||||||
|
default:
|
||||||
|
log.Fatal("unknown part number, please use 1 or 2")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s: %d\n", time.Now().Sub(startTime), solution)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package testutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"snikolov.me/aoc2022/utils"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHelper(t *testing.T, solver utils.Solver, dayNumber int, testMode bool, solutionPart1, solutionPart2 int) {
|
||||||
|
testInput, err := utils.ReadInput("../" + utils.GetInputFileName(dayNumber, testMode))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
solver.ParseInput(testInput)
|
||||||
|
if result := solver.SolvePart1(); result != solutionPart1 {
|
||||||
|
t.Errorf("wrong output for day %d part 1, test = %v: %d != %d", dayNumber, testMode, result, solutionPart1)
|
||||||
|
}
|
||||||
|
if result := solver.SolvePart2(); result != solutionPart2 {
|
||||||
|
t.Errorf("wrong output for day %d part 2, test = %v: %d != %d", dayNumber, testMode, result, solutionPart1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Solver interface {
|
||||||
|
ParseInput(input []string)
|
||||||
|
SolvePart1() int
|
||||||
|
SolvePart2() int
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadInput(inputFileName string) ([]string, error) {
|
||||||
|
var input = make([]string, 0)
|
||||||
|
|
||||||
|
reader, err := os.Open(inputFileName)
|
||||||
|
if err != nil {
|
||||||
|
return input, fmt.Errorf("failed to open input file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
for scanner.Scan() {
|
||||||
|
input = append(input, scanner.Text())
|
||||||
|
}
|
||||||
|
return input, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInputFileName(dayNumber int, testMode bool) string {
|
||||||
|
var testString string
|
||||||
|
if testMode {
|
||||||
|
testString = "test"
|
||||||
|
} else {
|
||||||
|
testString = "prod"
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("day%d/%s.in.txt", dayNumber, testString)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadInput(sessionCookie string, dayNumber int, inputFileName string) error {
|
||||||
|
req, err := http.NewRequest("GET", fmt.Sprintf("https://adventofcode.com/2022/day/%d/input", dayNumber), nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("couldn't create reques: %s", err)
|
||||||
|
}
|
||||||
|
req.AddCookie(&http.Cookie{Name: "session", Value: sessionCookie})
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
writer, err := os.Create(inputFileName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := io.Copy(writer, resp.Body); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue