day 12
This commit is contained in:
parent
796a7a1b4f
commit
0d12942dfe
5
.gitignore
vendored
5
.gitignore
vendored
@ -2,8 +2,3 @@
|
|||||||
tmp
|
tmp
|
||||||
|
|
||||||
# Ignore these to avoid leaking local replacements to the devkit
|
# Ignore these to avoid leaking local replacements to the devkit
|
||||||
./go.mod
|
|
||||||
./go.sum
|
|
||||||
|
|
||||||
go.mod
|
|
||||||
go.sum
|
|
||||||
149
year25/day12/day.go
Normal file
149
year25/day12/day.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package day12
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.bizdoc.ro/gabi-public/Advent-of-Code.git/aoc"
|
||||||
|
"git.bizdoc.ro/private/devkit.git/gg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Part1(ctx aoc.Context) (int, error) {
|
||||||
|
input, err := parseInput(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("day12: failed to parse input: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ares := make([]int, len(input.Shapes))
|
||||||
|
for i, shape := range input.Shapes {
|
||||||
|
ares[i] = shape.Area()
|
||||||
|
}
|
||||||
|
|
||||||
|
solution := 0
|
||||||
|
for _, region := range input.Regions {
|
||||||
|
regionSize := region.Rows * region.Cols
|
||||||
|
sum := 0
|
||||||
|
for i, count := range region.ShapeCounts {
|
||||||
|
sum += count * ares[i]
|
||||||
|
}
|
||||||
|
canFit := sum < regionSize
|
||||||
|
if canFit {
|
||||||
|
solution += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.Println(input.String())
|
||||||
|
return solution, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Shape [3][3]byte
|
||||||
|
|
||||||
|
func (s *Shape) Area() int {
|
||||||
|
sum := 0
|
||||||
|
for i := range s {
|
||||||
|
for j := range s[i] {
|
||||||
|
if s[i][j] == '#' {
|
||||||
|
sum += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
type Region struct {
|
||||||
|
Rows, Cols int
|
||||||
|
ShapeCounts []int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Region) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
|
out := gg.NewSafeWriter(w)
|
||||||
|
fmt.Fprintf(out, "%dx%d ", r.Rows, r.Cols)
|
||||||
|
for _, count := range r.ShapeCounts {
|
||||||
|
out.WriteString(strconv.Itoa(count) + " ")
|
||||||
|
}
|
||||||
|
out.WriteString("\n")
|
||||||
|
return out.BytesWritten(), out.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Input struct {
|
||||||
|
Shapes []Shape
|
||||||
|
Regions []Region
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInput(ctx aoc.Context) (input Input, err error) {
|
||||||
|
text, err := ctx.BodyString()
|
||||||
|
if err != nil {
|
||||||
|
return input, fmt.Errorf("day12: failed to read input file: %w", err)
|
||||||
|
}
|
||||||
|
parts := strings.Split(text, "\n\n")
|
||||||
|
regionPart := parts[len(parts)-1]
|
||||||
|
parts = parts[0 : len(parts)-1]
|
||||||
|
|
||||||
|
input.Shapes = make([]Shape, len(parts))
|
||||||
|
for _, part := range parts {
|
||||||
|
// 0:
|
||||||
|
// ###
|
||||||
|
// ##.
|
||||||
|
// ##.
|
||||||
|
lines := strings.Split(part, "\n")
|
||||||
|
id, err := strconv.Atoi(lines[0][:len(lines[0])-1])
|
||||||
|
if err != nil {
|
||||||
|
return input, fmt.Errorf("day12: failed to parse shape id: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
shape := input.Shapes[id]
|
||||||
|
for i := range shape {
|
||||||
|
for j := range shape[i] {
|
||||||
|
shape[i][j] = lines[1+i][j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input.Shapes[id] = shape // shape is value object
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, regionStr := range strings.Split(regionPart, "\n") {
|
||||||
|
// 12x5: 1 0 1 0 3 2
|
||||||
|
var region Region
|
||||||
|
parts := strings.Split(regionStr, ": ")
|
||||||
|
for _, idstr := range strings.Split(parts[1], " ") {
|
||||||
|
id, err := strconv.Atoi(idstr)
|
||||||
|
if err != nil {
|
||||||
|
return input, fmt.Errorf("day12: failed to parse region id: %w", err)
|
||||||
|
}
|
||||||
|
region.ShapeCounts = append(region.ShapeCounts, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
parts2 := strings.Split(parts[0], "x")
|
||||||
|
region.Rows, err = strconv.Atoi(parts2[0])
|
||||||
|
if err != nil {
|
||||||
|
return input, fmt.Errorf("day12: failed to parse region rows: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
region.Cols, err = strconv.Atoi(parts2[1])
|
||||||
|
if err != nil {
|
||||||
|
return input, fmt.Errorf("day12: failed to parse region cols: %w", err)
|
||||||
|
}
|
||||||
|
input.Regions = append(input.Regions, region)
|
||||||
|
}
|
||||||
|
return input, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Input) String() string {
|
||||||
|
buf := strings.Builder{}
|
||||||
|
|
||||||
|
for shapeid, shape := range i.Shapes {
|
||||||
|
fmt.Fprintln(&buf, shapeid)
|
||||||
|
for i := range shape {
|
||||||
|
for j := range shape[i] {
|
||||||
|
buf.WriteString(string(shape[i][j]) + " ")
|
||||||
|
}
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
buf.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, region := range i.Regions {
|
||||||
|
region.WriteTo(&buf)
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
18
year25/day12/day_test.go
Normal file
18
year25/day12/day_test.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package day12
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.bizdoc.ro/gabi-public/Advent-of-Code.git/tests"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPart1Example(t *testing.T) {
|
||||||
|
const want = 2
|
||||||
|
tests.Test(t, "example.txt", tests.Handler(Part1), want)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPart1(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
const want = 510
|
||||||
|
tests.Test(t, "input.txt", tests.Handler(Part1), want)
|
||||||
|
}
|
||||||
@ -1,83 +0,0 @@
|
|||||||
package main_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.bizdoc.ro/gabi-public/Advent-of-Code.git/aoc"
|
|
||||||
)
|
|
||||||
|
|
||||||
func getInput(name string) io.Reader {
|
|
||||||
name = fmt.Sprintf("./data/%s.txt", name)
|
|
||||||
input, err := os.ReadFile(name)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return bytes.NewReader(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
func assert(t *testing.T, err error, a, b any) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
want := fmt.Sprintf("%v", a)
|
|
||||||
got := fmt.Sprintf("%v", b)
|
|
||||||
if got != want {
|
|
||||||
err = fmt.Errorf("want %s, got %s", want, got)
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type TestCase struct {
|
|
||||||
Name string
|
|
||||||
File string
|
|
||||||
Want any
|
|
||||||
Handler func(ctx aoc.Context) (any, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
var StderrLogger = log.New(os.Stderr, "", 0)
|
|
||||||
var DiscardLogger = log.New(io.Discard, "", 0)
|
|
||||||
|
|
||||||
func handler[T any](f func(ctx aoc.Context) (T, error)) func(ctx aoc.Context) (any, error) {
|
|
||||||
return func(c aoc.Context) (any, error) {
|
|
||||||
return f(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handler2[T any, K any](param T, f func(ctx aoc.Context, param T) (K, error)) func(ctx aoc.Context) (any, error) {
|
|
||||||
return func(c aoc.Context) (any, error) {
|
|
||||||
return f(c, param)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func runTestCase(t *testing.T, cases []TestCase, l *log.Logger) {
|
|
||||||
|
|
||||||
t.Helper()
|
|
||||||
var totalTime time.Duration
|
|
||||||
defer func() {
|
|
||||||
t.Log("Total time:", totalTime.String())
|
|
||||||
}()
|
|
||||||
for _, test := range cases {
|
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
|
||||||
start := time.Now()
|
|
||||||
defer func() {
|
|
||||||
end := time.Since(start)
|
|
||||||
t.Log("elapsed:", end)
|
|
||||||
totalTime += end
|
|
||||||
}()
|
|
||||||
input := getInput(test.File)
|
|
||||||
if test.Handler == nil {
|
|
||||||
t.Fatalf("%s handler is nil", test.Name)
|
|
||||||
}
|
|
||||||
got, err := test.Handler(aoc.Context{Body: input, Logger: l})
|
|
||||||
assert(t, err, test.Want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user