Advent of Code 2023: Day 2: Cube Conundrum

Страшный, длинный, мучительный парсинг ввода…
Хотелось бы, конечно, иметь возможность сделать по-перловому, что-то типа: echo -e "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green\nGame 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue" | perl -wlne '@matches = $_ =~ /(?:\G(?!\A)|^Game) (\S+)/g; print join("=",@matches)'.

Немного почистить после, или сразу докрутить регулярку, чтобы не захватывала разделители. Сложить в хэш. И закончить кучей циклов в итоге 🙁

С другой стороны – и возня с java Matcher не вдохновляла, и описывать структуру в виде POJO – для чисто скриптового решения – зачем.

split – дёшево и сердито, fastpath бонусом. К счастью – ввод был одинаков для обеих частей загадки.

// Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
static void day2(String puzzleInputUri) throws IOException, InterruptedException {
    Map<String, Integer> bagOfCubes = Map.of("red", 12, "green", 13, "blue", 14);
    var games = client.send(request.uri((URI.create(puzzleInputUri))).build(),
                    HttpResponse.BodyHandlers.ofLines()).body()
            .map(game -> game.split(":", 2))
            .map(idAndResults -> Map.entry(
                    idAndResults[0].split(" ", 2)[1], // game id
                    idAndResults[1] // results string
            ))
            .map(idAndResults -> Map.entry(idAndResults.getKey(), idAndResults.getValue().split(";")))
            .map(idAndResults -> {
                List<Map<String, Integer>> parsedResults = new ArrayList<>();
                for (String s : idAndResults.getValue()) {
                    Map<String, Integer> cubesCount = new HashMap<>();
                    for (String s1 : s.split(",")) {
                        String[] cubeCount = s1.trim().split(" ", 2);
                        cubesCount.put(cubeCount[1].trim(), Integer.parseInt(cubeCount[0].trim()));
                    }
                    parsedResults.add(cubesCount);
                }
                return Map.entry(idAndResults.getKey(), parsedResults);
            })
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

    var answer1 = games.entrySet().stream()
            .filter(idAndResults -> idAndResults.getValue().stream()
                .flatMap(it -> it.entrySet().stream())
                .noneMatch(result -> result.getValue() > bagOfCubes.get(result.getKey()))
            )
            .mapToInt(idAndResults -> Integer.parseInt(idAndResults.getKey()))
            .sum();

    var answer2 = games.entrySet().stream()
            .map(idAndResults -> Map.entry(
                idAndResults.getKey(),
                idAndResults.getValue().stream()
                    .reduce((m1, m2) -> {
                        Map<String, Integer> minRequired = new HashMap<>();
                        bagOfCubes.keySet().forEach(cube -> minRequired.put(cube,
                            Math.max(m1.getOrDefault(cube, 0),
                                    m2.getOrDefault(cube, 0))
                        ));
                        return minRequired;
                    }).orElseThrow()
                )
            )
            .mapToInt(idAndMinRequired -> idAndMinRequired.getValue().values().stream()
                    .reduce((v1, v2) -> v1 * v2).orElseThrow() // v != 0 ? v : 1
            )
            .sum();

    System.out.println(answer1);
    System.out.println(answer2);
}

Вид этой портянки мне не особо мил, особенно for внутри (mapMulti взамен?). Но и как-то значимо “облагородить” её не удалось с ходу – получалась куча менее понятных map, происходящее в которых сложно осознать уже через пару десятков минут.
А часики тикают, задачи требуют решений – и пора двигаться дальше!

https://adventofcode.com/2023/day/2