Skip to content

Commit

Permalink
AoC 2023 Day 7 - java
Browse files Browse the repository at this point in the history
  • Loading branch information
pareronia committed Dec 9, 2023
1 parent c91f9c6 commit 6b9777e
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
| ---| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| python3 | [](src/main/python/AoC2023_01.py) | [](src/main/python/AoC2023_02.py) | [](src/main/python/AoC2023_03.py) | [](src/main/python/AoC2023_04.py) | [](src/main/python/AoC2023_05.py) | [](src/main/python/AoC2023_06.py) | [](src/main/python/AoC2023_07.py) | [](src/main/python/AoC2023_08.py) | [](src/main/python/AoC2023_09.py) | | | | | | | | | | | | | | | | |
| java | [](src/main/java/AoC2023_01.java) | [](src/main/java/AoC2023_02.java) | [](src/main/java/AoC2023_03.java) | [](src/main/java/AoC2023_04.java) | | [](src/main/java/AoC2023_06.java) | | [](src/main/java/AoC2023_08.java) | [](src/main/java/AoC2023_09.java) | | | | | | | | | | | | | | | | |
| java | [](src/main/java/AoC2023_01.java) | [](src/main/java/AoC2023_02.java) | [](src/main/java/AoC2023_03.java) | [](src/main/java/AoC2023_04.java) | | [](src/main/java/AoC2023_06.java) | [](src/main/java/AoC2023_07.java) | [](src/main/java/AoC2023_08.java) | [](src/main/java/AoC2023_09.java) | | | | | | | | | | | | | | | | |
| bash | | | | | | | | | | | | | | | | | | | | | | | | | |
| c++ | | | | | | | | | | | | | | | | | | | | | | | | | |
| julia | | | | | | | | | | | | | | | | | | | | | | | | | |
Expand Down
119 changes: 119 additions & 0 deletions src/main/java/AoC2023_07.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import static com.github.pareronia.aoc.IterTools.enumerateFrom;
import static com.github.pareronia.aoc.Utils.toAString;
import static java.util.Comparator.comparing;

import java.util.Comparator;
import java.util.List;
import java.util.function.Function;

import com.github.pareronia.aoc.Counter;
import com.github.pareronia.aoc.StringOps;
import com.github.pareronia.aoc.StringOps.StringSplit;
import com.github.pareronia.aoc.Utils;
import com.github.pareronia.aoc.solution.Sample;
import com.github.pareronia.aoc.solution.Samples;
import com.github.pareronia.aoc.solution.SolutionBase;

public final class AoC2023_07
extends SolutionBase<List<AoC2023_07.Hand>, Integer, Integer> {

private AoC2023_07(final boolean debug) {
super(debug);
}

public static AoC2023_07 create() {
return new AoC2023_07(false);
}

public static AoC2023_07 createDebug() {
return new AoC2023_07(true);
}

@Override
protected List<Hand> parseInput(final List<String> inputs) {
return inputs.stream().map(Hand::fromInput).toList();
}

private int solve(final List<Hand> hands, final Comparator<Hand> order) {
return enumerateFrom(1, hands.stream().sorted(order))
.mapToInt(e -> e.index() * e.value().bid())
.sum();
}

@Override
public Integer solvePart1(final List<Hand> hands) {
return solve(hands, Hand.comparator());
}

@Override
public Integer solvePart2(final List<Hand> hands) {
return solve(hands, Hand.comparatorWithJokers());
}

@Override
@Samples({
@Sample(method = "part1", input = TEST, expected = "6440"),
@Sample(method = "part2", input = TEST, expected = "5905"),
})
public void samples() {
}

public static void main(final String[] args) throws Exception {
AoC2023_07.create().run();
}

record Hand(
int bid,
int value,
String strength,
int valueWithJokers,
String strengthWithJokers
) {
private static final Character JOKER = 'J';
private static final String BEST = "AAAAA";

public static Hand fromInput(final String line) {
final Function<String, Integer> getValue = cards -> {
final List<Counter.Entry<Character>> mc
= new Counter<>(Utils.asCharacterStream(cards).toList()).mostCommon();
return (int) (2 * mc.get(0).count() + (mc.size() > 1 ? mc.get(1).count() : 0));
};
final Function<String, String> withJokers = cards -> {
final Counter<Character> c = new Counter<>(
Utils.asCharacterStream(cards).filter(ch -> ch != JOKER).toList());
if (c.isEmpty()) {
return BEST;
}
final Character best = c.mostCommon().get(0).value();
return Utils.asCharacterStream(cards)
.map(ch -> ch == JOKER ? best : ch)
.collect(toAString());
};

final StringSplit split = StringOps.splitOnce(line, " ");
final int bid = Integer.parseInt(split.right());
final int value = getValue.apply(split.left());
final String strength = StringOps.translate(split.left(), "TJQKA", "BCDEF");
final int valueWithJokers = getValue.apply(withJokers.apply(split.left()));
final String strengthWithJokers = StringOps.translate(split.left(), "TJQKA", "B0DEF");
return new Hand(bid, value, strength, valueWithJokers, strengthWithJokers);
}

public static Comparator<Hand> comparator() {
return comparing(Hand::value).thenComparing(comparing(Hand::strength));
}

public static Comparator<Hand> comparatorWithJokers() {
return comparing(Hand::valueWithJokers)
.thenComparing(comparing(Hand::strengthWithJokers));
}
}

private static final String TEST = """
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483
""";
}
30 changes: 30 additions & 0 deletions src/main/java/com/github/pareronia/aoc/Counter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.github.pareronia.aoc;

