1
0

Compare commits

...

4 Commits

Author SHA1 Message Date
66a9f3f9e6 clean up main 2024-12-05 22:51:31 +02:00
ee0ac427cf solve day 4 2024-12-05 22:07:42 +02:00
e715a03263 solve day 3 2024-12-05 20:43:35 +02:00
c54a2e3440 solve day 2 2024-12-04 22:45:05 +02:00
5 changed files with 390 additions and 8 deletions

10
day1.go
View File

@ -12,7 +12,7 @@ type Day1Input struct {
column2 []int64
}
func day1_parse(lines []string) (*Day1Input, error) {
func Day1Parse(lines []string) (*Day1Input, error) {
column1 := make([]int64, len(lines))
column2 := make([]int64, len(lines))
@ -42,8 +42,8 @@ func day1_parse(lines []string) (*Day1Input, error) {
return &parsed, nil
}
func day1_part1(lines []string) (error) {
input, err := day1_parse(lines)
func Day1Part1(lines []string) (error) {
input, err := Day1Parse(lines)
if err != nil {
return err
}
@ -70,8 +70,8 @@ func day1_part1(lines []string) (error) {
return nil
}
func day1_part2(lines []string) (error) {
input, err := day1_parse(lines)
func Day1Part2(lines []string) (error) {
input, err := Day1Parse(lines)
if err != nil {
return err
}

109
day2.go Normal file
View File

@ -0,0 +1,109 @@
package main
import (
"fmt"
"strconv"
"strings"
)
type Day2Input [][]int64
func Day2Parse(lines []string) (Day2Input, error) {
rows := make([][]int64, len(lines))
for i, line := range lines {
levelsCount := strings.Count(line, " ") + 1
rows[i] = make([]int64, levelsCount)
for j, level := range strings.Split(line, " ") {
number, err := strconv.ParseInt(level, 10, 0)
if err != nil {
return nil, err
}
rows[i][j] = number
}
}
return rows, nil
}
func absInt(value int64) int64 {
if value < 0 {
return -value
} else {
return value
}
}
func Day2IsReportSafe(report []int64) bool {
increasing := false
decreasing := false
for i := range len(report)-1 {
if report[i+1] >= report[i] {
increasing = true
}
if report[i+1] <= report[i] {
decreasing = true
}
if absInt(report[i+1] - report[i]) >= 4 {
return false
}
if increasing && decreasing {
return false
}
}
return !(increasing && decreasing) && (increasing || decreasing)
}
func Day2Part1(lines []string) error {
input, err := Day2Parse(lines)
if err != nil {
return err
}
answer := 0
for _, row := range input {
if Day2IsReportSafe(row) {
answer += 1
}
}
fmt.Println(answer)
return nil
}
func DeleteAtIndex(slice []int64, index int) []int64 {
result := make([]int64, len(slice))
copy(result, slice)
return append(result[:index], result[index+1:]...)
}
func Day2Part2(lines []string) error {
input, err := Day2Parse(lines)
if err != nil {
return err
}
answer := 0
for _, row := range input {
if Day2IsReportSafe(row) {
answer += 1
continue
}
for i := range len(row) {
if Day2IsReportSafe(DeleteAtIndex(row, i)) {
answer += 1
break
}
}
}
fmt.Println(answer)
return nil
}

142
day3.go Normal file
View File

@ -0,0 +1,142 @@
package main
import (
"strconv"
"strings"
)
type Day3Mul struct {
size int
number1 int
number2 int
}
func Day3ParseMulInstruction(text string) *Day3Mul {
max_length := 0
max_length += 4 // mul(
max_length += 3 // 999
max_length += 1 // ,
max_length += 3 // 999
max_length += 1 // )
if len(text) < 4 {
return nil
}
if len(text) > max_length {
text = text[:max_length]
}
if text[0:4] != "mul(" {
return nil
}
comma_index := strings.IndexRune(text, ',')
if (comma_index == -1) {
return nil
}
closing_index := strings.IndexRune(text, ')')
if (closing_index == -1) {
return nil
}
number1_text := text[4:comma_index]
number2_text := text[(comma_index+1):closing_index]
number1, err := strconv.ParseUint(number1_text, 10, 0)
if err != nil {
return nil
}
if number1 > 999 {
return nil
}
number2, err := strconv.ParseUint(number2_text, 10, 0)
if err != nil {
return nil
}
if number2 > 999 {
return nil
}
inst := Day3Mul{
size: closing_index + 1,
number1: int(number1),
number2: int(number2),
}
return &inst
}
func Day3Part1(lines []string) error {
answer := 0
for _, line := range lines {
cursor := 0
for cursor < len(line) {
inst := Day3ParseMulInstruction(line[cursor:])
if inst != nil {
cursor += inst.size
answer += inst.number1 * inst.number2
} else {
cursor += 1
}
}
}
println(answer)
return nil
}
func Day3StartsWith(haystack string, needle string) bool {
if len(haystack) < len(needle) {
return false
}
return haystack[:len(needle)] == needle
}
func Day3Part2(lines []string) error {
answer := 0
do_inst := "do()"
dont_inst := "don't()"
enabled := true
for _, line := range lines {
cursor := 0
for cursor < len(line) {
rest := line[cursor:]
if Day3StartsWith(rest, do_inst) {
enabled = true
cursor += len(do_inst)
continue
}
if Day3StartsWith(rest, dont_inst) {
enabled = false
cursor += len(dont_inst)
continue
}
if enabled {
inst := Day3ParseMulInstruction(rest)
if inst != nil {
cursor += inst.size
answer += inst.number1 * inst.number2
continue
}
}
cursor += 1
}
}
println(answer)
return nil
}

110
day4.go Normal file
View File

@ -0,0 +1,110 @@
package main
type Day4Offset struct {
x int
y int
}
func Day4IsWordValid(lines []string, x int, y int, table []Day4Offset, word string) bool {
for i, offset := range table {
y := y + offset.y
if y < 0 {
return false
}
if y >= len(lines) {
return false
}
x := x + offset.x
if x < 0 {
return false
}
if x >= len(lines[y]) {
return false
}
if lines[y][x] != word[i] {
return false
}
}
return true
}
func Day4Part1(lines []string) error {
offsetTables := [][]Day4Offset{
[]Day4Offset{
Day4Offset{ x: 0, y: 0, },
Day4Offset{ x: 1, y: 0, },
Day4Offset{ x: 2, y: 0, },
Day4Offset{ x: 3, y: 0, },
},
[]Day4Offset{
Day4Offset{ x: 0, y: 0, },
Day4Offset{ x: 0, y: 1, },
Day4Offset{ x: 0, y: 2, },
Day4Offset{ x: 0, y: 3, },
},
[]Day4Offset{
Day4Offset{ x: 0, y: 0, },
Day4Offset{ x: 1, y: 1, },
Day4Offset{ x: 2, y: 2, },
Day4Offset{ x: 3, y: 3, },
},
[]Day4Offset{
Day4Offset{ x: 0, y: 0, },
Day4Offset{ x: -1, y: 1, },
Day4Offset{ x: -2, y: 2, },
Day4Offset{ x: -3, y: 3, },
},
}
answer := 0
for y := range len(lines) {
for x := range len(lines[y]) {
for _, table := range offsetTables {
if Day4IsWordValid(lines, x, y, table, "XMAS") {
answer += 1
}
if Day4IsWordValid(lines, x, y, table, "SAMX") {
answer += 1
}
}
}
}
println(answer)
return nil
}
func Day4Part2(lines []string) error {
table1 := []Day4Offset{
Day4Offset{ x: 0, y: 0, },
Day4Offset{ x: 1, y: 1, },
Day4Offset{ x: 2, y: 2, },
}
table2 := []Day4Offset{
Day4Offset{ x: 2, y: 0, },
Day4Offset{ x: 1, y: 1, },
Day4Offset{ x: 0, y: 2, },
}
answer := 0
for y := range len(lines) {
for x := range len(lines[y]) {
diagonal1 := Day4IsWordValid(lines, x, y, table1, "MAS") || Day4IsWordValid(lines, x, y, table1, "SAM")
diagonal2 := Day4IsWordValid(lines, x, y, table2, "MAS") || Day4IsWordValid(lines, x, y, table2, "SAM")
if diagonal1 && diagonal2 {
answer += 1
}
}
}
println(answer)
return nil
}

29
main.go
View File

@ -12,6 +12,12 @@ func showUsage() {
fmt.Printf("Usage: %s <day> <part> [input.txt]\n", os.Args[0])
}
type DayPartSolver func([]string) error
type DaySolver struct {
day1 DayPartSolver
day2 DayPartSolver
}
func main() {
if (len(os.Args) < 3) {
showUsage()
@ -35,11 +41,26 @@ func main() {
lines := strings.Split(strings.TrimRight(string(contents), "\n"), "\n")
if day == "1" {
solvers := make(map[string]DaySolver)
solvers["1"] = DaySolver{ day1: Day1Part1, day2: Day1Part2 }
solvers["2"] = DaySolver{ day1: Day2Part1, day2: Day2Part2 }
solvers["3"] = DaySolver{ day1: Day3Part1, day2: Day3Part2 }
solvers["4"] = DaySolver{ day1: Day4Part1, day2: Day4Part2 }
solver, ok := solvers[day]
if ok {
var err error
if part == "1" {
day1_part1(lines)
err = solver.day1(lines)
} else if part == "2" {
day1_part2(lines)
}
err = solver.day1(lines)
}
if err != nil {
log.Fatal(err)
}
} else {
log.Fatal("Day not found")
}
}