-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5dadb6a
commit 9076b42
Showing
6 changed files
with
374 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package day12 | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"log" | ||
"os" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
type Row struct { | ||
rawSeq []string | ||
damagedGroups []int | ||
} | ||
|
||
func Solution1(filepath string) int { | ||
m := parseInput(filepath) | ||
printMatrix(m) | ||
return -1 | ||
} | ||
|
||
func Solution2(filepath string) int { | ||
return -1 | ||
} | ||
|
||
func parseInput(filepath string) []Row { | ||
file, err := os.Open(filepath) | ||
if err != nil { | ||
log.Fatalf("Failed to open the input file with: %v\n", err.Error()) | ||
} | ||
|
||
var m []Row | ||
scanner := bufio.NewScanner(file) | ||
for scanner.Scan() { | ||
divInput := strings.Split(scanner.Text(), " ") | ||
seq := strings.Split(divInput[0], "") | ||
dmgGroups := strings.Split(divInput[1], ",") | ||
m = append(m, Row{rawSeq: seq, damagedGroups: parseInts(dmgGroups)}) | ||
} | ||
if err = scanner.Err(); err != nil { | ||
log.Fatalf("Error during input file read: %v\n", err.Error()) | ||
} | ||
|
||
return m | ||
} | ||
|
||
func printRows(rows []Row) { | ||
fmt.Println("-----MATRIX START-----") | ||
for _, row := range rows { | ||
fmt.Println(row) | ||
} | ||
fmt.Println("------MATRIX END-----") | ||
} | ||
|
||
func parseInts(sNums []string) []int { | ||
var nums []int | ||
for _, sNum := range sNums { | ||
num64, err := strconv.ParseInt(sNum, 10, 64) | ||
if err != nil { | ||
log.Fatalf("Failed to parse number %v with: %v\n", sNum, err.Error()) | ||
} | ||
|
||
nums = append(nums, int(num64)) | ||
} | ||
|
||
return nums | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
package day12 | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"log" | ||
"os" | ||
"regexp" | ||
"slices" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
type Row struct { | ||
rawSeq []string | ||
damagedGroups []int | ||
} | ||
|
||
func Solution1(filepath string) int { | ||
rows := parseInput(filepath) | ||
printRows(rows) | ||
|
||
result := 0 | ||
for _, r := range rows { | ||
result += countCombinations(r) | ||
} | ||
return result | ||
} | ||
|
||
func Solution2(filepath string) int { | ||
return -1 | ||
} | ||
|
||
func countCombinations(r Row) int { | ||
unsolvedChunks := getUnsolvedChunkRanges(r.rawSeq) | ||
|
||
// { startIdx: []{all possible substrings of len()=length}, ... } | ||
chunkVars := make(map[int][]string) | ||
for idx, length := range unsolvedChunks { | ||
chunkVars[idx] = getPossibleCombinations(length, "") | ||
} | ||
|
||
// chunkVars to generate full row strings of all potential combinations of . and # in place of ? | ||
var chunksOrder []int | ||
for chunkIdx, _ := range chunkVars { | ||
chunksOrder = append(chunksOrder, chunkIdx) | ||
} | ||
slices.Sort(chunksOrder) | ||
|
||
varStrings := getAllPossibleStrings(strings.Join(r.rawSeq, ""), chunkVars, chunksOrder) | ||
// fmt.Println("ALL STRINGS:") | ||
// for _, vs := range varStrings { | ||
// fmt.Println(vs) | ||
// } | ||
// fmt.Println("--------------") | ||
|
||
// count valid strings | ||
result := 0 | ||
expectedGroups := r.damagedGroups | ||
|
||
for _, v := range varStrings { | ||
dmgRegex := regexp.MustCompile(`#+`) | ||
matches := dmgRegex.FindAllString(v, -1) | ||
var groups []int | ||
for _, m := range matches { | ||
groups = append(groups, len(m)) | ||
} | ||
|
||
if slices.Equal(expectedGroups, groups) { | ||
result += 1 | ||
} | ||
} | ||
|
||
return result | ||
} | ||
|
||
func getUnsolvedChunkRanges(s []string) map[int]int { | ||
// { startIdx: length } | ||
unsolvedChunks := make(map[int]int) | ||
|
||
start := -1 | ||
currentSlice := false | ||
for i, char := range s { | ||
if char == "?" { | ||
if !currentSlice { | ||
currentSlice = true | ||
start = i | ||
} | ||
} else { | ||
if currentSlice { | ||
unsolvedChunks[start] = i - start | ||
currentSlice = false | ||
start = -1 | ||
} | ||
} | ||
} | ||
if currentSlice { | ||
unsolvedChunks[start] = len(s) - start | ||
} | ||
|
||
return unsolvedChunks | ||
} | ||
|
||
func getAllPossibleStrings(baseString string, chunkVariations map[int][]string, chunksOrder []int) []string { | ||
var result []string | ||
|
||
if len(chunksOrder) == 0 { | ||
return []string{baseString} | ||
} | ||
|
||
idx := chunksOrder[0] | ||
for _, v := range chunkVariations[idx] { | ||
newBaseString := "" | ||
if idx > 0 { | ||
newBaseString = baseString[:idx] | ||
} | ||
newBaseString += v | ||
if insertEndIdx := idx + len([]rune(v)); insertEndIdx < len([]rune(baseString)) { | ||
newBaseString += baseString[insertEndIdx:] | ||
} | ||
|
||
var newOrderChunk []int | ||
if len(chunksOrder) > 0 { | ||
newOrderChunk = chunksOrder[1:] | ||
} else { | ||
newOrderChunk = make([]int, 0) | ||
} | ||
result = append( | ||
result, | ||
getAllPossibleStrings(newBaseString, chunkVariations, newOrderChunk)..., | ||
) | ||
} | ||
return result | ||
} | ||
|
||
func getPossibleCombinations(length int, currentComb string) []string { | ||
var combs []string | ||
|
||
if length < 0 { | ||
log.Fatalln("bruh") | ||
} | ||
|
||
if length == 1 { | ||
combA := currentComb + "." | ||
combB := currentComb + "#" | ||
return []string{combA, combB} | ||
} | ||
|
||
combs = append(combs, getPossibleCombinations(length-1, currentComb+".")...) | ||
combs = append(combs, getPossibleCombinations(length-1, currentComb+"#")...) | ||
|
||
return combs | ||
} | ||
|
||
func parseInput(filepath string) []Row { | ||
file, err := os.Open(filepath) | ||
if err != nil { | ||
log.Fatalf("Failed to open the input file with: %v\n", err.Error()) | ||
} | ||
|
||
var m []Row | ||
scanner := bufio.NewScanner(file) | ||
for scanner.Scan() { | ||
divInput := strings.Split(scanner.Text(), " ") | ||
seq := strings.Split(divInput[0], "") | ||
dmgGroups := strings.Split(divInput[1], ",") | ||
m = append(m, Row{rawSeq: seq, damagedGroups: parseInts(dmgGroups)}) | ||
} | ||
if err = scanner.Err(); err != nil { | ||
log.Fatalf("Error during input file read: %v\n", err.Error()) | ||
} | ||
|
||
return m | ||
} | ||
|
||
func printRows(rows []Row) { | ||
fmt.Println("-----MATRIX START-----") | ||
for i, row := range rows { | ||
fmt.Printf("Row %d: %v | %v\n", i, strings.Join(row.rawSeq, ""), row.damagedGroups) | ||
} | ||
fmt.Println("------MATRIX END-----") | ||
} | ||
|
||
func parseInts(sNums []string) []int { | ||
var nums []int | ||
for _, sNum := range sNums { | ||
num64, err := strconv.ParseInt(sNum, 10, 64) | ||
if err != nil { | ||
log.Fatalf("Failed to parse number %v with: %v\n", sNum, err.Error()) | ||
} | ||
|
||
nums = append(nums, int(num64)) | ||
} | ||
|
||
return nums | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package day12 | ||
|
||
import ( | ||
"fmt" | ||
"maps" | ||
"slices" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func TestSolutio1(t *testing.T) { | ||
cases := map[string]int{ | ||
"test_input12": 6, | ||
"test_input11": 21, | ||
} | ||
|
||
for input, expectedResult := range cases { | ||
result := Solution1(input) | ||
|
||
if result == expectedResult { | ||
fmt.Printf("Solution1()=%d, OK\n", result) | ||
} else { | ||
t.Fatalf("Solution1()=%d, expecting %d, FAIL\n", result, expectedResult) | ||
} | ||
} | ||
} | ||
|
||
func TestGetAllPossibleStrings(t *testing.T) { | ||
input := "?..?##.?" | ||
expectedResult := []string{ | ||
"#..###.#", | ||
"#..###..", | ||
"#...##.#", | ||
"#...##..", | ||
"...###.#", | ||
"...###..", | ||
"....##.#", | ||
"....##..", | ||
} | ||
chunkVars := map[int][]string{ | ||
0: {".", "#"}, | ||
3: {".", "#"}, | ||
7: {".", "#"}, | ||
} | ||
|
||
result := getAllPossibleStrings(input, chunkVars, []int{0, 3, 7}) | ||
slices.Sort(expectedResult) | ||
slices.Sort(result) | ||
if slices.Equal(result, expectedResult) { | ||
fmt.Printf("getAllPossibleStrings()=%v; OK\n", result) | ||
} else { | ||
t.Fatalf("getAllPossibleStrings()=%v, expecting %v; FAIL\n", result, expectedResult) | ||
} | ||
} | ||
|
||
func TestGetAllPossibleCombinations(t *testing.T) { | ||
cases := map[int][]string{ | ||
1: {".", "#"}, | ||
2: { | ||
"..", | ||
"#.", | ||
".#", | ||
"##", | ||
}, | ||
} | ||
|
||
for input, expectedResult := range cases { | ||
result := getPossibleCombinations(input, "") | ||
slices.Sort(result) | ||
slices.Sort(expectedResult) | ||
|
||
if slices.Equal(result, expectedResult) { | ||
fmt.Printf("getPossibleCombinations()=%v, OK\n", result) | ||
} else { | ||
t.Fatalf("getPossibleCombinations()=%v, expecting %v, FAIL\n", result, expectedResult) | ||
} | ||
} | ||
} | ||
|
||
func TestGetAllUnsolvedChunkRanges(t *testing.T) { | ||
cases := map[string]map[int]int{ | ||
"???.###": {0: 3}, | ||
".??..??...?##.": {1: 2, 5: 2, 10: 1}, | ||
"?#?#?": {0: 1, 2: 1, 4: 1}, | ||
"?###???????": {0: 1, 4: 7}, | ||
} | ||
|
||
for input, expectedResult := range cases { | ||
result := getUnsolvedChunkRanges(strings.Split(input, "")) | ||
|
||
if maps.Equal(result, expectedResult) { | ||
fmt.Printf("getUnsolvedChunkRanges()=%v; OK\n", result) | ||
} else { | ||
t.Fatalf("getUnsolvedChunkRanges()=%v, expecting %v; FAIL\n", result, expectedResult) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
???.### 1,1,3 | ||
.??..??...?##. 1,1,3 | ||
?#?#?#?#?#?#?#? 1,3,1,6 | ||
????.#...#... 4,1,1 | ||
????.######..#####. 1,6,5 | ||
?###???????? 3,2,1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
???.### 1,1,3 | ||
.??..??...?##. 1,1,3 | ||
?#?#?#?#?#?#?#? 1,3,1,6 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters