Skip to content

Commit

Permalink
Finished part 1 of day 12. Working on part 2.
Browse files Browse the repository at this point in the history
  • Loading branch information
devries committed Dec 12, 2023
1 parent df1f7c7 commit 1e411f6
Show file tree
Hide file tree
Showing 5 changed files with 341 additions and 1 deletion.
106 changes: 106 additions & 0 deletions day12p1/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package day12p1

import (
"fmt"
"io"
"strconv"
"strings"

"aoc/utils"
)

func Solve(r io.Reader) any {
lines := utils.ReadLines(r)

sum := int64(0)
for _, ln := range lines {
if utils.Verbose {
fmt.Printf("Starting %s\n", ln)
}

parts := strings.Fields(ln)

numbers := strings.Split(parts[1], ",")

groups := make([]int64, len(numbers))

var err error
for i, v := range numbers {
groups[i], err = strconv.ParseInt(v, 10, 64)
utils.Check(err, "Unable to convert %s to int64", v)
}

sum += findValid([]rune(parts[0]), groups)
}
return sum
}

func findValid(row []rune, groups []int64) int64 {
valids := int64(0)

for i, r := range row {
if r == '?' {
// replace with functional spring
trialA := make([]rune, len(row))
copy(trialA, row)
trialA[i] = '.'
if isValid(trialA, groups) {
valids += findValid(trialA, groups)
}

// replace with broken sprint
trialB := make([]rune, len(row))
copy(trialB, row)
trialB[i] = '#'
if isValid(trialB, groups) {
valids += findValid(trialB, groups)
}

return valids
}
}

if isValid(row, groups) {
valids = 1
if utils.Verbose {
fmt.Printf("\t%s\n", string(row))
}
}
return valids
}

func isValid(row []rune, groups []int64) bool {
cgroups := []int64{}

n := int64(0)

for _, r := range row {
switch r {
case '#':
n++
case '.':
if n > 0 {
cgroups = append(cgroups, n)
n = 0
}
case '?':
return true
}
}
if n > 0 {
cgroups = append(cgroups, n)
}
n = 0

if len(cgroups) != len(groups) {
return false
}

for i, g := range groups {
if cgroups[i] != g {
return false
}
}

return true
}
38 changes: 38 additions & 0 deletions day12p1/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package day12p1

import (
"strings"
"testing"

"aoc/utils"
)

var testInput = `???.### 1,1,3
.??..??...?##. 1,1,3
?#?#?#?#?#?#?#? 1,3,1,6
????.#...#... 4,1,1
????.######..#####. 1,6,5
?###???????? 3,2,1`

func TestSolve(t *testing.T) {
tests := []struct {
input string
answer int64
}{
{testInput, 21},
}

if testing.Verbose() {
utils.Verbose = true
}

for _, test := range tests {
r := strings.NewReader(test.input)

result := Solve(r).(int64)

if result != test.answer {
t.Errorf("Expected %d, got %d", test.answer, result)
}
}
}
158 changes: 158 additions & 0 deletions day12p2/solution.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package day12p2

import (
"fmt"
"io"
"strconv"
"strings"

"aoc/utils"
)

func Solve(r io.Reader) any {
lines := utils.ReadLines(r)

sum := int64(0)
for _, ln := range lines {
if utils.Verbose {
fmt.Printf("Starting %s\n", ln)
}

parts := strings.Fields(ln)

numbers := strings.Split(parts[1], ",")

groups := make([]int64, len(numbers)*5)

for i, v := range numbers {
n, err := strconv.ParseInt(v, 10, 64)
utils.Check(err, "Unable to convert %s to int64", v)
for j := 0; j < 5; j++ {
groups[i+len(numbers)*j] = n
}
}

var bld strings.Builder
for i := 0; i < 5; i++ {
bld.WriteString(parts[0])
if i < 4 {
bld.WriteString("?")
}
}

if utils.Verbose {
fmt.Printf("\texpanded: %s\n", bld.String())
}
valid := findValid([]rune(bld.String()), groups)
if utils.Verbose {
fmt.Printf("\tValid: %d\n\n", valid)
}
sum += valid
}
return sum
}

func findValid(row []rune, groups []int64) int64 {
valids := int64(0)

for i, r := range row {
if r == '?' {
// replace with functional spring
trialA := make([]rune, len(row))
copy(trialA, row)
trialA[i] = '.'
if isValid(trialA, groups) {
valids += findValid(trialA, groups)
}

// replace with broken sprint
trialB := make([]rune, len(row))
copy(trialB, row)
trialB[i] = '#'
if isValid(trialB, groups) {
valids += findValid(trialB, groups)
}

return valids
}
}

if isValid(row, groups) {
valids = 1
// if utils.Verbose {
// fmt.Printf("\t%s\n", string(row))
// }
}
return valids
}

func isValid(row []rune, groups []int64) bool {
cgroups := []int64{}

n := int64(0)
sum := int64(0)
empties := int64(0)
firstEmpty := false

// To add:
// find minimum possible groups
// by checking for '.' between remaining '#'
// also: if !firstEmpty sum==sum(groups)

for _, r := range row {
switch r {
case '#':
n++
sum++
case '.':
if !firstEmpty && n > 0 {
cgroups = append(cgroups, n)
n = 0
}
case '?':
empties++
if !firstEmpty && n > 0 {
cgroups = append(cgroups, n)
}
n = 0
firstEmpty = true
}
}
if !firstEmpty && n > 0 {
cgroups = append(cgroups, n)
}
n = 0

if !firstEmpty && len(cgroups) != len(groups) {
return false
}

if len(cgroups) > len(groups) {
// more groups already made than allowed
return false
}

totalBroken := int64(0)
cgl := len(cgroups)
for i, g := range groups {
if i < cgl-1 && cgroups[i] != g {
return false
} else if i == cgl-1 && cgroups[i] > g {
// What if there are no empties? then cgroups[i] should equal g
return false
}
totalBroken += g
}

if sum > totalBroken {
// too many defects
return false
}

if sum+empties < totalBroken {
// not enough to make total broken
return false
}

return true
}
38 changes: 38 additions & 0 deletions day12p2/solution_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package day12p2

import (
"strings"
"testing"

"aoc/utils"
)

var testInput = `???.### 1,1,3
.??..??...?##. 1,1,3
?#?#?#?#?#?#?#? 1,3,1,6
????.#...#... 4,1,1
????.######..#####. 1,6,5
?###???????? 3,2,1`

func TestSolve(t *testing.T) {
tests := []struct {
input string
answer int64
}{
{testInput, 525152},
}

if testing.Verbose() {
utils.Verbose = true
}

for _, test := range tests {
r := strings.NewReader(test.input)

result := Solve(r).(int64)

if result != test.answer {
t.Errorf("Expected %d, got %d", test.answer, result)
}
}
}
2 changes: 1 addition & 1 deletion inputs

0 comments on commit 1e411f6

Please sign in to comment.