Merge pull request #4 from StevanFreeborn/stevanfreeborn/refactor/clean-up-day-two-part-one
refactor: clean up day two part one
This commit is contained in:
+8
-45
@@ -1,61 +1,24 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/02/rnge"
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/internal/file"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SeparatorCharacter = ","
|
const SeparatorCharacter = ","
|
||||||
const RangeSeparatorCharacter = "-"
|
|
||||||
|
|
||||||
type Range struct {
|
|
||||||
Start int64
|
|
||||||
End int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func SolvePartOne(filePath string) int64 {
|
func SolvePartOne(filePath string) int64 {
|
||||||
bytes, readErr := os.ReadFile(filePath)
|
input := file.ReadAllText(filePath)
|
||||||
|
strRanges := strings.SplitSeq(input, SeparatorCharacter)
|
||||||
if readErr != nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
strRanges := strings.SplitSeq(string(bytes), SeparatorCharacter)
|
|
||||||
|
|
||||||
rngs := []Range{}
|
|
||||||
|
|
||||||
for r := range strRanges {
|
|
||||||
parts := strings.Split(strings.TrimSpace(r), "-")
|
|
||||||
start, _ := strconv.ParseInt(parts[0], 10, 64)
|
|
||||||
end, _ := strconv.ParseInt(parts[1], 10, 64)
|
|
||||||
rng := Range{
|
|
||||||
Start: start,
|
|
||||||
End: end,
|
|
||||||
}
|
|
||||||
rngs = append(rngs, rng)
|
|
||||||
}
|
|
||||||
|
|
||||||
total := int64(0)
|
total := int64(0)
|
||||||
|
|
||||||
for _, rng := range rngs {
|
for r := range strRanges {
|
||||||
for id := rng.Start; id <= rng.End; id++ {
|
rng := rnge.From(r)
|
||||||
idStr := strconv.FormatInt(id, 10)
|
|
||||||
idLength := len(idStr)
|
|
||||||
|
|
||||||
if idLength%2 != 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
midpoint := idLength / 2
|
|
||||||
|
|
||||||
firstHalf := idStr[:midpoint]
|
|
||||||
secondHalf := idStr[midpoint:]
|
|
||||||
|
|
||||||
if firstHalf != secondHalf {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for id := range rng.InvalidIds() {
|
||||||
total += id
|
total += id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// Package rnge provides a simple structure to represent a range with a start and end value.
|
||||||
|
package rnge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"iter"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const RangeSeparatorCharacter = "-"
|
||||||
|
|
||||||
|
type Range interface {
|
||||||
|
InvalidIds() iter.Seq[int64]
|
||||||
|
Start() int64
|
||||||
|
End() int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type rnge struct {
|
||||||
|
start int64
|
||||||
|
end int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func From(rngeStr string) Range {
|
||||||
|
parts := strings.Split(strings.TrimSpace(rngeStr), RangeSeparatorCharacter)
|
||||||
|
start, _ := strconv.ParseInt(parts[0], 10, 64)
|
||||||
|
end, _ := strconv.ParseInt(parts[1], 10, 64)
|
||||||
|
|
||||||
|
return rnge{
|
||||||
|
start: start,
|
||||||
|
end: end,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r rnge) Start() int64 {
|
||||||
|
return r.start
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r rnge) End() int64 {
|
||||||
|
return r.end
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r rnge) InvalidIds() iter.Seq[int64] {
|
||||||
|
return func(yield func(int64) bool) {
|
||||||
|
for id := r.start; id <= r.end; id++ {
|
||||||
|
idStr := strconv.FormatInt(id, 10)
|
||||||
|
idLength := len(idStr)
|
||||||
|
|
||||||
|
if idLength%2 != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
midpoint := idLength / 2
|
||||||
|
firstHalf := idStr[:midpoint]
|
||||||
|
secondHalf := idStr[midpoint:]
|
||||||
|
|
||||||
|
if firstHalf != secondHalf {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ok := yield(id)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package rnge_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/02/rnge"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFrom(t *testing.T) {
|
||||||
|
expectedStart := int64(1000)
|
||||||
|
expectedEnd := int64(2000)
|
||||||
|
|
||||||
|
r := rnge.From("1000-2000")
|
||||||
|
|
||||||
|
if r.Start() != expectedStart {
|
||||||
|
t.Errorf("expected start %d, got %d", expectedStart, r.Start())
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.End() != expectedEnd {
|
||||||
|
t.Errorf("expected end %d, got %d", expectedEnd, r.End())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStart(t *testing.T) {
|
||||||
|
expectedStart := int64(500)
|
||||||
|
|
||||||
|
r := rnge.From("500-1500")
|
||||||
|
|
||||||
|
if r.Start() != expectedStart {
|
||||||
|
t.Errorf("expected start %d, got %d", expectedStart, r.Start())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnd(t *testing.T) {
|
||||||
|
expectedEnd := int64(1500)
|
||||||
|
|
||||||
|
r := rnge.From("500-1500")
|
||||||
|
|
||||||
|
if r.End() != expectedEnd {
|
||||||
|
t.Errorf("expected end %d, got %d", expectedEnd, r.End())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidIds(t *testing.T) {
|
||||||
|
r := rnge.From("1000-1100")
|
||||||
|
expectedInvalidIds := []int64{1010}
|
||||||
|
resultInvalidIds := []int64{}
|
||||||
|
|
||||||
|
for id := range r.InvalidIds() {
|
||||||
|
resultInvalidIds = append(resultInvalidIds, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if slices.Equal(resultInvalidIds, expectedInvalidIds) == false {
|
||||||
|
t.Errorf("expected invalid IDs %v, got %v", expectedInvalidIds, resultInvalidIds)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,3 +24,13 @@ func ReadLines(filePath string) []string {
|
|||||||
|
|
||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadAllText(filePath string) string {
|
||||||
|
fileContent, readErr := os.ReadFile(filePath)
|
||||||
|
|
||||||
|
if readErr != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(fileContent)
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,3 +19,13 @@ func TestReadLines(t *testing.T) {
|
|||||||
t.Errorf("got %s but expected %s", result, expectedLines)
|
t.Errorf("got %s but expected %s", result, expectedLines)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadAllText(t *testing.T) {
|
||||||
|
expectedText := "hello\r\nworld\r\n"
|
||||||
|
|
||||||
|
result := file.ReadAllText("test.txt")
|
||||||
|
|
||||||
|
if result != expectedText {
|
||||||
|
t.Errorf("got %q but expected %q", result, expectedText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user