Solution to submarine navigation
This commit is contained in:
3
main.go
3
main.go
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"unsupervised.ca/aoc2021/one"
|
||||
"unsupervised.ca/aoc2021/two"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -25,6 +26,8 @@ func main() {
|
||||
switch flagParts[1] {
|
||||
case "one":
|
||||
day = one.Init("one/input.txt")
|
||||
case "two":
|
||||
day = two.Init("two/input.txt")
|
||||
default:
|
||||
fmt.Printf("%q does not have a solution.\n", flagParts[1])
|
||||
help()
|
||||
|
1000
two/input.txt
Normal file
1000
two/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
39
two/main.go
Normal file
39
two/main.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package two
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Two struct {
|
||||
sub sub
|
||||
}
|
||||
|
||||
func Init(filepath string) *Two {
|
||||
two := &Two{
|
||||
sub: sub{},
|
||||
}
|
||||
|
||||
two.sub.load(filepath)
|
||||
|
||||
return two
|
||||
}
|
||||
|
||||
func (d *Two) Answer() string {
|
||||
d.sub.reset()
|
||||
d.sub.execute()
|
||||
|
||||
return fmt.Sprintf("Horizontal is %d, depth is %d, answer is %d",
|
||||
d.sub.horizontal,
|
||||
d.sub.depth,
|
||||
d.sub.horizontal*d.sub.depth,
|
||||
)
|
||||
}
|
||||
|
||||
func (d *Two) FollowUp() string {
|
||||
d.sub.reset()
|
||||
d.sub.executeWithAim()
|
||||
|
||||
return fmt.Sprintf("Horizontal is %d, depth is %d, answer is %d",
|
||||
d.sub.horizontal,
|
||||
d.sub.depth,
|
||||
d.sub.horizontal*d.sub.depth,
|
||||
)
|
||||
}
|
87
two/sub.go
Normal file
87
two/sub.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package two
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type command struct {
|
||||
instruction string
|
||||
value int
|
||||
}
|
||||
|
||||
type sub struct {
|
||||
input []command
|
||||
depth int
|
||||
horizontal int
|
||||
aim int
|
||||
}
|
||||
|
||||
// load Loads the commands from input.txt into the sub
|
||||
func (s *sub) load(filename string) error {
|
||||
s.input = []command{}
|
||||
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
parts := strings.Split(scanner.Text(), " ")
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("Unable to parse input: %s", parts)
|
||||
}
|
||||
|
||||
value, err := strconv.Atoi(parts[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.input = append(s.input, command{
|
||||
instruction: parts[0],
|
||||
value: value,
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sub) reset() {
|
||||
s.horizontal = 0
|
||||
s.depth = 0
|
||||
s.aim = 0
|
||||
}
|
||||
|
||||
func (s *sub) execute() {
|
||||
for _, command := range s.input {
|
||||
switch command.instruction {
|
||||
case "forward":
|
||||
s.horizontal += command.value
|
||||
case "up":
|
||||
s.depth -= command.value
|
||||
if s.depth < 0 {
|
||||
s.depth = 0
|
||||
}
|
||||
case "down":
|
||||
s.depth += command.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *sub) executeWithAim() {
|
||||
for _, command := range s.input {
|
||||
switch command.instruction {
|
||||
case "forward":
|
||||
s.horizontal += command.value
|
||||
s.depth += s.aim * command.value
|
||||
case "up":
|
||||
s.aim -= command.value
|
||||
case "down":
|
||||
s.aim += command.value
|
||||
}
|
||||
}
|
||||
}
|
80
two/sub_test.go
Normal file
80
two/sub_test.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package two
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testInput = []string{
|
||||
"forward 5",
|
||||
"down 5",
|
||||
"forward 8",
|
||||
"up 3",
|
||||
"down 8",
|
||||
"forward 2",
|
||||
}
|
||||
|
||||
func Test_scan(t *testing.T) {
|
||||
s := sub{}
|
||||
if err := s.load("input.txt"); err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if len(s.input) != 1000 {
|
||||
t.Logf("Expected 1000 commands, found %d", len(s.input))
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_execute(t *testing.T) {
|
||||
s := sub{
|
||||
input: []command{},
|
||||
}
|
||||
|
||||
for _, raw := range testInput {
|
||||
parts := strings.Split(raw, " ")
|
||||
value, _ := strconv.Atoi(parts[1])
|
||||
s.input = append(s.input, command{
|
||||
instruction: parts[0],
|
||||
value: value,
|
||||
})
|
||||
}
|
||||
|
||||
s.execute()
|
||||
if s.horizontal != 15 {
|
||||
t.Logf("Expected horizontal of 15, found %d", s.horizontal)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if s.depth != 10 {
|
||||
t.Logf("Expected depth of 10, found %d", s.depth)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func Test_executeWithAim(t *testing.T) {
|
||||
s := sub{
|
||||
input: []command{},
|
||||
}
|
||||
|
||||
for _, raw := range testInput {
|
||||
parts := strings.Split(raw, " ")
|
||||
value, _ := strconv.Atoi(parts[1])
|
||||
s.input = append(s.input, command{
|
||||
instruction: parts[0],
|
||||
value: value,
|
||||
})
|
||||
}
|
||||
|
||||
s.executeWithAim()
|
||||
if s.horizontal != 15 {
|
||||
t.Logf("Expected horizontal of 15, found %d", s.horizontal)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if s.depth != 60 {
|
||||
t.Logf("Expected depth of 60, found %d", s.depth)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user