diff --git a/day01/day01.go b/day01/day01.go new file mode 100644 index 0000000..69c603a --- /dev/null +++ b/day01/day01.go @@ -0,0 +1,75 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" +) + +const digits = "0123456789" + +func words() [10]string { + return [10]string{"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"} +} + +func firstDigit(input string) string { + var result string + loc := len(input) + if index := strings.IndexAny(input, "0123456789"); index != -1 { + loc = index + result = string([]rune(input)[index]) + } + for key, value := range words() { + if index := strings.Index(input, value); index != -1 && index <= loc { + loc = index + result = strconv.Itoa(key) + } + } + return result +} + +func lastDigit(input string) string { + var result string + loc := -1 + if index := strings.LastIndexAny(input, "0123456789"); index != -1 { + loc = index + result = string([]rune(input)[index]) + } + for key, value := range words() { + if index := strings.LastIndex(input, value); index != -1 && index >= loc { + loc = index + result = strconv.Itoa(key) + } + } + return result +} + +func calibration(input string) int { + first := firstDigit(input) + last := lastDigit(input) + output, _ := strconv.Atoi(first + last) + return output +} + +func ScanFile(file *os.File) (int, error) { + scanner := bufio.NewScanner(file) + sum := 0 + for scanner.Scan() { + sum += calibration(scanner.Text()) + } + if err := scanner.Err(); err != nil { + return 0, err + } + return sum, nil +} + +func main() { + sum, err := ScanFile(os.Stdin) + if err != nil { + fmt.Fprintf(os.Stderr, "Invalid input: %s\n", err) + return + } + fmt.Println(sum) +} \ No newline at end of file diff --git a/day01/day01_test.go b/day01/day01_test.go new file mode 100644 index 0000000..141ab87 --- /dev/null +++ b/day01/day01_test.go @@ -0,0 +1,32 @@ +package main + +import ( + "os" + "testing" +) + +func TestScanFile(t *testing.T) { + cases := []struct { + inFile string; + want int; + }{ + {"input1.txt", 142}, + {"input2.txt", 281}, + } + + for _, c := range cases { + f, err := os.Open(c.inFile) + if err != nil { + t.Fatal(err) + } + + got, err := ScanFile(f) + if err != nil { + t.Fatal(err) + } + + if got != c.want { + t.Errorf("ScanFile(%q) == %d, want %d", c.inFile, got, c.want) + } + } +} \ No newline at end of file diff --git a/day01/input1.txt b/day01/input1.txt new file mode 100644 index 0000000..7bbc69a --- /dev/null +++ b/day01/input1.txt @@ -0,0 +1,4 @@ +1abc2 +pqr3stu8vwx +a1b2c3d4e5f +treb7uchet diff --git a/day01/input2.txt b/day01/input2.txt new file mode 100644 index 0000000..4316a6b --- /dev/null +++ b/day01/input2.txt @@ -0,0 +1,7 @@ +two1nine +eightwothree +abcone2threexyz +xtwone3four +4nineeightseven2 +zoneight234 +7pqrstsixteen \ No newline at end of file diff --git a/day02/day02.go b/day02/day02.go new file mode 100644 index 0000000..cd0d465 --- /dev/null +++ b/day02/day02.go @@ -0,0 +1,82 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" +) + +type Game struct { + id int + sets []Set +} + +type Set struct { + red int + green int + blue int +} + +func parseGame(input string) Game { + idStr, setsStr, _ := strings.Cut(input, ": ") + + var game Game + var err error + + game.id, err = strconv.Atoi(strings.TrimPrefix(idStr, "Game ")) + + for i, setStr := range strings.Split(setsStr, "; ") { + game.sets = append(game.sets, Set{}) + for _, colorStr := range strings.Split(setStr, ", ") { + if strings.HasSuffix(colorStr, " red") { + game.sets[i].red, err = strconv.Atoi(strings.TrimSuffix(colorStr, " red")) + } + if strings.HasSuffix(colorStr, " green") { + game.sets[i].green, err = strconv.Atoi(strings.TrimSuffix(colorStr, " green")) + } + if strings.HasSuffix(colorStr, " blue") { + game.sets[i].blue, err = strconv.Atoi(strings.TrimSuffix(colorStr, " blue")) + } + } + } + + if err != nil { + panic("day02: invalid game format") + } + + return game +} + +func isGameValid(game Game) bool { + for _, set := range game.sets { + if set.red > 12 || set.green > 13 || set.blue > 14 { + return false + } + } + return true +} + +func ScanFile(file *os.File) (int, error) { + scanner := bufio.NewScanner(file) + sum := 0 + for scanner.Scan() { + if game := parseGame(scanner.Text()); isGameValid(game) { + sum += game.id + } + } + if err := scanner.Err(); err != nil { + return 0, err + } + return sum, nil +} + +func main() { + sum, err := ScanFile(os.Stdin) + if err != nil { + fmt.Fprintf(os.Stderr, "Invalid input: %s\n", err) + return + } + fmt.Println(sum) +} \ No newline at end of file diff --git a/day02/day02_test.go b/day02/day02_test.go new file mode 100644 index 0000000..923b84c --- /dev/null +++ b/day02/day02_test.go @@ -0,0 +1,31 @@ +package main + +import ( + "os" + "testing" +) + +func TestScanFile(t *testing.T) { + cases := []struct { + inFile string; + want int; + }{ + {"input1.txt", 8}, + } + + for _, c := range cases { + f, err := os.Open(c.inFile) + if err != nil { + t.Fatal(err) + } + + got, err := ScanFile(f) + if err != nil { + t.Fatal(err) + } + + if got != c.want { + t.Errorf("ScanFile(%q) == %d, want %d", c.inFile, got, c.want) + } + } +} \ No newline at end of file diff --git a/day02/input1.txt b/day02/input1.txt new file mode 100644 index 0000000..1cd7d33 --- /dev/null +++ b/day02/input1.txt @@ -0,0 +1,5 @@ +Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green +Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue +Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red +Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red +Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..00f0358 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.qenya.tel/qenya/aoc2023 + +go 1.23.2 diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..8303b75 --- /dev/null +++ b/shell.nix @@ -0,0 +1,10 @@ +let + pkgs = import {}; +in pkgs.mkShell { + packages = with pkgs; [ + go + ]; + shellHook = '' + export PATH=$PATH:~/go/bin + ''; +} \ No newline at end of file