You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
4.1 KiB
Go

package day12
import (
"fmt"
"regexp"
"strings"
"gitea.paas.celticinfo.fr/oabrivard/aoc2023/utils"
)
func generateConditions(condPattern []byte) [][]byte {
result := [][]byte{}
for i, b := range condPattern {
if b == '?' {
newPattern1 := make([]byte, len(condPattern))
copy(newPattern1, condPattern)
newPattern1[i] = '.'
result = append(result, generateConditions(newPattern1)...)
newPattern2 := make([]byte, len(condPattern))
copy(newPattern2, condPattern)
newPattern2[i] = '#'
result = append(result, generateConditions(newPattern2)...)
return result
}
}
result = append(result, condPattern)
return result
}
func SumArragements1(lines []string) int {
result := 0
for l, line := range lines {
line_parts := strings.Fields(line)
gs := utils.ParseIntArray(line_parts[1], ",") // group sizes
count := 0 // numberOfArrangements for the line
var sb strings.Builder
sb.WriteString(`^\.*`)
for i, curr_gs := range gs {
sb.WriteString(fmt.Sprintf("#{%d}?", curr_gs))
if i != len(gs)-1 {
sb.WriteString(`\.+`)
}
}
sb.WriteString(`\.*$`)
reString := sb.String()
var re = regexp.MustCompile(reString)
conds := generateConditions([]byte(line_parts[0]))
for _, cond := range conds {
if re.Match(cond) {
count++
}
}
fmt.Printf("Matching line %d : %d\n", l, count)
result += count
}
return result
}
var solved map[string]int
/*
func CountArrangements(line []byte, gs []int, curr_gs int, previous byte, s string) int {
if curr_gs == len(gs)-1 && gs[curr_gs] == 0 {
for _, c := range line {
if c == '#' {
return 0
}
}
//fmt.Println(s)
return 1
}
if len(line) == 0 {
return 0
}
key := string(line) + fmt.Sprintf("%v-%v", gs, curr_gs)
val, found := solved[key]
if found {
return val
}
count := 0
switch line[0] {
case '?':
line[0] = '.'
count1 := CountArrangements(line, gs, curr_gs, previous, s)
line[0] = '#'
count2 := CountArrangements(line, gs, curr_gs, previous, s)
line[0] = '?'
count = count1 + count2
case '#':
if previous == '.' || previous == 0 {
if curr_gs >= 0 && gs[curr_gs] > 0 {
return 0
}
curr_gs++
}
if curr_gs >= len(gs) {
return 0
}
if gs[curr_gs] == 0 {
return 0
}
gs[curr_gs]--
count = CountArrangements(line[1:], gs, curr_gs, '#', s+"#")
gs[curr_gs]++
case '.':
count = CountArrangements(line[1:], gs, curr_gs, '.', s+".")
}
solved[key] = count
return count
}
*/
func CountArrangements(conds []byte, gs []int) int {
if len(gs) == 0 {
for _, c := range conds {
if c == '#' {
return 0
}
}
return 1
}
if len(conds) == 0 {
return 0
}
key := fmt.Sprintf("%v-%v", conds, gs)
val, found := solved[key]
if found {
return val
}
count := 0
switch conds[0] {
case '?':
conds[0] = '.'
count += CountArrangements(conds, gs)
conds[0] = '#'
count += CountArrangements(conds, gs)
conds[0] = '?'
case '#':
first_gs := gs[0]
if first_gs <= len(conds) &&
!strings.Contains(string(conds[0:first_gs]), ".") {
if first_gs == len(conds) {
count = CountArrangements(conds[first_gs:], gs[1:])
} else if conds[first_gs] != '#' {
count = CountArrangements(conds[first_gs+1:], gs[1:])
}
}
case '.':
count = CountArrangements(conds[1:], gs)
}
solved[key] = count
return count
}
func SumArragements2(lines []string, expansion int) int {
result := 0
for l, line := range lines {
line_parts := strings.Fields(line)
parsed_gs := utils.ParseIntArray(line_parts[1], ",") // group sizes
gs := []int{}
for i := 0; i < expansion+1; i++ {
gs = append(gs, parsed_gs...)
}
var sb strings.Builder
sb.WriteString(line_parts[0])
for i := 0; i < expansion; i++ {
sb.WriteString("?")
sb.WriteString(line_parts[0])
}
s := sb.String()
solved = map[string]int{}
/*
count := CountArrangements([]byte(s), gs, -1, 0, "") // numberOfArrangements for the line
*/
count := CountArrangements([]byte(s), gs) // numberOfArrangements for the line
fmt.Printf("%d arrangements for %s on line %d\n", count, s, l)
result += count
}
return result
}