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)) } sum := 0 text := string(bytes) text = strings.TrimSpace(text) 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 } log.Printf("for line %s blocks %+v matches %d\n", mask, blockLengs, match) sum += match } return sum } // ???.### 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] blockLengthStrings := strings.Split(firstSplit[1], ",") 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 { 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)) 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 }