feat: solve day 12 and there is no part 2
This commit is contained in:
@@ -37,4 +37,4 @@ go test ./cmd/01
|
|||||||
| 09 | [Problem](https://adventofcode.com/2025/day/9) | [Solution](./cmd/09/) | Part 1 was such a nice break from the madness of day 8. Basically I need to go build some video games. |
|
| 09 | [Problem](https://adventofcode.com/2025/day/9) | [Solution](./cmd/09/) | Part 1 was such a nice break from the madness of day 8. Basically I need to go build some video games. |
|
||||||
| 10 | [Problem](https://adventofcode.com/2025/day/10) | [Solution](./cmd/10/) | Part 1 took me way to look cause I couldn't figure out how to generate all button press combinations. |
|
| 10 | [Problem](https://adventofcode.com/2025/day/10) | [Solution](./cmd/10/) | Part 1 took me way to look cause I couldn't figure out how to generate all button press combinations. |
|
||||||
| 11 | [Problem](https://adventofcode.com/2025/day/11) | [Solution](./cmd/11/) | DFS to the rescue again. |
|
| 11 | [Problem](https://adventofcode.com/2025/day/11) | [Solution](./cmd/11/) | DFS to the rescue again. |
|
||||||
| 12 | [Problem](https://adventofcode.com/2025/day/12) | [Solution](./cmd/12/) | |
|
| 12 | [Problem](https://adventofcode.com/2025/day/12) | [Solution](./cmd/12/) | I did it...but the example input takes a long time to find solution |
|
||||||
|
|||||||
+128
-23
@@ -1,32 +1,36 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/StevanFreeborn/advent-of-code-2025/cmd/12/shape"
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/12/shape"
|
||||||
"github.com/StevanFreeborn/advent-of-code-2025/internal/file"
|
"github.com/StevanFreeborn/advent-of-code-2025/internal/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Make the splitting
|
|
||||||
// safe for LF and CRLF
|
|
||||||
const NEWLINE = "\r\n"
|
|
||||||
const COLON = ":"
|
const COLON = ":"
|
||||||
const X = "x"
|
const X = "x"
|
||||||
|
|
||||||
func SolvePartOne(filePath string) int {
|
func SolvePartOne(filePath string) int {
|
||||||
input := file.ReadAllText(filePath)
|
twoNewLineRegex := regexp.MustCompile(`\r?\n\r?\n`)
|
||||||
sections := strings.Split(strings.TrimSpace(input), NEWLINE+NEWLINE)
|
newLineRegex := regexp.MustCompile(`\r?\n`)
|
||||||
|
|
||||||
shapes := []shape.Shape{}
|
input := file.ReadAllText(filePath)
|
||||||
|
sections := twoNewLineRegex.Split(strings.TrimSpace(input), -1)
|
||||||
|
|
||||||
|
total := 0
|
||||||
|
shapes := map[int][]shape.Shape{}
|
||||||
regions := []string{}
|
regions := []string{}
|
||||||
|
|
||||||
for _, section := range sections {
|
for _, section := range sections {
|
||||||
lines := strings.Split(strings.TrimSpace(section), NEWLINE)
|
lines := newLineRegex.Split(strings.TrimSpace(section), -1)
|
||||||
header := lines[0]
|
header := lines[0]
|
||||||
|
|
||||||
if strings.Contains(header, COLON) && strings.Contains(header, X) == false {
|
if strings.Contains(header, COLON) && strings.Contains(header, X) == false {
|
||||||
shapes = append(shapes, shape.From(lines))
|
shape := shape.From(lines)
|
||||||
|
shapes[shape.Id()] = shape.GenerateVariants()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,23 +41,124 @@ func SolvePartOne(filePath string) int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We are currently not generating
|
for _, region := range regions {
|
||||||
// all the expected variants. Need to debug this
|
parts := strings.Split(region, COLON)
|
||||||
// WRITE AUTOMATED UNIT TESTS DUMMY
|
dims := strings.Split(parts[0], X)
|
||||||
// WHEN YOU READ THIS IN THE FUTURE YOU ARE GOING
|
width, _ := strconv.Atoi(dims[0])
|
||||||
// TO WANT TO IGNORE IT...DON'T!
|
height, _ := strconv.Atoi(dims[1])
|
||||||
// - Past Stevan
|
|
||||||
for _, s := range shapes {
|
countsStr := strings.Fields(parts[1])
|
||||||
if s.Id() != 1 && s.Id() != 2 && s.Id() != 0 {
|
requiredShapes := []int{}
|
||||||
continue
|
|
||||||
|
for id, s := range countsStr {
|
||||||
|
count, _ := strconv.Atoi(s)
|
||||||
|
|
||||||
|
for range count {
|
||||||
|
requiredShapes = append(requiredShapes, id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("SHAPE ID", s.Id())
|
if canFit(width, height, requiredShapes, shapes) {
|
||||||
|
total++
|
||||||
for _, v := range s.GenerateVariants() {
|
|
||||||
fmt.Println(v)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
type item struct {
|
||||||
|
id int
|
||||||
|
area int
|
||||||
|
variants []shape.Shape
|
||||||
|
}
|
||||||
|
|
||||||
|
func canFit(width int, height int, requiredShapes []int, shapes map[int][]shape.Shape) bool {
|
||||||
|
totalArea := 0
|
||||||
|
|
||||||
|
itemsToPlace := make([]item, 0, len(requiredShapes))
|
||||||
|
|
||||||
|
for _, id := range requiredShapes {
|
||||||
|
shapeVariants := shapes[id]
|
||||||
|
area := shapeVariants[0].Area()
|
||||||
|
totalArea += area
|
||||||
|
itemsToPlace = append(itemsToPlace, item{id: id, area: area, variants: shapeVariants})
|
||||||
|
}
|
||||||
|
|
||||||
|
if totalArea > width*height {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(itemsToPlace, func(i, j int) bool {
|
||||||
|
return itemsToPlace[i].area > itemsToPlace[j].area
|
||||||
|
})
|
||||||
|
|
||||||
|
grid := make([][]bool, height)
|
||||||
|
|
||||||
|
for i := range grid {
|
||||||
|
grid[i] = make([]bool, width)
|
||||||
|
}
|
||||||
|
|
||||||
|
return checkFit(0, itemsToPlace, grid, width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFit(index int, itemsToPlace []item, grid [][]bool, width int, height int) bool {
|
||||||
|
if index == len(itemsToPlace) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
itemToPlace := itemsToPlace[index]
|
||||||
|
|
||||||
|
for _, variant := range itemToPlace.variants {
|
||||||
|
maxRow := variant.MaxRow()
|
||||||
|
maxColumn := variant.MaxColumn()
|
||||||
|
|
||||||
|
lastRow := height - maxRow
|
||||||
|
lastColumn := width - maxColumn
|
||||||
|
|
||||||
|
for r := range lastRow {
|
||||||
|
for c := range lastColumn {
|
||||||
|
if canPlace(grid, r, c, variant) {
|
||||||
|
place(grid, r, c, variant)
|
||||||
|
|
||||||
|
if checkFit(index+1, itemsToPlace, grid, width, height) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
unplace(grid, r, c, variant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func canPlace(grid [][]bool, r, c int, variant shape.Shape) bool {
|
||||||
|
for _, position := range variant.Positions() {
|
||||||
|
absoluteRow := r + position.Row()
|
||||||
|
absoluteColumn := c + position.Column()
|
||||||
|
isOccupied := grid[absoluteRow][absoluteColumn]
|
||||||
|
|
||||||
|
if isOccupied {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func place(grid [][]bool, r, c int, variant shape.Shape) {
|
||||||
|
for _, position := range variant.Positions() {
|
||||||
|
absoluteRow := r + position.Row()
|
||||||
|
absoluteColumn := c + position.Column()
|
||||||
|
grid[absoluteRow][absoluteColumn] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unplace(grid [][]bool, r, c int, variant shape.Shape) {
|
||||||
|
for _, position := range variant.Positions() {
|
||||||
|
absoluteRow := r + position.Row()
|
||||||
|
absoluteColumn := c + position.Column()
|
||||||
|
grid[absoluteRow][absoluteColumn] = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-2
@@ -6,8 +6,9 @@ import (
|
|||||||
solution "github.com/StevanFreeborn/advent-of-code-2025/cmd/12"
|
solution "github.com/StevanFreeborn/advent-of-code-2025/cmd/12"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSolvePartOne(t *testing.T) {
|
// NOTE: This takes long time
|
||||||
expected := -1
|
func TestSolvePartOneWithExampleInput(t *testing.T) {
|
||||||
|
expected := 2
|
||||||
|
|
||||||
result := solution.SolvePartOne("EXAMPLE.txt")
|
result := solution.SolvePartOne("EXAMPLE.txt")
|
||||||
|
|
||||||
@@ -15,3 +16,13 @@ func TestSolvePartOne(t *testing.T) {
|
|||||||
t.Errorf("got %d but wanted %d", result, expected)
|
t.Errorf("got %d but wanted %d", result, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSolvePartOneWithInput(t *testing.T) {
|
||||||
|
expected := 550
|
||||||
|
|
||||||
|
result := solution.SolvePartOne("INPUT.txt")
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("got %d but wanted %d", result, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+68
-21
@@ -11,14 +11,17 @@ import (
|
|||||||
"github.com/StevanFreeborn/advent-of-code-2025/internal/position"
|
"github.com/StevanFreeborn/advent-of-code-2025/internal/position"
|
||||||
)
|
)
|
||||||
|
|
||||||
// shape.GenerateAllVariants() []Shape
|
|
||||||
|
|
||||||
type Shape interface {
|
type Shape interface {
|
||||||
Id() int
|
Id() int
|
||||||
GetKey() string
|
GetKey() string
|
||||||
GenerateVariants() []Shape
|
GenerateVariants() []Shape
|
||||||
RotateClockwise() Shape
|
RotateClockwise() Shape
|
||||||
FlipVertically() Shape
|
FlipVertically() Shape
|
||||||
|
String() string
|
||||||
|
Area() int
|
||||||
|
MaxRow() int
|
||||||
|
MaxColumn() int
|
||||||
|
Positions() []position.Position
|
||||||
}
|
}
|
||||||
|
|
||||||
type shape struct {
|
type shape struct {
|
||||||
@@ -46,37 +49,81 @@ func From(lines []string) Shape {
|
|||||||
return shape{id: id, positions: positions}
|
return shape{id: id, positions: positions}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s shape) Positions() []position.Position {
|
||||||
|
return s.positions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s shape) MaxRow() int {
|
||||||
|
maxRow := 0
|
||||||
|
|
||||||
|
for _, p := range s.positions {
|
||||||
|
if p.Row() > maxRow {
|
||||||
|
maxRow = p.Row()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxRow
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s shape) MaxColumn() int {
|
||||||
|
maxColumn := 0
|
||||||
|
|
||||||
|
for _, p := range s.positions {
|
||||||
|
if p.Column() > maxColumn {
|
||||||
|
maxColumn = p.Column()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxColumn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s shape) Area() int {
|
||||||
|
return len(s.positions)
|
||||||
|
}
|
||||||
|
|
||||||
func (s shape) GenerateVariants() []Shape {
|
func (s shape) GenerateVariants() []Shape {
|
||||||
shapes := []Shape{}
|
shapes := []Shape{}
|
||||||
var current Shape
|
var current Shape
|
||||||
current = s
|
current = s
|
||||||
numberOfTransformations := 4
|
numberOfTransformations := 4
|
||||||
|
|
||||||
// Rotate 90 clockwise
|
|
||||||
for range numberOfTransformations {
|
|
||||||
current = current.RotateClockwise()
|
|
||||||
shapes = append(shapes, current)
|
|
||||||
}
|
|
||||||
|
|
||||||
current = s
|
|
||||||
|
|
||||||
// Flip then rotate 90 clockwise
|
|
||||||
for range numberOfTransformations {
|
for range numberOfTransformations {
|
||||||
shapes = append(shapes, current)
|
shapes = append(shapes, current)
|
||||||
flipped := current.FlipVertically()
|
flipped := current.FlipVertically()
|
||||||
shapes = append(shapes, flipped)
|
shapes = append(shapes, flipped)
|
||||||
current = flipped.RotateClockwise()
|
current = current.RotateClockwise()
|
||||||
}
|
}
|
||||||
|
|
||||||
current = s
|
// // Rotate 90 clockwise
|
||||||
|
// for range numberOfTransformations {
|
||||||
// Rotate 90 clockwise then flip
|
// current = current.RotateClockwise()
|
||||||
for range numberOfTransformations {
|
// shapes = append(shapes, current)
|
||||||
shapes = append(shapes, current)
|
// }
|
||||||
rotated := current.RotateClockwise()
|
//
|
||||||
shapes = append(shapes, rotated)
|
// current = s
|
||||||
current = rotated.FlipVertically()
|
//
|
||||||
}
|
// // Flip then rotate 90 clockwise
|
||||||
|
// for range numberOfTransformations {
|
||||||
|
// shapes = append(shapes, current)
|
||||||
|
// flipped := current.FlipVertically()
|
||||||
|
// shapes = append(shapes, flipped)
|
||||||
|
// current = flipped.RotateClockwise()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// current = s
|
||||||
|
//
|
||||||
|
// // Rotate 90 clockwise then flip
|
||||||
|
// for range numberOfTransformations {
|
||||||
|
// shapes = append(shapes, current)
|
||||||
|
// rotated := current.RotateClockwise()
|
||||||
|
// shapes = append(shapes, rotated)
|
||||||
|
// current = rotated.FlipVertically()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// current = s
|
||||||
|
// rotated := current.RotateClockwise().RotateClockwise()
|
||||||
|
// flipped := rotated.FlipVertically()
|
||||||
|
// shapes = append(shapes, flipped)
|
||||||
|
|
||||||
seenShapes := map[string]Shape{}
|
seenShapes := map[string]Shape{}
|
||||||
|
|
||||||
|
|||||||
+141
-1
@@ -1,9 +1,149 @@
|
|||||||
package shape_test
|
package shape_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/12/shape"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFrom(t *testing.T) {
|
func TestGenerateVariants(t *testing.T) {
|
||||||
|
t.Run("works for shape 0", func(t *testing.T) {
|
||||||
|
expectedVariants := [][]string{
|
||||||
|
{
|
||||||
|
"###",
|
||||||
|
"##.",
|
||||||
|
"##.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"###",
|
||||||
|
".##",
|
||||||
|
".##",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"###",
|
||||||
|
"###",
|
||||||
|
"#..",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"###",
|
||||||
|
"###",
|
||||||
|
"..#",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
".##",
|
||||||
|
".##",
|
||||||
|
"###",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"##.",
|
||||||
|
"##.",
|
||||||
|
"###",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := []string{
|
||||||
|
"0:",
|
||||||
|
"###",
|
||||||
|
"##.",
|
||||||
|
"##.",
|
||||||
|
}
|
||||||
|
|
||||||
|
shape := shape.From(lines)
|
||||||
|
|
||||||
|
result := shape.GenerateVariants()
|
||||||
|
|
||||||
|
for _, ev := range expectedVariants {
|
||||||
|
expected := strings.Join(ev, "\n")
|
||||||
|
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for _, v := range result {
|
||||||
|
if strings.TrimSpace(v.String()) == expected {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found == false {
|
||||||
|
t.Errorf("expected to find variant but did not:\n%v", expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("works for shape 1", func(t *testing.T) {
|
||||||
|
expectedVariants := [][]string{
|
||||||
|
{
|
||||||
|
"###",
|
||||||
|
"##.",
|
||||||
|
".##",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
".##",
|
||||||
|
"###",
|
||||||
|
"#.#",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"##.",
|
||||||
|
".##",
|
||||||
|
"###",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"#.#",
|
||||||
|
"###",
|
||||||
|
"##.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"###",
|
||||||
|
".##",
|
||||||
|
"##.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"##.",
|
||||||
|
"###",
|
||||||
|
"#.#",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"##.",
|
||||||
|
"###",
|
||||||
|
"#.#",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
".##",
|
||||||
|
"##.",
|
||||||
|
"###",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"#.#",
|
||||||
|
"###",
|
||||||
|
".##",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := []string{
|
||||||
|
"0:",
|
||||||
|
"###",
|
||||||
|
"##.",
|
||||||
|
".##",
|
||||||
|
}
|
||||||
|
|
||||||
|
shape := shape.From(lines)
|
||||||
|
|
||||||
|
result := shape.GenerateVariants()
|
||||||
|
|
||||||
|
for _, ev := range expectedVariants {
|
||||||
|
expected := strings.Join(ev, "\n")
|
||||||
|
|
||||||
|
found := false
|
||||||
|
|
||||||
|
for _, v := range result {
|
||||||
|
if strings.TrimSpace(v.String()) == expected {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if found == false {
|
||||||
|
t.Errorf("expected to find variant but did not:\n%v", expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user