├── .gitignore ├── src └── main │ └── java │ ├── AdventOfCode15.java │ ├── AdventOfCode01.java │ ├── AdventOfCode09.java │ ├── AdventOfCode14.java │ ├── AdventOfCode06.java │ ├── AdventOfCode08.java │ ├── AdventOfCode12.java │ ├── AdventOfCode02.java │ ├── AdventOfCode04.java │ ├── AdventOfCode11.java │ ├── AdventOfCode03.java │ ├── AdventOfCode07.java │ ├── AdventOfCode21.java │ ├── AdventOfCode13.java │ ├── AdventOfCode18.java │ ├── AdventOfCode16.java │ ├── AdventOfCode25.java │ ├── AdventOfCode10.java │ ├── AdventOfCode24.java │ ├── AdventOfCode19.java │ ├── AdventOfCode23.java │ ├── AdventOfCode17.java │ ├── AdventOfCode05.java │ ├── AdventOfCode22.java │ └── AdventOfCode20.java ├── LICENSE ├── pom.xml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | replay_pid* 25 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode15.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class AdventOfCode15 { 4 | static int sumOfHashes(String input) { 5 | return Arrays.stream(input.split("[,\n]")) 6 | .mapToInt(text -> text.chars().reduce(0, (acc, c) -> ((acc + c) * 17) & 0xFF)).sum(); 7 | } 8 | 9 | public static void main(String[] args) { 10 | var input = """ 11 | rn=1,cm-,qp=3,cm=2,qp-,pc=4,ot=9,ab=5,pc-,pc=6,ot=7 12 | """; 13 | System.out.println(sumOfHashes(input)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode01.java: -------------------------------------------------------------------------------- 1 | public class AdventOfCode01 { 2 | static int sumOfDigits(String input) { 3 | return input.lines() 4 | .map(line -> line.chars().filter(c -> c >= '0' && c <= '9').mapToObj(c -> c - '0').toList()) 5 | .mapToInt(list -> 10 * list.getFirst() + list.getLast()) 6 | .sum(); 7 | } 8 | 9 | public static void main(String[] args) { 10 | var input = """ 11 | 1abc2 12 | pqr3stu8vwx 13 | a1b2c3d4e5f 14 | treb7uchet 15 | """; 16 | System.out.println(sumOfDigits(input)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode09.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.List; 3 | import java.util.stream.Stream; 4 | 5 | import static java.util.stream.IntStream.range; 6 | 7 | public class AdventOfCode09 { 8 | static int analysisOasisAndReportSum(String input) { 9 | return input.lines() 10 | .map(line -> Arrays.stream(line.split(" ")).map(Integer::parseInt).toList()) 11 | .mapToInt(history -> Stream.iterate(history, 12 | h -> !h.stream().allMatch(v -> v == 0), 13 | h -> range(1, h.size()).mapToObj(i -> h.get(i) - h.get(i - 1)).toList()) 14 | .mapToInt(List::getLast) 15 | .sum()) 16 | .sum(); 17 | } 18 | 19 | public static void main(String[] args) { 20 | var input = """ 21 | 0 3 6 9 12 15 22 | 1 3 6 10 15 21 23 | 10 13 16 21 30 45 24 | """; 25 | System.out.println(analysisOasisAndReportSum(input)); 26 | } 27 | } -------------------------------------------------------------------------------- /src/main/java/AdventOfCode14.java: -------------------------------------------------------------------------------- 1 | import static java.util.stream.IntStream.range; 2 | 3 | public class AdventOfCode14 { 4 | static int totalLoad(String input) { 5 | var lines = input.lines().toList(); 6 | var width = lines.getFirst().length(); 7 | var height = lines.size(); 8 | var next = new int[width]; 9 | return range(0, height) 10 | .map(row -> range(0, width) 11 | .map(column -> switch (lines.get(row).charAt(column)) { 12 | case '#' -> { next[column] = row + 1; yield 0; } 13 | case 'O' -> height - next[column]++; 14 | default -> 0; 15 | }) 16 | .sum()) 17 | .sum(); 18 | } 19 | 20 | public static void main(String[] args) { 21 | var input = """ 22 | O....#.... 23 | O.OO#....# 24 | .....##... 25 | OO.#O....O 26 | .O.....O#. 27 | O.#..O.#.# 28 | ..O..#O..O 29 | .......O.. 30 | #....###.. 31 | #OO..#.... 32 | """; 33 | System.out.println(totalLoad(input)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode06.java: -------------------------------------------------------------------------------- 1 | import java.util.regex.Pattern; 2 | import java.util.stream.IntStream; 3 | 4 | import static java.lang.Integer.parseInt; 5 | 6 | public class AdventOfCode06 { 7 | private static final Pattern NUMBER = Pattern.compile("(\\d+)"); 8 | 9 | static int productOfPossibilities(String input) { 10 | var lines = input.lines().toList(); 11 | var time = NUMBER.matcher(lines.getFirst()).results().map(r -> parseInt(r.group())).toList(); 12 | var distance = NUMBER.matcher(lines.get(1)).results().map(r -> parseInt(r.group())).toList(); 13 | return IntStream.range(0, time.size()) 14 | .map(i -> { 15 | var t = time.get(i); 16 | var d = distance.get(i); 17 | return IntStream.range(1, t).map(x -> - x * x + t * x > d ? 1 : 0).sum(); 18 | }) 19 | .reduce(1, (a, b) -> a * b); 20 | } 21 | 22 | public static void main(String[] args) { 23 | var input = """ 24 | Time: 7 15 30 25 | Distance: 9 40 200 26 | """; 27 | 28 | System.out.println(productOfPossibilities(input)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Rémi Forax 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode08.java: -------------------------------------------------------------------------------- 1 | import java.util.Scanner; 2 | import java.util.function.Predicate; 3 | import java.util.regex.Pattern; 4 | import java.util.stream.Stream; 5 | 6 | import static java.util.function.Predicate.not; 7 | import static java.util.stream.Collectors.toMap; 8 | 9 | public class AdventOfCode08 { 10 | private static final Pattern PATTERN = Pattern.compile("(\\w+) = \\((\\w+), (\\w+)\\)"); 11 | 12 | static int stepCount(String input) { 13 | var scanner = new Scanner(input); 14 | var instrs = scanner.nextLine().chars().map(c -> c == 'L' ? 0 : 1).toArray(); 15 | record Node(String name, String... next) {} 16 | var map = scanner.findAll(PATTERN) 17 | .map(result -> new Node(result.group(1), result.group(2), result.group(3))) 18 | .collect(toMap(Node::name, n -> n)); 19 | var cycle = Stream.iterate(0, i -> (i + 1) % instrs.length).iterator(); 20 | return (int) Stream.iterate("AAA", not("ZZZ"::equals), n -> map.get(n).next[instrs[cycle.next()]]).count(); 21 | } 22 | 23 | public static void main(String[] args) { 24 | var input = """ 25 | LLR 26 | 27 | AAA = (BBB, BBB) 28 | BBB = (AAA, ZZZ) 29 | ZZZ = (ZZZ, ZZZ) 30 | """; 31 | System.out.println(stepCount(input)); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode12.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.List; 3 | import java.util.regex.Pattern; 4 | 5 | public class AdventOfCode12 { 6 | private static final Pattern PATTERN = Pattern.compile("[#]+"); 7 | 8 | static int combination(String line, List damages) { 9 | var index = line.indexOf('?'); 10 | if (index == -1) { 11 | return damages.equals(PATTERN.matcher(line).results().map(r -> r.group().length()).toList()) ? 1 : 0; 12 | } 13 | var prefix = line.substring(0, index); 14 | var suffix = index == line.length() - 1 ? "" : line.substring(index + 1); 15 | return combination(prefix + "." + suffix, damages) + combination(prefix + "#" + suffix, damages); 16 | } 17 | 18 | static int sumOfCombinations(String input) { 19 | return input.lines() 20 | .map(line -> line.split(" ")) 21 | .mapToInt(pair -> combination(pair[0], Arrays.stream(pair[1].split(",")).map(Integer::parseInt).toList())) 22 | .sum(); 23 | } 24 | 25 | public static void main(String[] args){ 26 | var input = """ 27 | ???.### 1,1,3 28 | .??..??...?##. 1,1,3 29 | ?#?#?#?#?#?#?#? 1,3,1,6 30 | ????.#...#... 4,1,1 31 | ????.######..#####. 1,6,5 32 | ?###???????? 3,2,1 33 | """; 34 | 35 | System.out.println(sumOfCombinations(input)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 4.0.0 6 | com.github.forax.adventofcode 7 | adventofcode-2023 8 | 0.0.1-SNAPSHOT 9 | 10 | 11 | UTF-8 12 | 13 | 14 | 15 | 16 | org.junit.jupiter 17 | junit-jupiter-api 18 | 5.10.1 19 | test 20 | 21 | 22 | 23 | 24 | 25 | 26 | org.apache.maven.plugins 27 | maven-compiler-plugin 28 | 3.11.0 29 | 30 | 21 31 | 32 | 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-surefire-plugin 37 | 3.2.2 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode02.java: -------------------------------------------------------------------------------- 1 | import java.util.Map; 2 | import java.util.regex.Pattern; 3 | import java.util.stream.Stream; 4 | 5 | import static java.lang.Integer.parseInt; 6 | import static java.util.regex.Pattern.compile; 7 | import static java.util.stream.IntStream.range; 8 | 9 | public class AdventOfCode02 { 10 | private static final Pattern PATTERN = Pattern.compile("Game ([0-9]+)|([0-9]+) (red|green|blue)"); 11 | 12 | static int sumOfGameId(String input, int expectedRed, int expectedGreen, int expectedBlue) { 13 | var expected = Map.of("red", expectedRed, "green", expectedGreen, "blue", expectedBlue); 14 | return input.lines() 15 | .mapToInt(line -> { 16 | var matcher = PATTERN.matcher(line); 17 | matcher.find(); 18 | var gameId = parseInt(matcher.group(1)); 19 | return matcher.results().allMatch(result -> parseInt(result.group(2)) <= expected.get(result.group(3))) ? gameId : 0; 20 | }) 21 | .sum(); 22 | } 23 | 24 | public static void main(String[] args) { 25 | var text = """ 26 | Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green 27 | Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue 28 | Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red 29 | Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red 30 | Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green 31 | """; 32 | System.out.println(sumOfGameId(text, 12, 13, 14)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode04.java: -------------------------------------------------------------------------------- 1 | import java.util.HashSet; 2 | import java.util.Scanner; 3 | import java.util.function.IntUnaryOperator; 4 | import java.util.stream.Stream; 5 | 6 | import static java.lang.Integer.parseInt; 7 | 8 | public class AdventOfCode04 { 9 | static int winningPoints(String input) { 10 | return input.lines() 11 | .mapToInt(line -> { 12 | var winnings = new HashSet(); 13 | var state = new Object() { IntUnaryOperator action = v -> winnings.add(v) ? 0 : 0; }; 14 | return Stream.iterate(new Scanner(line.substring(line.indexOf(':') + 1)), Scanner::hasNext, s -> s) 15 | .mapToInt(scanner -> switch (scanner.next()) { 16 | case "|" -> { state.action = v -> winnings.contains(v) ? 1 : 0; yield 0; } 17 | case String token -> state.action.applyAsInt(parseInt(token)); 18 | }) 19 | .reduce(0, (v1, v2) -> v2 == 0 ? v1 : (v1 == 0) ? 1 : v1 * 2); 20 | }) 21 | .sum(); 22 | } 23 | 24 | public static void main(String[] args) { 25 | var text = """ 26 | Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 27 | Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 28 | Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 29 | Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 30 | Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 31 | Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11 32 | """; 33 | System.out.println(winningPoints(text)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode11.java: -------------------------------------------------------------------------------- 1 | import static java.util.stream.Collectors.joining; 2 | import static java.util.stream.IntStream.range; 3 | 4 | public class AdventOfCode11 { 5 | static int sumOfShortestPaths(String input) { 6 | var data = input.lines().collect(joining()); 7 | var notCols = new boolean[input.indexOf('\n')]; 8 | var notRows = new boolean[data.length() / notCols.length]; 9 | class Galaxy { 10 | final int x, y; Galaxy(int x, int y) { this.x = x; this.y = y; } 11 | int distance(Galaxy g) { 12 | // I'm not sure, it's the correct way to compute the length between galaxies 13 | return ((x == g.x) ? 0 : ((x < g.x) ? range(x, g.x) : range(g.x, x)).map(i -> notCols[i] ? 1 : 2).sum()) + 14 | ((y == g.y) ? 0 : ((y < g.y) ? range(y, g.y) : range(g.y, y)).map(j -> notRows[j] ? 1 : 2).sum()); 15 | } 16 | } 17 | var galaxies = range(0, data.length()) 18 | .filter(i -> data.charAt(i) == '#') 19 | .mapToObj(i -> new Galaxy(i % notCols.length, i / notCols.length)) 20 | .peek(g -> { notCols[g.x] = true; notRows[g.y] = true; }) 21 | .toList(); 22 | return range(0, galaxies.size()).boxed() 23 | .flatMapToInt(i -> range(0, i).map(j -> galaxies.get(i).distance(galaxies.get(j)))) 24 | .sum(); 25 | } 26 | 27 | public static void main(String[] args){ 28 | var input = """ 29 | ...#...... 30 | .......#.. 31 | #......... 32 | .......... 33 | ......#... 34 | .#........ 35 | .........# 36 | .......... 37 | .......#.. 38 | #...#..... 39 | """; 40 | System.out.println(sumOfShortestPaths(input)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode03.java: -------------------------------------------------------------------------------- 1 | import java.util.TreeMap; 2 | import java.util.regex.MatchResult; 3 | import java.util.regex.Pattern; 4 | import java.util.stream.IntStream; 5 | import java.util.stream.Stream; 6 | 7 | import static java.lang.Integer.parseInt; 8 | import static java.util.stream.Collectors.collectingAndThen; 9 | import static java.util.stream.Collectors.partitioningBy; 10 | import static java.util.stream.Collectors.toMap; 11 | import static java.util.stream.Collectors.toSet; 12 | 13 | public class AdventOfCode03 { 14 | private static final Pattern PATTERN = Pattern.compile("([0-9]+)|([*#+*$])"); 15 | 16 | static int sumOfParts(String input) { 17 | var length = 1 + input.indexOf('\n'); 18 | var map = PATTERN.matcher(input).results() 19 | .collect(partitioningBy(result -> result.start(1) != -1, 20 | toMap(MatchResult::start, MatchResult::group, (_1, _2) -> null, TreeMap::new))); 21 | return map.get(false).keySet().stream() 22 | .flatMap(start -> Stream.of(-length, 0, length) 23 | .flatMap(j -> IntStream.of(-1, 0, 1).mapToObj(i -> start + i + j))) 24 | .flatMap(start -> Stream.ofNullable(map.get(true).floorEntry(start)).filter(e -> start < e.getKey() + e.getValue().length())) 25 | .collect(collectingAndThen(toSet(), set -> set.stream().mapToInt(e -> parseInt(e.getValue())).sum())); 26 | } 27 | 28 | public static void main(String[] args) { 29 | var text = """ 30 | 467..114.. 31 | ...*...... 32 | ..35..633. 33 | ......#... 34 | 617*...... 35 | .....+.58. 36 | ..592..... 37 | ......755. 38 | ...$.*.... 39 | .664.598.. 40 | """; 41 | System.out.println(sumOfParts(text)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode07.java: -------------------------------------------------------------------------------- 1 | import java.util.Map; 2 | import java.util.Scanner; 3 | import java.util.stream.Stream; 4 | 5 | import static java.util.Comparator.comparingLong; 6 | import static java.util.Comparator.reverseOrder; 7 | import static java.util.stream.Collectors.collectingAndThen; 8 | import static java.util.stream.Collectors.counting; 9 | import static java.util.stream.Collectors.groupingBy; 10 | import static java.util.stream.Collectors.teeing; 11 | import static java.util.stream.Collectors.toList; 12 | import static java.util.stream.Collectors.toMap; 13 | import static java.util.stream.IntStream.range; 14 | 15 | public class AdventOfCode07 { 16 | private static final Map MAP = 17 | range(0, 13).boxed().collect(toMap(i -> (int) "AKQJT98765432".charAt(i), i -> 12 - i)); 18 | 19 | static int totalWinnings(String input) { 20 | record Pair(long hash, int bid) {} 21 | var bids = Stream.iterate(new Scanner(input), Scanner::hasNext, s -> s) 22 | .map(scanner -> scanner.next().chars().mapToObj(MAP::get) 23 | .collect(teeing(toList(), 24 | collectingAndThen(groupingBy(v -> v,counting()), 25 | m -> m.values().stream().sorted(reverseOrder()).limit(2).toList()), 26 | (hand, counts) -> new Pair(((long) counts.hashCode()) << 32 | hand.hashCode(), scanner.nextInt())))) 27 | .sorted(comparingLong(Pair::hash)) 28 | .map(Pair::bid) 29 | .toList(); 30 | return range(0, bids.size()).map(i -> (i + 1) * bids.get(i)).sum(); 31 | } 32 | 33 | public static void main(String[] args) { 34 | var input = """ 35 | 32T3K 765 36 | T55J5 684 37 | KK677 28 38 | KTJJT 220 39 | QQQJA 483 40 | """; 41 | System.out.println(totalWinnings(input)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode21.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | import java.util.Set; 3 | 4 | import static java.util.stream.Collectors.joining; 5 | import static java.util.stream.Collectors.toSet; 6 | import static java.util.stream.IntStream.range; 7 | 8 | public class AdventOfCode21 { 9 | 10 | record Pos(int x, int y) { 11 | Pos next(Dir dir) { return new Pos(x + dir.dx, y + dir.dy); } 12 | } 13 | enum Dir { 14 | NORTH(0, -1), EAST(1, 0), SOUTH(0, 1), WEST(-1, 0); 15 | private static final List ALL = List.of(values()); 16 | private final int dx, dy; Dir(int dx, int dy) { this.dx = dx; this.dy = dy; } 17 | } 18 | record Grid(String data, int width, int height) { 19 | boolean in(Pos pos) { return pos.x >= 0 && pos.x < width && pos.y >= 0 && pos.y < height; } 20 | char at(Pos pos) { return data.charAt(pos.x + pos.y * width); } 21 | } 22 | 23 | static Set step(Grid grid, Set positions) { 24 | return positions.stream() 25 | .flatMap(p -> Dir.ALL.stream().map(p::next)) 26 | .filter(p -> grid.in(p) && grid.at(p) != '#') 27 | .collect(toSet()); 28 | } 29 | 30 | static int locationCount(String input, int steps) { 31 | var data = input.lines().collect(joining()); 32 | var width = input.indexOf('\n'); 33 | var grid = new Grid(data, width, data.length() / width); 34 | var startIndex = data.indexOf('S'); 35 | var start = new Pos(startIndex % width, startIndex / width); 36 | return range(0, steps).boxed() 37 | .reduce(Set.of(start), (set, __) -> step(grid, set), (_1, _2) -> null) 38 | .size(); 39 | } 40 | 41 | public static void main(String[] args) { 42 | var input = """ 43 | ........... 44 | .....###.#. 45 | .###.##..#. 46 | ..#.#...#.. 47 | ....#.#.... 48 | .##..S####. 49 | .##..#...#. 50 | .......##.. 51 | .##.#.####. 52 | .##..##.##. 53 | ........... 54 | """; 55 | System.out.println(locationCount(input, 64)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode13.java: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | 3 | import static java.util.stream.Collectors.groupingBy; 4 | import static java.util.stream.Collectors.joining; 5 | import static java.util.stream.Collectors.toList; 6 | import static java.util.stream.IntStream.range; 7 | 8 | public class AdventOfCode13 { 9 | 10 | static int mirror(List lines) { 11 | return range(0, lines.size()).boxed() 12 | .collect(groupingBy(lines::get, toList())) 13 | .values().stream() 14 | .flatMap(indexes -> { 15 | var state = new Object() { int index = -2; }; 16 | return indexes.stream().sorted().mapMulti((index, consumer) -> { 17 | if (state.index + 1 == index) { 18 | consumer.accept(state.index); 19 | } 20 | state.index = index; 21 | }); 22 | }) 23 | .filter(index -> range(0, index).filter(i -> index - i >= 0 && index + 1 + i < lines.size()) 24 | .allMatch(i -> lines.get(index - i).equals(lines.get(index + 1 + i)))) 25 | .findFirst().map(index -> 1 + index).orElseThrow(); 26 | } 27 | 28 | static int summarizingMirrors(String input) { 29 | var puzzles = input.split("\n\n"); 30 | var lines = puzzles[0].lines().toList(); 31 | var puzzle1Columns = range(0, lines.getFirst().length()) 32 | .mapToObj(i -> lines.stream().map(line -> "" + line.charAt(i)).collect(joining())) 33 | .toList(); 34 | var puzzle2Lines = puzzles[1].lines().toList(); 35 | return mirror(puzzle1Columns) + 100 * mirror(puzzle2Lines); 36 | } 37 | 38 | public static void main(String[] args) { 39 | var input = """ 40 | #.##..##. 41 | ..#.##.#. 42 | ##......# 43 | ##......# 44 | ..#.##.#. 45 | ..##..##. 46 | #.#.##.#. 47 | 48 | #...##..# 49 | #....#..# 50 | ..##..### 51 | #####.##. 52 | #####.##. 53 | ..##..### 54 | #....#..# 55 | """; 56 | System.out.println(summarizingMirrors(input)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode18.java: -------------------------------------------------------------------------------- 1 | import java.util.Scanner; 2 | import java.util.stream.IntStream; 3 | import java.util.stream.Stream; 4 | 5 | import static java.util.stream.Collectors.groupingBy; 6 | import static java.util.stream.Collectors.summarizingInt; 7 | import static java.util.stream.IntStream.rangeClosed; 8 | 9 | public class AdventOfCode18 { 10 | static int sumOfFilledPool(String input) { 11 | record Pos(int x, int y) {} 12 | var state = new Object() { int x, y; }; 13 | return Stream.concat(Stream.of(new Pos(0, 0)), Stream.iterate(new Scanner(input), Scanner::hasNext, s -> s) 14 | .flatMap(scanner -> { 15 | var letter = scanner.next().charAt(0); 16 | var distance = scanner.nextInt(); 17 | scanner.next(); // skip color 18 | return switch (letter) { 19 | case 'R', 'L' -> { 20 | var order = letter == 'R' ? 1 : -1; 21 | var x = state.x; state.x += order * distance; 22 | yield IntStream.of(1, distance).mapToObj(i -> new Pos(x + order * i, state.y)); 23 | } 24 | default -> { // case 'D', 'U' 25 | var order = letter == 'D' ? 1 : -1; 26 | var y = state.y; state.y += order * distance; 27 | yield rangeClosed(1, distance).mapToObj(i -> new Pos(state.x, y + order * i)); 28 | } 29 | }; 30 | }) 31 | ).collect(groupingBy(Pos::y, summarizingInt(Pos::x))) 32 | .values().stream().mapToInt(stat -> 1 + stat.getMax() - stat.getMin()).sum(); 33 | } 34 | 35 | public static void main(String[] args) { 36 | var input = """ 37 | R 6 (#70c710) 38 | D 5 (#0dc571) 39 | L 2 (#5713f0) 40 | D 2 (#d2c081) 41 | R 2 (#59c680) 42 | D 2 (#411b91) 43 | L 5 (#8ceee2) 44 | U 2 (#caa173) 45 | L 1 (#1b58a2) 46 | U 2 (#caa171) 47 | R 2 (#7807d2) 48 | U 3 (#a77fa3) 49 | L 2 (#015232) 50 | U 2 (#7a21e3) 51 | """; 52 | System.out.println(sumOfFilledPool(input)); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode16.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.List; 3 | import java.util.Map; 4 | import java.util.function.Function; 5 | 6 | public class AdventOfCode16 { 7 | enum Dir { 8 | NORTH(0, -1), EAST(1, 0), SOUTH(0, 1), WEST(-1, 0); 9 | private static final List ALL = List.of(values()); 10 | private final int dx, dy; Dir(int dx, int dy) { this.dx = dx; this.dy = dy; } 11 | Dir step(int step) { return ALL.get((ordinal() + step) % ALL.size()); } 12 | int orient() { return 1 + (ordinal() & 1); } 13 | } 14 | 15 | private static final int VERTICAL = 1, HORIZONTAL = 2; 16 | private static final Map>> MAP = Map.of( 17 | '|', d -> d.orient() == HORIZONTAL ? List.of(Dir.NORTH, Dir.SOUTH) : List.of(d), 18 | '-', d -> d.orient() == VERTICAL ? List.of(Dir.WEST, Dir.EAST) : List.of(d), 19 | '/', d -> List.of(d.orient() == HORIZONTAL ? d.step(3) : d.step(1)), 20 | '\\', d -> List.of(d.step(1)) 21 | ); 22 | 23 | 24 | static void move(int x, int y, Dir dir, char[][] grid, int[][] energy) { 25 | int orient; 26 | if (x < 0 || x >= grid[0].length || y < 0 || y >= grid.length || ((orient = dir.orient()) & energy[y][x]) != 0) { 27 | return; 28 | } 29 | energy[y][x] |= orient; 30 | var letter = grid[y][x]; 31 | for(var newDir : MAP.getOrDefault(letter, __ -> List.of(dir)).apply(dir)) { 32 | move(x + newDir.dx, y + newDir.dy, newDir, grid, energy); 33 | } 34 | } 35 | 36 | static int sumOfEnergized(String input) { 37 | var grid = input.lines().map(String::toCharArray).toArray(char[][]::new); 38 | var energy = new int[grid[0].length][grid.length]; 39 | move(0, 0, Dir.EAST, grid, energy); 40 | return Arrays.stream(energy).flatMapToInt(Arrays::stream).filter(e -> e != 0).sum(); 41 | } 42 | 43 | public static void main(String[] args) { 44 | var input = """ 45 | .|...\\.... 46 | |.-.\\..... 47 | .....|-... 48 | ........|. 49 | .......... 50 | .........\\ 51 | ..../.\\\\.. 52 | .-.-/..|.. 53 | .|....-|.\\ 54 | ..//.|.... 55 | """; 56 | System.out.println(sumOfEnergized(input)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode25.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayList; 2 | import java.util.BitSet; 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.Scanner; 7 | import java.util.stream.Stream; 8 | 9 | import static java.util.stream.Collectors.groupingBy; 10 | 11 | public class AdventOfCode25 { 12 | 13 | record Edge(int src, int dst) {} 14 | 15 | static void reachableFrom(Map> graph, int node, BitSet visited) { 16 | if (visited.get(node)) { 17 | return; 18 | } 19 | visited.set(node); 20 | for(var edge : graph.get(node)) { 21 | reachableFrom(graph, edge.dst, visited); 22 | } 23 | } 24 | 25 | static int tryCut(List edges, int depth) { 26 | if (depth == 0) { 27 | var bits = new BitSet(); 28 | var graph = edges.stream().flatMap(e -> Stream.of(e, new Edge(e.dst, e.src))).collect(groupingBy(Edge::src)); 29 | reachableFrom(graph, 0, bits); 30 | if (bits.cardinality() != graph.size()) { 31 | return bits.cardinality() * (graph.size() - bits.cardinality()); 32 | } 33 | return -1; 34 | } 35 | for (var i = 0; i < edges.size(); i++) { 36 | var newEdged = new ArrayList<>(edges); 37 | newEdged.remove(i); 38 | var cut = tryCut(newEdged, depth - 1); 39 | if (cut != -1) { 40 | return cut; 41 | } 42 | } 43 | return -1; 44 | } 45 | 46 | static int productOfConnectedNodes(String input) { 47 | var map = new HashMap(); 48 | var edges = input.lines() 49 | .flatMap(line -> { 50 | var scanner = new Scanner(line).useDelimiter("[: ]+"); 51 | var srcText = scanner.next(); 52 | var src = map.computeIfAbsent(srcText, __ -> map.size()); 53 | return Stream.iterate(scanner, Scanner::hasNext, s -> s) 54 | .map(s -> new Edge(src, map.computeIfAbsent(s.next(), __ -> map.size()))); 55 | }) 56 | .toList(); 57 | 58 | return tryCut(edges, 3); 59 | } 60 | 61 | public static void main(String[] args) { 62 | var input = """ 63 | jqt: rhn xhk nvd 64 | rsh: frs pzl lsr 65 | xhk: hfx 66 | cmg: qnr nvd lhk bvb 67 | rhn: xhk bvb hfx 68 | bvb: xhk hfx 69 | pzl: lsr hfx nvd 70 | qnr: nvd 71 | ntq: jqt hfx bvb xhk 72 | nvd: lhk 73 | lsr: lhk 74 | rzs: qnr cmg lsr rsh 75 | frs: qnr lhk lsr 76 | """; 77 | 78 | System.out.println(productOfConnectedNodes(input)); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode10.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.Map; 3 | import java.util.function.UnaryOperator; 4 | 5 | import static java.util.stream.Collectors.joining; 6 | 7 | public class AdventOfCode10 { 8 | record Pos(int x, int y) { 9 | Pos next(Dir dir) { return new Pos(x + dir.dx, y + dir.dy); } 10 | } 11 | enum Dir { 12 | NORTH(0, -1), EAST(1, 0), SOUTH(0, 1), WEST(-1, 0); 13 | private final int dx, dy; Dir(int dx, int dy) { this.dx = dx; this.dy = dy; } 14 | } 15 | record Grid(String data, int width, int height) { 16 | boolean in(Pos pos) { return pos.x >= 0 && pos.x < width && pos.y >= 0 && pos.y < height; } 17 | char at(Pos pos) { return data.charAt(pos.x + pos.y * width); } 18 | } 19 | 20 | private static final Map> PIPE_MAP = Map.of( 21 | '|', d -> d == Dir.NORTH || d == Dir.SOUTH ? d : null, 22 | '-', d -> d == Dir.EAST || d == Dir.WEST ? d : null, 23 | 'L', d -> d == Dir.SOUTH ? Dir.EAST : (d == Dir.WEST ? Dir.NORTH : null), 24 | 'J', d -> d == Dir.SOUTH ? Dir.WEST : (d == Dir.EAST ? Dir.NORTH : null), 25 | '7', d -> d == Dir.NORTH ? Dir.WEST : (d == Dir.EAST ? Dir.SOUTH : null), 26 | 'F', d -> d == Dir.NORTH ? Dir.EAST : (d == Dir.WEST ? Dir.SOUTH : null) 27 | ); 28 | 29 | static int farthest(String input) { 30 | var data = input.lines().collect(joining()); 31 | var width = input.indexOf('\n'); 32 | var grid = new Grid(data, width, data.length() / width); 33 | var startIndex = data.indexOf('S'); 34 | var start = new Pos(startIndex % width, startIndex / width); 35 | var dir = Arrays.stream(Dir.values()) 36 | .filter(d -> grid.in(start.next(d))) 37 | .filter(d -> PIPE_MAP.getOrDefault(grid.at(start.next(d)), __ -> null).apply(d) != null) 38 | .findFirst().orElseThrow(); 39 | var step = 0; 40 | var pos = start; 41 | for(;;) { 42 | pos = pos.next(dir); 43 | var symbol = grid.at(pos); 44 | if (symbol == 'S') { 45 | break; 46 | } 47 | dir = PIPE_MAP.get(symbol).apply(dir); 48 | step++; 49 | } 50 | return step / 2 + step % 2; 51 | } 52 | 53 | public static void main(String[] args){ 54 | var input = """ 55 | -L|F7 56 | 7S-7| 57 | L|7|| 58 | -L-J| 59 | L|-JF 60 | """; 61 | System.out.println(farthest(input)); 62 | 63 | var input2 = """ 64 | 7-F7- 65 | .FJ|7 66 | SJLL7 67 | |F--J 68 | LJ.LJ 69 | """; 70 | System.out.println(farthest(input2)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode24.java: -------------------------------------------------------------------------------- 1 | import java.math.BigInteger; 2 | import java.util.regex.Pattern; 3 | 4 | import static java.lang.Long.parseLong; 5 | import static java.util.stream.IntStream.range; 6 | 7 | public class AdventOfCode24 { 8 | 9 | record Rat(BigInteger num, BigInteger den) implements Comparable { 10 | Rat { 11 | if (den.signum() == -1) { num = num.negate(); den = den.negate(); } 12 | var gcd = num.gcd(den); num = num.divide(gcd); den = den.divide(gcd); 13 | } 14 | Rat(long num) { this(BigInteger.valueOf(num), BigInteger.ONE); } 15 | Rat mul(Rat rat) { return new Rat(num.multiply(rat.num), den.multiply(rat.den)); } 16 | Rat div(Rat rat) { return mul(new Rat(rat.den, rat.num)); } 17 | Rat add(Rat rat) { return new Rat(num.multiply(rat.den).add(rat.num.multiply(den)), den.multiply(rat.den)); } 18 | Rat sub(Rat rat) { return add(new Rat(rat.num.negate(), rat.den)); } 19 | public int compareTo(Rat rat) { return num.multiply(rat.den).compareTo(rat.num.multiply(den)); } 20 | public String toString() { return num + "/" + den; } 21 | } 22 | 23 | private static final Pattern PATTERN = Pattern.compile("[, @]+"); 24 | 25 | static int cross(String input, Rat low, Rat high) { 26 | record HailStone(Rat x, Rat y, Rat vx, Rat vy) {} 27 | var stones = input.lines() 28 | .map(l -> { 29 | var data = PATTERN.splitAsStream(l).map(s -> new Rat(parseLong(s))).toArray(Rat[]::new); 30 | return new HailStone(data[0], data[1], data[3], data[4]); 31 | }) 32 | .toList(); 33 | return range(0, stones.size()) 34 | .flatMap(i -> range(0, i).map(j -> { 35 | var a = stones.get(i); 36 | var b = stones.get(j); 37 | var u = b.x.sub(a.x).mul(a.vy).div(a.vx).add(a.y).sub(b.y).div(b.vy.sub(a.vy.mul(b.vx).div(a.vx))); 38 | var t = b.vx.mul(u).add(b.x).sub(a.x).div(a.vx); 39 | if (t.den.equals(BigInteger.ZERO) || t.num.signum() == -1 || u.num.signum() == -1) { 40 | return 0; 41 | } 42 | var x = a.vx.mul(t).add(a.x); 43 | var y = a.vy.mul(t).add(a.y); 44 | return (low.compareTo(x) <= 0 && high.compareTo(x) >= 0 && 45 | low.compareTo(y) <= 0 && high.compareTo(y) >= 0) ? 1 : 0; 46 | })) 47 | .sum(); 48 | } 49 | 50 | public static void main(String[] args) { 51 | var input = """ 52 | 19, 13, 30 @ -2, 1, -2 53 | 18, 19, 22 @ -1, -1, -2 54 | 20, 25, 34 @ -2, -2, -4 55 | 12, 31, 28 @ -1, -2, -1 56 | 20, 19, 15 @ 1, -5, -3 57 | """; 58 | var low = new Rat(7); 59 | var hight = new Rat(27); 60 | System.out.println(cross(input, low, hight)); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode19.java: -------------------------------------------------------------------------------- 1 | import java.util.Map; 2 | import java.util.regex.Pattern; 3 | 4 | import static java.lang.Integer.parseInt; 5 | import static java.util.stream.Collectors.toMap; 6 | 7 | public class AdventOfCode19 { 8 | 9 | private static final Pattern ACTION = Pattern.compile("([a-z]+)([\\<\\>])(\\d+)\\:([a-zAR]+)|([a-zAR]+)"); 10 | private static final Pattern PROPERTY = Pattern.compile("(\\w+)=(\\d+)"); 11 | 12 | static int sumOfRatingNumbers(String input) { 13 | interface Action { String apply(Map ratings); } 14 | var index = input.indexOf("\n\n"); 15 | var actionMap = input.substring(0, index).lines() 16 | .collect(toMap( 17 | line -> line.substring(0, line.indexOf('{')), 18 | line -> ACTION.matcher(line).region(line.indexOf('{'), line.length()).results() 19 | .map(r -> { 20 | if (r.start(5) != -1) { 21 | return ratings -> r.group(5); 22 | } 23 | var variable = r.group(1); 24 | var number = parseInt(r.group(3)); 25 | var target = r.group(4); 26 | return switch (r.group(2)) { 27 | case "<" -> ratings -> ratings.get(variable) < number ? target : null; 28 | default -> ratings -> ratings.get(variable) > number ? target : null; 29 | }; 30 | }) 31 | .toList())); 32 | return input.substring(index + 2).lines() 33 | .mapToInt(line -> { 34 | var ratings = PROPERTY.matcher(line).results().collect(toMap(r -> r.group(1), r -> parseInt(r.group(2)))); 35 | loop: for(var state = "in";;) { 36 | var actions = actionMap.get(state); 37 | for(var action: actions) { 38 | switch (action.apply(ratings)) { 39 | case null -> {} 40 | case "A" -> { return ratings.values().stream().mapToInt(v -> v).sum(); } 41 | case "R" -> { return 0; } 42 | case String target -> { state = target; continue loop; } 43 | } 44 | } 45 | } 46 | }) 47 | .sum(); 48 | } 49 | 50 | public static void main(String[] args) { 51 | var input = """ 52 | px{a<2006:qkq,m>2090:A,rfg} 53 | pv{a>1716:R,A} 54 | lnx{m>1548:A,A} 55 | rfg{s<537:gd,x>2440:R,A} 56 | qs{s>3448:A,lnx} 57 | qkq{x<1416:A,crn} 58 | crn{x>2662:A,R} 59 | in{s<1351:px,qqz} 60 | qqz{s>2770:qs,m<1801:hdj,R} 61 | gd{a>3333:R,R} 62 | hdj{m>838:A,pv} 63 | 64 | {x=787,m=2655,a=1222,s=2876} 65 | {x=1679,m=44,a=2067,s=496} 66 | {x=2036,m=264,a=79,s=2244} 67 | {x=2461,m=1339,a=466,s=291} 68 | {x=2127,m=1623,a=2188,s=1013} 69 | """; 70 | System.out.println(sumOfRatingNumbers(input)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode23.java: -------------------------------------------------------------------------------- 1 | import java.util.HashSet; 2 | import java.util.List; 3 | import java.util.Set; 4 | import java.util.stream.Stream; 5 | 6 | import static java.util.stream.Collectors.joining; 7 | 8 | public class AdventOfCode23 { 9 | record Pos(int x, int y) { 10 | Pos next(Dir dir) { return new Pos(x + dir.dx, y + dir.dy); } 11 | } 12 | enum Dir { 13 | NORTH(0, -1), EAST(1, 0), SOUTH(0, 1), WEST(-1, 0); 14 | private static final List ALL = List.of(values()); 15 | private final int dx, dy; Dir(int dx, int dy) { this.dx = dx; this.dy = dy; } 16 | } 17 | record Grid(String data, int width, int height) { 18 | boolean in(Pos pos) { return pos.x >= 0 && pos.x < width && pos.y >= 0 && pos.y < height; } 19 | char at(Pos pos) { return data.charAt(pos.x + pos.y * width); } 20 | } 21 | 22 | static int walk(Pos pos, Set visited, Grid grid, Pos end) { 23 | if (pos.equals(end)) { 24 | return visited.size(); 25 | } 26 | visited.add(pos); 27 | return Dir.ALL.stream() 28 | .flatMap(dir -> Stream.of(pos.next(dir)) 29 | .filter(p -> grid.in(p) && !visited.contains(p) && switch (grid.at(p)) { 30 | case '#' -> false; 31 | case '<' -> dir == Dir.WEST; 32 | case '>' -> dir == Dir.EAST; 33 | case '^' -> dir == Dir.NORTH; 34 | case 'v' -> dir == Dir.SOUTH; 35 | default -> true; // case '.' 36 | })) 37 | .mapToInt(p -> walk(p, new HashSet<>(visited), grid, end)) 38 | .max() 39 | .orElse(0); 40 | } 41 | 42 | static int longestHike(String input) { 43 | var data = input.lines().collect(joining()); 44 | var width = input.indexOf('\n'); 45 | var grid = new Grid(data, width, data.length() / width); 46 | var startIndex = data.indexOf('.'); 47 | var start = new Pos(startIndex % width, startIndex / width); 48 | var endIndex = data.lastIndexOf('.'); 49 | var end = new Pos(endIndex % width, endIndex / width); 50 | return walk(start, new HashSet<>(), grid, end); 51 | } 52 | 53 | public static void main(String[] args) { 54 | var input = """ 55 | #.##################### 56 | #.......#########...### 57 | #######.#########.#.### 58 | ###.....#.>.>.###.#.### 59 | ###v#####.#v#.###.#.### 60 | ###.>...#.#.#.....#...# 61 | ###v###.#.#.#########.# 62 | ###...#.#.#.......#...# 63 | #####.#.#.#######.#.### 64 | #.....#.#.#.......#...# 65 | #.#####.#.#.#########v# 66 | #.#...#...#...###...>.# 67 | #.#.#v#######v###.###v# 68 | #...#.>.#...>.>.#.###.# 69 | #####v#.#.###v#.#.###.# 70 | #.....#...#...#.#.#...# 71 | #.#########.###.#.#.### 72 | #...###...#...#...#.### 73 | ###.###.#.###v#####v### 74 | #...#...#.#.>.>.#.>.### 75 | #.###.###.#.###.#.#v### 76 | #.....###...###...#...# 77 | #####################.# 78 | """; 79 | System.out.println(longestHike(input)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode17.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.Comparator; 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.PriorityQueue; 6 | import java.util.stream.Stream; 7 | 8 | import static java.util.stream.IntStream.rangeClosed; 9 | 10 | public class AdventOfCode17 { 11 | enum Dir { 12 | NORTH(0, -1), EAST(1, 0), SOUTH(0, 1), WEST(-1, 0); 13 | private final int dx, dy; Dir(int dx, int dy) { this.dx = dx; this.dy = dy; } 14 | List next() { 15 | return switch (this) { 16 | case NORTH -> List.of(WEST, NORTH, EAST); 17 | case EAST -> List.of(NORTH, EAST, SOUTH); 18 | case SOUTH -> List.of(EAST, SOUTH, WEST); 19 | case WEST -> List.of(SOUTH, WEST, NORTH); 20 | }; 21 | } 22 | } 23 | 24 | static int minHeatLost(String input) { 25 | var grid = input.lines().map(line -> line.chars().map(c -> c - '0').toArray()).toArray(int[][]::new); 26 | var width = grid[0].length; 27 | var height = grid.length; 28 | record Walk(int x, int y, Dir dir, int dist) {} 29 | record Work(int x, int y, Dir dir, int dist, int heat) {} 30 | var queue = new PriorityQueue<>(Comparator.comparing(Work::heat)); 31 | queue.offer(new Work(0, 0, Dir.EAST, 0, 0)); 32 | var heatMap = new HashMap(); 33 | while(!queue.isEmpty()) { 34 | var work = queue.poll(); 35 | var x = work.x; 36 | var y = work.y; 37 | var heat = work.heat; 38 | var dir = work.dir; 39 | var dist = work.dist; 40 | var walk = new Walk(x, y, dir, dist); 41 | var seenHeat = heatMap.getOrDefault(walk, Integer.MAX_VALUE); 42 | if (seenHeat <= heat) { 43 | continue; 44 | } 45 | heatMap.put(walk, heat); 46 | if (x == width - 1 && y == height - 1) { 47 | continue; 48 | } 49 | for(var nextDir : dir.next()) { 50 | if (nextDir == dir && dist == 3) { 51 | continue; 52 | } 53 | var nextX = x + nextDir.dx; 54 | var nextY = y + nextDir.dy; 55 | if (nextX < 0 || nextX >= width || nextY < 0 || nextY >= height) { 56 | continue; 57 | } 58 | var nextHeat = grid[nextY][nextX] + heat; 59 | queue.offer(new Work(nextX, nextY, nextDir, nextDir == dir ? dist + 1 : 1, nextHeat)); 60 | } 61 | } 62 | return Arrays.stream(Dir.values()) 63 | .flatMap(d -> rangeClosed(1, 3).boxed().flatMap(i -> Stream.ofNullable(heatMap.get(new Walk(width - 1, height - 1, d, i))))) 64 | .mapToInt(v -> v) 65 | .min().orElseThrow(); 66 | } 67 | 68 | public static void main(String[] args) { 69 | var input = """ 70 | 2413432311323 71 | 3215453535623 72 | 3255245654254 73 | 3446585845452 74 | 4546657867536 75 | 1438598798454 76 | 4457876987766 77 | 3637877979653 78 | 4654967986887 79 | 4564679986453 80 | 1224686865563 81 | 2546548887735 82 | 4322674655533 83 | """; 84 | System.out.println(minHeatLost(input)); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode05.java: -------------------------------------------------------------------------------- 1 | import java.util.LinkedHashMap; 2 | import java.util.Optional; 3 | import java.util.Scanner; 4 | import java.util.function.IntFunction; 5 | import java.util.regex.Pattern; 6 | 7 | import static java.lang.Integer.parseInt; 8 | import static java.util.stream.Collectors.toList; 9 | import static java.util.stream.Collectors.toMap; 10 | 11 | public class AdventOfCode05 { 12 | private static final Pattern NUMBER = Pattern.compile("(\\d+)"); 13 | private static final Pattern TO = Pattern.compile("(\\w+)-to-(\\w+)"); 14 | private static final Pattern TRANSLATION = Pattern.compile("(\\d+)\\h+(\\d+)\\h+(\\d+)"); 15 | 16 | static int lowestLocationNumber(String input) { 17 | var scanner = new Scanner(input); 18 | var values = NUMBER.matcher(scanner.nextLine()).results().map(r -> parseInt(r.group())).collect(toList()); 19 | record Recipe(String from, String to, int location) {} 20 | var recipeMap = scanner.findAll(TO) 21 | .map(result -> new Recipe(result.group(1), result.group(2), result.end())) 22 | .collect(toMap(Recipe::from, r -> r, (_1, _2) -> null, LinkedHashMap::new)); 23 | for(var category = "seed"; !category.equals("location");) { 24 | var recipe = recipeMap.get(category); 25 | var end = recipeMap.values().stream() 26 | .dropWhile(r -> r != recipe).skip(1).mapToInt(Recipe::location).findFirst().orElseGet(input::length); 27 | var translations = TRANSLATION.matcher(input).region(recipe.location, end).results() 28 | .>>map(result -> { 29 | var destination = parseInt(result.group(1)); 30 | var source = parseInt(result.group(2)); 31 | var length = parseInt(result.group(3)); 32 | return v -> Optional.of(v).filter(x -> x >= source && x < source + length).map(x -> x - source + destination); 33 | }) 34 | .toList(); 35 | values.replaceAll(v -> translations.stream().flatMap(t -> t.apply(v).stream()).findFirst().orElse(v)); 36 | category = recipe.to; 37 | } 38 | return values.stream().mapToInt(l -> l).min().orElseThrow(); 39 | } 40 | 41 | public static void main(String[] args) { 42 | var input = """ 43 | seeds: 79 14 55 13 44 | 45 | seed-to-soil map: 46 | 50 98 2 47 | 52 50 48 48 | 49 | soil-to-fertilizer map: 50 | 0 15 37 51 | 37 52 2 52 | 39 0 15 53 | 54 | fertilizer-to-water map: 55 | 49 53 8 56 | 0 11 42 57 | 42 0 7 58 | 57 7 4 59 | 60 | water-to-light map: 61 | 88 18 7 62 | 18 25 70 63 | 64 | light-to-temperature map: 65 | 45 77 23 66 | 81 45 19 67 | 68 64 13 68 | 69 | temperature-to-humidity map: 70 | 0 69 1 71 | 1 0 69 72 | 73 | humidity-to-location map: 74 | 60 56 37 75 | 56 93 4 76 | """; 77 | System.out.println(lowestLocationNumber(input)); 78 | } 79 | } 80 | 81 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode22.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.HashMap; 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.Map.Entry; 6 | import java.util.Set; 7 | import java.util.TreeMap; 8 | import java.util.stream.Collectors; 9 | import java.util.stream.Gatherer; 10 | import java.util.stream.Stream; 11 | 12 | import static java.util.stream.Collectors.filtering; 13 | import static java.util.stream.Collectors.flatMapping; 14 | import static java.util.stream.Collectors.groupingBy; 15 | import static java.util.stream.Collectors.mapping; 16 | import static java.util.stream.Collectors.teeing; 17 | import static java.util.stream.Collectors.toList; 18 | import static java.util.stream.Collectors.toMap; 19 | import static java.util.stream.Collectors.toSet; 20 | import static java.util.stream.IntStream.rangeClosed; 21 | 22 | public class AdventOfCode22 { 23 | record Pos(int x, int y) {} 24 | record Brick(int x1, int x2, int y1, int y2, int z1, int z2) { 25 | Stream positions() { 26 | return x1 == x2 ? rangeClosed(y1, y2).mapToObj(y -> new Pos(x1, y)) : 27 | rangeClosed(x1, x2).mapToObj(x -> new Pos(x, y1)); 28 | } 29 | } 30 | record Level(Brick brick, int z) {} 31 | record Pair(U u, V v) { } 32 | 33 | static int numberOfBrickWithChildrenWithAtLeastTwoParents(String input) { 34 | var grid = new HashMap(); 35 | return input.lines() 36 | .map(l -> { 37 | var array = Arrays.stream(l.split(",|~")).mapToInt(Integer::parseInt).toArray(); 38 | return new Brick(array[0], array[3], array[1], array[4], array[2], array[5]); 39 | }) 40 | .collect(groupingBy(Brick::z1, TreeMap::new, toList())) 41 | .values().stream() 42 | .flatMap(List::stream) 43 | .map(brick -> { 44 | var onTop = brick.positions() 45 | .map(pos -> grid.getOrDefault(pos, new Level(null, 0))) 46 | .collect(groupingBy(Level::z, TreeMap::new, flatMapping(l -> Stream.ofNullable(l.brick), toSet()))) 47 | .lastEntry(); 48 | var level = new Level(brick, 1 + brick.z2 - brick.z1 + onTop.getKey()); 49 | brick.positions().forEach(pos -> grid.put(pos, level)); 50 | return new Pair<>(brick, onTop.getValue()); 51 | }) 52 | .collect(teeing( 53 | toMap(Pair::u, pair -> pair.v().size()), 54 | flatMapping(pair -> pair.v().stream().map(b -> new Pair<>(b, pair.u())), 55 | groupingBy(Pair::u, mapping(Pair::v, toList()))), 56 | (parentMap, childrenMap) -> 57 | (int) parentMap.keySet().stream() 58 | .filter(parent -> childrenMap.getOrDefault(parent, List.of()).stream() 59 | .allMatch(child -> parentMap.get(child) > 1)) 60 | .count() 61 | )); 62 | } 63 | 64 | public static void main(String[] args) { 65 | var input = """ 66 | 1,0,1~1,2,1 67 | 0,0,2~2,0,2 68 | 0,2,3~2,2,3 69 | 0,0,4~0,2,4 70 | 2,0,5~2,2,5 71 | 0,1,6~2,1,6 72 | 1,1,8~1,1,9 73 | """; 74 | System.out.println(numberOfBrickWithChildrenWithAtLeastTwoParents(input)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # advent-of-code-2023 2 | Let's try to do the advent of code 2023 in Java 21 3 | 4 | It's not the first time I tried to do an advent of code, but I never completed one, so this year in order to ty to complete it, 5 | I will only do the first part of each challenge in hope it wil not take too much time. 6 | 7 | Each puzzle is contained in one file, by example for the day 1, you can just run 8 | ```bash 9 | java src/main/java/AdventOfCode01.java 10 | ``` 11 | 12 | - [Day 1](https://adventofcode.com/2023/day/1) [AdventOfCode01.java](src/main/java/AdventOfCode01.java) 13 | - [Day 2](https://adventofcode.com/2023/day/2) [AdventOfCode02.java](src/main/java/AdventOfCode02.java) 14 | - [Day 3](https://adventofcode.com/2023/day/3) [AdventOfCode03.java](src/main/java/AdventOfCode03.java) 15 | - [Day 4](https://adventofcode.com/2023/day/4) [AdventOfCode04.java](src/main/java/AdventOfCode04.java) 16 | - [Day 5](https://adventofcode.com/2023/day/5) [AdventOfCode05.java](src/main/java/AdventOfCode05.java) 17 | - [Day 6](https://adventofcode.com/2023/day/6) [AdventOfCode06.java](src/main/java/AdventOfCode06.java) 18 | - [Day 7](https://adventofcode.com/2023/day/7) [AdventOfCode07.java](src/main/java/AdventOfCode07.java) 19 | - [Day 8](https://adventofcode.com/2023/day/8) [AdventOfCode08.java](src/main/java/AdventOfCode08.java) 20 | - [Day 9](https://adventofcode.com/2023/day/9) [AdventOfCode09.java](src/main/java/AdventOfCode09.java) 21 | - [Day 10](https://adventofcode.com/2023/day/10) [AdventOfCode10.java](src/main/java/AdventOfCode10.java) 22 | - [Day 11](https://adventofcode.com/2023/day/11) [AdventOfCode11.java](src/main/java/AdventOfCode11.java) 23 | - [Day 12](https://adventofcode.com/2023/day/12) [AdventOfCode12.java](src/main/java/AdventOfCode12.java) 24 | - [Day 13](https://adventofcode.com/2023/day/13) [AdventOfCode13.java](src/main/java/AdventOfCode13.java) 25 | - [Day 14](https://adventofcode.com/2023/day/14) [AdventOfCode14.java](src/main/java/AdventOfCode14.java) 26 | - [Day 15](https://adventofcode.com/2023/day/15) [AdventOfCode15.java](src/main/java/AdventOfCode15.java) 27 | - [Day 16](https://adventofcode.com/2023/day/16) [AdventOfCode16.java](src/main/java/AdventOfCode16.java) 28 | - [Day 17](https://adventofcode.com/2023/day/17) [AdventOfCode17.java](src/main/java/AdventOfCode17.java) 29 | - [Day 18](https://adventofcode.com/2023/day/18) [AdventOfCode18.java](src/main/java/AdventOfCode18.java) 30 | - [Day 19](https://adventofcode.com/2023/day/19) [AdventOfCode19.java](src/main/java/AdventOfCode19.java) 31 | - [Day 20](https://adventofcode.com/2023/day/20) [AdventOfCode20.java](src/main/java/AdventOfCode20.java) 32 | - [Day 21](https://adventofcode.com/2023/day/21) [AdventOfCode21.java](src/main/java/AdventOfCode21.java) 33 | - [Day 22](https://adventofcode.com/2023/day/22) [AdventOfCode22.java](src/main/java/AdventOfCode22.java) 34 | - [Day 23](https://adventofcode.com/2023/day/23) [AdventOfCode23.java](src/main/java/AdventOfCode23.java) 35 | - [Day 24](https://adventofcode.com/2023/day/24) [AdventOfCode24.java](src/main/java/AdventOfCode24.java) 36 | - [Day 25](https://adventofcode.com/2023/day/25) [AdventOfCode25.java](src/main/java/AdventOfCode25.java) 37 | 38 | Each code will be published the day after. 39 | 40 | Enjoy 41 | 42 | -------------------------------------------------------------------------------- /src/main/java/AdventOfCode20.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | import java.util.BitSet; 3 | import java.util.Deque; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | import static java.util.stream.Collectors.toMap; 9 | import static java.util.stream.IntStream.range; 10 | 11 | public class AdventOfCode20 { 12 | enum Pulse { LOW, HIGH } 13 | record Event(String source, Pulse pulse, String dest) {} 14 | static final class State { int index; } 15 | enum EntityKind { BROADCASTER, FLIP_FLOP, CONJUNCTION, OUTPUT } 16 | record Entity(String name, EntityKind kind, Map ins, List outs, State state) { 17 | void send(Deque queue, Pulse pulse) { 18 | outs.forEach(o -> queue.offer(new Event(name, pulse, o))); 19 | } 20 | } 21 | record Counter(int low, int high) { 22 | Counter add(Counter c) { return new Counter(low + c.low, high + c.high); } 23 | } 24 | 25 | static Counter execute(Map map, BitSet states) { 26 | int low = 0, high = 0; 27 | var queue = new ArrayDeque(); 28 | queue.add(new Event("button", Pulse.LOW, "broadcaster")); 29 | while(!queue.isEmpty()) { 30 | var event = queue.poll(); 31 | if (event.pulse == Pulse.LOW) { low++; } else { high++; } 32 | var entity = map.get(event.dest); 33 | switch (entity.kind) { 34 | case BROADCASTER -> entity.send(queue, event.pulse); 35 | case FLIP_FLOP -> { 36 | if (event.pulse == Pulse.LOW) { 37 | var state = states.get(entity.state.index); 38 | states.set(entity.state.index, !state); 39 | entity.send(queue, state ? Pulse.LOW : Pulse.HIGH); 40 | } 41 | } 42 | case CONJUNCTION -> { 43 | states.set(entity.state.index + entity.ins.get(event.source), event.pulse == Pulse.HIGH); 44 | var allHigh = range(0, entity.ins.size()).allMatch(i -> states.get(entity.state.index + i)); 45 | entity.send(queue, allHigh ? Pulse.LOW : Pulse.HIGH); 46 | } 47 | } 48 | } 49 | return new Counter(low, high); 50 | } 51 | 52 | static Counter steps(String input, int times) { 53 | var map = input.lines() 54 | .map(line -> { 55 | var parts = line.split("->"); 56 | var name = parts[0].substring(1).strip(); 57 | var outputs = List.of(parts[1].strip().split(", ")); 58 | var kind = switch (parts[0].charAt(0)) { 59 | case '%' -> EntityKind.FLIP_FLOP; 60 | case '&' -> EntityKind.CONJUNCTION; 61 | default -> { name = "broadcaster"; yield EntityKind.BROADCASTER; } 62 | }; 63 | return new Entity(name, kind, new HashMap<>(), outputs, new State()); 64 | }) 65 | .collect(toMap(Entity::name, e -> e)); 66 | map.put("output", new Entity("output", EntityKind.OUTPUT, new HashMap<>(), List.of(), null)); 67 | map.values().forEach(e -> e.outs.stream().map(o -> map.get(o).ins).forEach(ins -> ins.put(e.name, ins.size()))); 68 | var stateCount = 0; 69 | for(var e : map.values()) { 70 | switch (e.kind) { 71 | case FLIP_FLOP -> e.state.index = stateCount++; 72 | case CONJUNCTION -> { e.state.index = stateCount; stateCount += e.ins.size(); } 73 | } 74 | } 75 | var set = new BitSet(stateCount); 76 | return range(0, times).mapToObj(__ -> execute(map, set)).reduce(new Counter(0, 0), Counter::add); 77 | } 78 | 79 | public static void main(String[] args) { 80 | var input = """ 81 | broadcaster -> a, b, c 82 | %a -> b 83 | %b -> c 84 | %c -> inv 85 | &inv -> a 86 | """; 87 | System.out.println(steps(input, 1_000)); 88 | 89 | var input2 = """ 90 | broadcaster -> a 91 | %a -> inv, con 92 | &inv -> b 93 | %b -> con 94 | &con -> output 95 | """; 96 | System.out.println(steps(input2, 1_000)); 97 | } 98 | } 99 | --------------------------------------------------------------------------------