feat: wip on day 12 part 1

This commit is contained in:
Stevan Freeborn
2025-12-23 08:18:01 -06:00
parent f693c4b71f
commit f99af72e2e
4 changed files with 302 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
package main
import (
"fmt"
"strings"
"github.com/StevanFreeborn/advent-of-code-2025/cmd/12/shape"
"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 X = "x"
func SolvePartOne(filePath string) int {
input := file.ReadAllText(filePath)
sections := strings.Split(strings.TrimSpace(input), NEWLINE+NEWLINE)
shapes := []shape.Shape{}
regions := []string{}
for _, section := range sections {
lines := strings.Split(strings.TrimSpace(section), NEWLINE)
header := lines[0]
if strings.Contains(header, COLON) && strings.Contains(header, X) == false {
shapes = append(shapes, shape.From(lines))
continue
}
for _, line := range lines {
if strings.Contains(line, COLON) {
regions = append(regions, line)
}
}
}
// TODO: We are currently not generating
// all the expected variants. Need to debug this
// WRITE AUTOMATED UNIT TESTS DUMMY
// WHEN YOU READ THIS IN THE FUTURE YOU ARE GOING
// TO WANT TO IGNORE IT...DON'T!
// - Past Stevan
for _, s := range shapes {
if s.Id() != 1 && s.Id() != 2 && s.Id() != 0 {
continue
}
fmt.Println("SHAPE ID", s.Id())
for _, v := range s.GenerateVariants() {
fmt.Println(v)
}
}
return 0
}
+17
View File
@@ -0,0 +1,17 @@
package main_test
import (
"testing"
solution "github.com/StevanFreeborn/advent-of-code-2025/cmd/12"
)
func TestSolvePartOne(t *testing.T) {
expected := -1
result := solution.SolvePartOne("EXAMPLE.txt")
if result != expected {
t.Errorf("got %d but wanted %d", result, expected)
}
}
+217
View File
@@ -0,0 +1,217 @@
// Package shape provides a model and methods for representing and manipulating shapes
package shape
import (
"fmt"
"maps"
"slices"
"strconv"
"strings"
"github.com/StevanFreeborn/advent-of-code-2025/internal/position"
)
// shape.GenerateAllVariants() []Shape
type Shape interface {
Id() int
GetKey() string
GenerateVariants() []Shape
RotateClockwise() Shape
FlipVertically() Shape
}
type shape struct {
id int
positions []position.Position
}
func From(lines []string) Shape {
idStr := strings.TrimSuffix(lines[0], ":")
id, _ := strconv.Atoi(idStr)
positions := []position.Position{}
for r, line := range lines[1:] {
for c, char := range line {
if char != '#' {
continue
}
position := position.From(r, c)
positions = append(positions, position)
}
}
return shape{id: id, positions: positions}
}
func (s shape) GenerateVariants() []Shape {
shapes := []Shape{}
var current Shape
current = s
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 {
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()
}
seenShapes := map[string]Shape{}
for _, s := range shapes {
seenShapes[s.GetKey()] = s
}
return slices.Collect(maps.Values(seenShapes))
}
func (s shape) RotateClockwise() Shape {
rotatedPositions := []position.Position{}
for _, p := range s.positions {
rotatedPosition := position.From(p.Column(), -p.Row())
rotatedPositions = append(rotatedPositions, rotatedPosition)
}
rotatedShape := shape{
id: s.id,
positions: rotatedPositions,
}
return normalize(rotatedShape)
}
func (s shape) FlipVertically() Shape {
flippedPositions := []position.Position{}
for _, p := range s.positions {
flippedPosition := position.From(p.Row(), -p.Column())
flippedPositions = append(flippedPositions, flippedPosition)
}
flippedShape := shape{
id: s.id,
positions: flippedPositions,
}
return normalize(flippedShape)
}
func (s shape) GetKey() string {
var sb strings.Builder
for _, p := range s.positions {
fmt.Fprintf(&sb, "%d,%d|", p.Row(), p.Column())
}
return sb.String()
}
func (s shape) Id() int {
return s.id
}
func normalize(s shape) Shape {
if len(s.positions) == 0 {
return shape{
id: s.id,
positions: s.positions,
}
}
minRow := s.positions[0].Row()
minColumn := s.positions[0].Column()
for _, p := range s.positions {
if p.Row() < minRow {
minRow = p.Row()
}
if p.Column() < minColumn {
minColumn = p.Column()
}
}
nps := []position.Position{}
for _, p := range s.positions {
nr := p.Row() - minRow
nc := p.Column() - minColumn
np := position.From(nr, nc)
nps = append(nps, np)
}
return shape{
id: s.id,
positions: nps,
}
}
func (s shape) String() string {
if len(s.positions) == 0 {
return "(EMPTY SHAPE)"
}
maxRow := 0
maxColumn := 0
for _, p := range s.positions {
if p.Row() > maxRow {
maxRow = p.Row()
}
if p.Column() > maxColumn {
maxColumn = p.Column()
}
}
tempGrid := make([][]string, maxRow+1)
for r := range tempGrid {
tempGrid[r] = make([]string, maxColumn+1)
for c := range tempGrid[r] {
tempGrid[r][c] = "."
}
}
for _, p := range s.positions {
tempGrid[p.Row()][p.Column()] = "#"
}
var shape strings.Builder
for _, row := range tempGrid {
var rowString strings.Builder
for _, str := range row {
rowString.WriteString(str)
}
shape.WriteString(rowString.String() + "\n")
}
return shape.String()
}
+9
View File
@@ -0,0 +1,9 @@
package shape_test
import (
"testing"
)
func TestFrom(t *testing.T) {
}