import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;

import java.util.List;
import java.util.Map;

public class Counter<T> {

private final Map<T, Long> counts;

public Counter(final Iterable<T> iterable) {
this.counts = Utils.stream(iterable.iterator())
.collect(groupingBy(o -> o, counting()));
}

public boolean isEmpty() {
return this.counts.isEmpty();
}

public List<Entry<T>> mostCommon() {
return this.counts.entrySet().stream()
.sorted((e1, e2) -> Long.compare(e2.getValue(), e1.getValue()))
.map(e -> new Entry<T>(e.getKey(), e.getValue()))
.toList();
}

public record Entry<T>(T value, long count) {}
}
28 changes: 24 additions & 4 deletions src/main/java/com/github/pareronia/aoc/StringOps.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,25 @@ public static List<String> splitLines(final String input) {
return asList((Objects.requireNonNull(input) + "\n").split("\\r?\\n"));
}

public record StringSplit(String left, String right) {}

public static StringSplit splitOnce(final String string, final String regex) {
final String[] splits = Objects.requireNonNull(string).split(regex);
return new StringSplit(splits[0], splits[1]);
}

public static List<List<String>> toBlocks(final List<String> inputs) {
if (inputs.isEmpty()) {
return Collections.emptyList();
}
final List<List<String>> blocks = new ArrayList<>();
int i = 0;
final int last = inputs.size() - 1;
blocks.add(new ArrayList<String>());
blocks.add(new ArrayList<>());
for (int j = 0; j <= last; j++) {
if (inputs.get(j).isEmpty()) {
if (j != last) {
blocks.add(new ArrayList<String>());
blocks.add(new ArrayList<>());
i++;
}
} else {
Expand Down Expand Up @@ -77,14 +84,14 @@ public static char[] move(final char[] ch, final int from, final int to) {
assertTrue(from != to, () -> "Expected from and to to be different");
if (from < to) {
final char[] ch1 = subarray(ch, 0, from);
final char[] ch2 = new char[] { ch[from] };
final char[] ch2 = { ch[from] };
final char[] ch3 = subarray(ch, from + 1, to + 1);
final char[] ch4 = subarray(ch, to + 1, ch.length);
return addAll(ch1, addAll(ch3, addAll(ch2, ch4)));
} else {
final char[] ch1 = subarray(ch, 0, to);
final char[] ch2 = subarray(ch, to, from);
final char[] ch3 = new char[] { ch[from] };
final char[] ch3 = { ch[from] };
final char[] ch4 = subarray(ch, from + 1, ch.length);
return addAll(ch1, addAll(ch3, addAll(ch2, ch4)));
}
Expand Down Expand Up @@ -127,4 +134,17 @@ public static char nextLetter(final char c, final int shift) {
throw new IllegalArgumentException("Expected alphabetic char");
}
}

public static String translate(final String string, final String from, final String to) {
AssertUtils.assertTrue(
Objects.requireNonNull(from).length() == Objects.requireNonNull(to).length(),
() -> "from and to should be same length");
final char[] tmp = new char[string.length()];
for (int i = 0; i < string.length(); i++) {
final char ch = string.charAt(i);
final int idx = from.indexOf(ch);
tmp[i] = idx < 0 ? ch : to.charAt(idx);
}
return new String(tmp);
}
}

0 comments on commit 6b9777e

Please sign in to comment.