Merge pull request #1 from StevanFreeborn/stevanfreeborn/feat/solve-day-one-part-one
feat: solve day 1 part 1
This commit is contained in:
@@ -0,0 +1,48 @@
|
|||||||
|
// Package dial provides a model for representing a dial
|
||||||
|
package dial
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/01/direction"
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/01/instruction"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Dial interface {
|
||||||
|
Value() int
|
||||||
|
Turn(instruction instruction.Instruction)
|
||||||
|
}
|
||||||
|
|
||||||
|
type dial struct {
|
||||||
|
value int
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() Dial {
|
||||||
|
return &dial{
|
||||||
|
value: 50,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dial) Value() int {
|
||||||
|
return d.value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *dial) Turn(instruction instruction.Instruction) {
|
||||||
|
if instruction.Direction() == direction.Left {
|
||||||
|
d.value -= instruction.Distance()
|
||||||
|
|
||||||
|
for d.value < 0 {
|
||||||
|
d.value += 100
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if instruction.Direction() == direction.Right {
|
||||||
|
d.value += instruction.Distance()
|
||||||
|
|
||||||
|
for d.value > 99 {
|
||||||
|
d.value -= 100
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package dial_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/01/dial"
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/01/instruction"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
expectedStartingValue := 50
|
||||||
|
result := dial.New()
|
||||||
|
|
||||||
|
if result.Value() != expectedStartingValue {
|
||||||
|
t.Errorf("got unexpected beginning value. expected %d but got %d", expectedStartingValue, result.Value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TurnTestCase struct {
|
||||||
|
Instruction instruction.Instruction
|
||||||
|
ExpectedDialValue int
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTurn(t *testing.T) {
|
||||||
|
testCases := []TurnTestCase{
|
||||||
|
{
|
||||||
|
Instruction: instruction.FromParts("L", 68),
|
||||||
|
ExpectedDialValue: 82,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Instruction: instruction.FromParts("L", 30),
|
||||||
|
ExpectedDialValue: 52,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Instruction: instruction.FromParts("R", 48),
|
||||||
|
ExpectedDialValue: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Instruction: instruction.FromParts("L", 5),
|
||||||
|
ExpectedDialValue: 95,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Instruction: instruction.FromParts("R", 60),
|
||||||
|
ExpectedDialValue: 55,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Instruction: instruction.FromParts("L", 55),
|
||||||
|
ExpectedDialValue: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Instruction: instruction.FromParts("L", 1),
|
||||||
|
ExpectedDialValue: 99,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Instruction: instruction.FromParts("L", 99),
|
||||||
|
ExpectedDialValue: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Instruction: instruction.FromParts("R", 14),
|
||||||
|
ExpectedDialValue: 14,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Instruction: instruction.FromParts("L", 82),
|
||||||
|
ExpectedDialValue: 32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
dial := dial.New()
|
||||||
|
|
||||||
|
for i, testCase := range testCases {
|
||||||
|
|
||||||
|
dial.Turn(testCase.Instruction)
|
||||||
|
|
||||||
|
if dial.Value() != testCase.ExpectedDialValue {
|
||||||
|
t.Errorf("%d: got dial value %d, but expected dial value %d", i, dial.Value(), testCase.ExpectedDialValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// Package direction provides constants for left and right directions.
|
||||||
|
package direction
|
||||||
|
|
||||||
|
const Left = "L"
|
||||||
|
const Right = "R"
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// Package instruction provides a model for representing dial instructions
|
||||||
|
package instruction
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
type Instruction interface {
|
||||||
|
Direction() string
|
||||||
|
Distance() int
|
||||||
|
}
|
||||||
|
|
||||||
|
type instruction struct {
|
||||||
|
direction string
|
||||||
|
distance int
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromLine(line string) Instruction {
|
||||||
|
dir := string(line[0])
|
||||||
|
dist := line[1:]
|
||||||
|
distAsInt, _ := strconv.Atoi(dist)
|
||||||
|
|
||||||
|
return instruction{
|
||||||
|
direction: dir,
|
||||||
|
distance: distAsInt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromParts(direction string, distance int) Instruction {
|
||||||
|
return instruction{
|
||||||
|
direction: direction,
|
||||||
|
distance: distance,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i instruction) Direction() string {
|
||||||
|
return i.direction
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i instruction) Distance() int {
|
||||||
|
return i.distance
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package instruction_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/01/instruction"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFromLine(t *testing.T) {
|
||||||
|
expectedDirection := "L"
|
||||||
|
expectedDistance := 7
|
||||||
|
line := fmt.Sprintf("%s%d", expectedDirection, expectedDistance)
|
||||||
|
|
||||||
|
result := instruction.FromLine(line)
|
||||||
|
|
||||||
|
if result.Direction() != expectedDirection {
|
||||||
|
t.Errorf("got direction %s but expected direction %s", result.Direction(), expectedDirection)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Distance() != expectedDistance {
|
||||||
|
t.Errorf("got distance %d but expected distance %d", result.Distance(), expectedDistance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromParts(t *testing.T) {
|
||||||
|
expectedDirection := "L"
|
||||||
|
expectedDistance := 7
|
||||||
|
|
||||||
|
result := instruction.FromParts(expectedDirection, expectedDistance)
|
||||||
|
|
||||||
|
if result.Direction() != expectedDirection {
|
||||||
|
t.Errorf("got direction %s but expected direction %s", result.Direction(), expectedDirection)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.Distance() != expectedDistance {
|
||||||
|
t.Errorf("got distance %d but expected distance %d", result.Distance(), expectedDistance)
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
-1
@@ -1,5 +1,28 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/01/dial"
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/cmd/01/instruction"
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/internal/file"
|
||||||
|
)
|
||||||
|
|
||||||
func SolvePartOne(filePath string) int {
|
func SolvePartOne(filePath string) int {
|
||||||
return 0
|
lines := file.ReadLines(filePath)
|
||||||
|
dial := dial.New()
|
||||||
|
total := 0
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction := instruction.FromLine(line)
|
||||||
|
dial.Turn(instruction)
|
||||||
|
|
||||||
|
if dial.Value() == 0 {
|
||||||
|
total++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-2
@@ -7,11 +7,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestSolvePartOneWithExampleInput(t *testing.T) {
|
func TestSolvePartOneWithExampleInput(t *testing.T) {
|
||||||
expected := -1
|
expected := 3
|
||||||
|
|
||||||
result := solution.SolvePartOne("EXAMPLE.txt")
|
result := solution.SolvePartOne("EXAMPLE.txt")
|
||||||
|
|
||||||
if result != expected {
|
if result != expected {
|
||||||
t.Errorf("SolvePartOne() = %d; want %d", result, expected)
|
t.Errorf(`SolvePartOne("EXAMPLE.txt") = %d; want %d`, result, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSolvePartOneWithInput(t *testing.T) {
|
||||||
|
expected := 1011
|
||||||
|
|
||||||
|
result := solution.SolvePartOne("INPUT.txt")
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf(`SolvePartOne("INPUT.txt") = %d; want %d`, result, expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// Package file provides useful methods for interacting with files
|
||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ReadLines(filePath string) []string {
|
||||||
|
lines := []string{}
|
||||||
|
|
||||||
|
file, openErr := os.Open(filePath)
|
||||||
|
|
||||||
|
if openErr != nil {
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
for hasLine := scanner.Scan(); hasLine; hasLine = scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
fmt.Println(line)
|
||||||
|
lines = append(lines, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package file_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/StevanFreeborn/advent-of-code-2025/internal/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadLines(t *testing.T) {
|
||||||
|
expectedLines := []string{
|
||||||
|
"hello",
|
||||||
|
"world",
|
||||||
|
}
|
||||||
|
|
||||||
|
result := file.ReadLines("test.txt")
|
||||||
|
|
||||||
|
if slices.Equal(result, expectedLines) == false {
|
||||||
|
t.Errorf("got %s but expected %s", result, expectedLines)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
hello
|
||||||
|
world
|
||||||
Reference in New Issue
Block a user