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
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/StevanFreeborn/advent-of-code-2025/cmd/02/rnge"
|
||||
"github.com/StevanFreeborn/advent-of-code-2025/internal/file"
|
||||
)
|
||||
|
||||
const SeparatorCharacter = ","
|
||||
const RangeSeparatorCharacter = "-"
|
||||
|
||||
type Range struct {
|
||||
Start int64
|
||||
End int64
|
||||
}
|
||||
|
||||
func SolvePartOne(filePath string) int64 {
|
||||
bytes, readErr := os.ReadFile(filePath)
|
||||
|
||||
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)
|
||||
}
|
||||
input := file.ReadAllText(filePath)
|
||||
strRanges := strings.SplitSeq(input, SeparatorCharacter)
|
||||
|
||||
total := int64(0)
|
||||
|
||||
for _, rng := range rngs {
|
||||
for id := rng.Start; id <= rng.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
|
||||
}
|
||||
for r := range strRanges {
|
||||
rng := rnge.From(r)
|
||||
|
||||
for id := range rng.InvalidIds() {
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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