149 lines
3.5 KiB
Go
149 lines
3.5 KiB
Go
package day12
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func Run() int {
|
|
fmt.Println("hello day 12.")
|
|
|
|
filename := "day12/example1"
|
|
bytes, err := os.ReadFile(filename)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("error reading file %s\n", filename))
|
|
}
|
|
|
|
result := 0
|
|
text := string(bytes)
|
|
text = strings.TrimSpace(text)
|
|
|
|
// testMask, testBlocks := ReadLine(".??..??...?##. 1,1,3")
|
|
// blocksSum := 0
|
|
// for _, block := range testBlocks {
|
|
// blocksSum += block
|
|
// }
|
|
// testVariants := generatePermutations("", len(testMask), testBlocks, blocksSum, testMask)
|
|
// fmt.Printf("for mask %s and blocks %+v\n", testMask, testBlocks)
|
|
// for _, variant := range testVariants {
|
|
// fmt.Println(variant)
|
|
// }
|
|
|
|
for _, line := range strings.Split(text, "\n") {
|
|
mask, blockLengs := ReadLine(line)
|
|
|
|
blockLengthSum := 0
|
|
for _, blockLen := range blockLengs {
|
|
blockLengthSum += blockLen
|
|
}
|
|
|
|
variants := generatePermutations("", len(mask), blockLengs, blockLengthSum, mask)
|
|
|
|
match := 0
|
|
for range variants {
|
|
match += 1
|
|
}
|
|
fmt.Printf("for line %s blocks %+v matches %d\n", mask, blockLengs, match)
|
|
result += match
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func myRepeat(line, sep string, amount int) string {
|
|
acc := ""
|
|
for i := 0; i < amount; i++ {
|
|
acc += sep
|
|
acc += line
|
|
}
|
|
acc, _ = strings.CutPrefix(acc, sep)
|
|
|
|
return acc
|
|
}
|
|
|
|
// ???.### 1,1,3
|
|
func ReadLine(line string) (string, []int) {
|
|
firstSplit := strings.Split(line, " ")
|
|
if len(firstSplit) != 2 {
|
|
panic(fmt.Sprintf("error splitting %s into 2", line))
|
|
}
|
|
mask := firstSplit[0]
|
|
mask = myRepeat(mask, "?", 5)
|
|
blocks := firstSplit[1]
|
|
blocks = myRepeat(blocks, ",", 5)
|
|
// log.Printf(">> repeating blocks %s", blocks)
|
|
blockLengthStrings := strings.Split(blocks, ",")
|
|
blockLengs := make([]int, len(blockLengthStrings))
|
|
|
|
for i, blockLenStr := range blockLengthStrings {
|
|
num, err := strconv.Atoi(blockLenStr)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("error extracting num %s from %s\n", blockLenStr, line))
|
|
}
|
|
blockLengs[i] = num
|
|
}
|
|
|
|
return mask, blockLengs
|
|
}
|
|
|
|
func generatePermutations(curString string, targetLength int, blockLengths []int, blockLengthsSum int, mask string) []string {
|
|
// fmt.Printf("> entering with \n%s\nfor map \n%s\n\n", curString, mask)
|
|
// time.Sleep(time.Second)
|
|
if !isVariantMatchesMask(curString, mask) {
|
|
return []string{}
|
|
}
|
|
|
|
// log.Printf("> entering with %s\n", curString)
|
|
if len(blockLengths) == 0 {
|
|
if len(curString) > targetLength {
|
|
return []string{}
|
|
}
|
|
variant := curString + strings.Repeat(".", targetLength-len(curString))
|
|
if !isVariantMatchesMask(variant, mask) {
|
|
return []string{}
|
|
}
|
|
return []string{variant}
|
|
}
|
|
|
|
nextBlock := blockLengths[0]
|
|
restBlocks := blockLengths[1:]
|
|
|
|
if len(curString)+blockLengthsSum > targetLength {
|
|
return []string{}
|
|
}
|
|
|
|
isLast := len(restBlocks) == 0
|
|
rightPointRepeat := 1
|
|
if isLast {
|
|
rightPointRepeat = 0
|
|
}
|
|
|
|
whenPass := curString + "."
|
|
whenAdd := curString + strings.Repeat("#", nextBlock) + strings.Repeat(".", rightPointRepeat)
|
|
|
|
variantsWhenPass := generatePermutations(whenPass, targetLength, blockLengths, blockLengthsSum, mask)
|
|
variantsWhenAdd := generatePermutations(whenAdd, targetLength, restBlocks, blockLengthsSum-nextBlock, mask)
|
|
|
|
return append(variantsWhenAdd, variantsWhenPass...)
|
|
}
|
|
|
|
func isVariantMatchesMask(variant, mask string) bool {
|
|
if len(mask) < len(variant) {
|
|
log.Printf("mask %s is less than variant %s\n", mask, variant)
|
|
}
|
|
maskRunes := []rune(mask)
|
|
for i, symb := range variant {
|
|
if maskRunes[i] == '?' {
|
|
continue
|
|
}
|
|
if maskRunes[i] != symb {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|