refactor: edge and rectangle in separate packages
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
// Package edge provides a model and methods for representing and manipulating edges.
|
||||
package edge
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/StevanFreeborn/advent-of-code-2025/cmd/09/rectangle"
|
||||
"github.com/StevanFreeborn/advent-of-code-2025/internal/position"
|
||||
)
|
||||
|
||||
type Edge interface {
|
||||
Start() position.Position
|
||||
End() position.Position
|
||||
VerticallyContains(position.Position) bool
|
||||
IntersectsHorizontalLineAt(position.Position) bool
|
||||
Intersects(rect rectangle.Rectangle) bool
|
||||
}
|
||||
|
||||
type edge struct {
|
||||
start position.Position
|
||||
end position.Position
|
||||
totalHeight int
|
||||
totalWidth int
|
||||
minRow float64
|
||||
maxRow float64
|
||||
minColumn float64
|
||||
maxColumn float64
|
||||
}
|
||||
|
||||
func From(start position.Position, end position.Position) Edge {
|
||||
totalHeight := int(math.Abs(float64(end.Row() - start.Row())))
|
||||
totalWidth := int(math.Abs(float64(end.Column() - start.Column())))
|
||||
|
||||
minRow := math.Min(float64(start.Row()), float64(end.Row()))
|
||||
maxRow := math.Max(float64(start.Row()), float64(end.Row()))
|
||||
minColumn := math.Min(float64(start.Column()), float64(end.Column()))
|
||||
maxColumn := math.Max(float64(start.Column()), float64(end.Column()))
|
||||
|
||||
return edge{
|
||||
start: start,
|
||||
end: end,
|
||||
totalHeight: totalHeight,
|
||||
totalWidth: totalWidth,
|
||||
minRow: minRow,
|
||||
maxRow: maxRow,
|
||||
minColumn: minColumn,
|
||||
maxColumn: maxColumn,
|
||||
}
|
||||
}
|
||||
|
||||
func (e edge) Start() position.Position {
|
||||
return e.start
|
||||
}
|
||||
|
||||
func (e edge) End() position.Position {
|
||||
return e.end
|
||||
}
|
||||
|
||||
func (e edge) VerticallyContains(p position.Position) bool {
|
||||
return (e.start.Row() <= p.Row()) && (p.Row() <= e.end.Row())
|
||||
}
|
||||
|
||||
func (e edge) IntersectsHorizontalLineAt(p position.Position) bool {
|
||||
centerPercentageOfEdgeHeight := int(float64(p.Row()-e.start.Row()) / float64(e.totalHeight))
|
||||
edgeColumnAtCenterRow := e.start.Column() + centerPercentageOfEdgeHeight*e.totalWidth
|
||||
return p.Row() <= edgeColumnAtCenterRow
|
||||
}
|
||||
|
||||
func (e edge) Intersects(rect rectangle.Rectangle) bool {
|
||||
isVerticalEdge := e.start.Column() == e.end.Column()
|
||||
|
||||
if isVerticalEdge {
|
||||
isRectBetweenEdgeColumns := e.start.Column() > rect.MinColumn() && e.start.Column() < rect.MaxColumn()
|
||||
|
||||
if isRectBetweenEdgeColumns {
|
||||
overlapStart := int(math.Max(e.minRow, float64(rect.MinRow())))
|
||||
overlapEnd := int(math.Min(e.maxRow, float64(rect.MaxRow())))
|
||||
|
||||
if overlapEnd > overlapStart {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isRectBetweenEdgeRows := e.start.Row() > rect.MinRow() && e.start.Row() < rect.MaxRow()
|
||||
|
||||
if isRectBetweenEdgeRows {
|
||||
overlapStart := int(math.Max(e.minColumn, float64(rect.MinColumn())))
|
||||
overlapEnd := int(math.Min(e.maxColumn, float64(rect.MaxColumn())))
|
||||
|
||||
if overlapEnd > overlapStart {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package edge_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/StevanFreeborn/advent-of-code-2025/cmd/09/edge"
|
||||
"github.com/StevanFreeborn/advent-of-code-2025/internal/position"
|
||||
)
|
||||
|
||||
func TestFrom(t *testing.T) {
|
||||
start := position.From(1, 2)
|
||||
end := position.From(3, 4)
|
||||
|
||||
e := edge.From(start, end)
|
||||
|
||||
if e.Start() != start {
|
||||
t.Errorf("Expected start position %v, got %v", start, e.Start())
|
||||
}
|
||||
|
||||
if e.End() != end {
|
||||
t.Errorf("Expected end position %v, got %v", end, e.End())
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerticallyContains(t *testing.T) {
|
||||
start := position.From(1, 2)
|
||||
end := position.From(3, 4)
|
||||
e := edge.From(start, end)
|
||||
|
||||
tests := []struct {
|
||||
p position.Position
|
||||
expected bool
|
||||
}{
|
||||
{position.From(2, 3), true},
|
||||
{position.From(1, 2), true},
|
||||
{position.From(3, 4), true},
|
||||
{position.From(0, 0), false},
|
||||
{position.From(4, 5), false},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
result := e.VerticallyContains(test.p)
|
||||
|
||||
if result != test.expected {
|
||||
t.Errorf("VerticallyContains(%v) = %v; want %v", test.p, result, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntersectsHorizontalLineAt(t *testing.T) {
|
||||
start := position.From(1, 2)
|
||||
end := position.From(3, 4)
|
||||
e := edge.From(start, end)
|
||||
|
||||
tests := []struct {
|
||||
p position.Position
|
||||
expected bool
|
||||
}{
|
||||
{position.From(2, 3), true},
|
||||
{position.From(1, 2), true},
|
||||
{position.From(3, 4), true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
result := e.IntersectsHorizontalLineAt(test.p)
|
||||
|
||||
if result != test.expected {
|
||||
t.Errorf("IntersectsHorizontalLineAt(%v) = %v; want %v", test.p, result, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user