Страшный, длинный, мучительный парсинг ввода…
Хотелось бы, конечно, иметь возможность сделать по-перловому, что-то типа: 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