package dev.forstenlechner.aoc; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.stream.IntStream; import java.util.stream.Stream; import static java.util.stream.Collectors.toList; public class Day13 { record EarliestBus(long earliest, long bus) {} record BusWithOffset(long bus, long offset) {} record BusAsStringWithOffset(String bus, long offset) {} public static void main(String[] args) throws Exception { new Day13().solve(); } private void solve() throws Exception { List lines = Files.lines(Paths.get("day13/input")).collect(toList()); part1(lines); part2(lines.get(1)); part2FromFusch(lines.get(1)); } private void part2(String busLine) { String[] busses = busLine.split(","); List busWithOffsets = IntStream.range(0, busses.length) .mapToObj(offset -> new BusAsStringWithOffset(busses[offset], offset)) .filter(bus -> !bus.bus().equals("x")) .map(bus -> new BusWithOffset(Long.parseLong(bus.bus()), bus.offset())) .collect(toList()); busWithOffsets.forEach(System.out::println); long bus23 = 23; long minBusProduct = bus23 * 647 * 19 * 29 * 37; long count = 1; while (true) { if (count % 1000 == 0) { System.out.println(count); } long possibleT = minBusProduct * count - bus23; if (busWithOffsets.stream().allMatch(bus -> ((possibleT + bus.offset()) % bus.bus()) == 0)) { System.out.println(possibleT); break; } count++; } System.out.println(count); } private void part2FromFusch(String busLine) { List busWithOffsets = getBussesWithOffset(busLine); long count = 1; long currentNumber = 1; long stepWidth = 1; for (BusWithOffset busWithOffset : busWithOffsets) { while ((currentNumber + busWithOffset.offset) % busWithOffset.bus != 0) { currentNumber += stepWidth; count++; } // Found the number that fulfills the requirement. // Adapt step width, so all further steps also fulfill this requirement // KGV shouldn't be necessary, because input is all primes stepWidth *= busWithOffset.bus; } System.out.println(count); System.out.println(currentNumber); } private List getBussesWithOffset(String busLine) { String[] busses = busLine.split(","); return IntStream.range(0, busses.length) .mapToObj(offset -> new BusAsStringWithOffset(busses[offset], offset)) .filter(bus -> !bus.bus().equals("x")) .map(bus -> new BusWithOffset(Long.parseLong(bus.bus()), bus.offset())) .collect(toList()); } private void part1(List lines) { long earliestDeparture = Long.parseLong(lines.get(0)); Stream busTimes = Arrays.stream(lines.get(1).split(",")).filter(x -> !x.equals("x")).map(Long::parseLong); EarliestBus earliestBus = busTimes.map(t -> earliestDepartureForBus(earliestDeparture, t)).min(Comparator.comparing(EarliestBus::earliest)).orElseThrow(); System.out.println(earliestBus.bus() * (earliestBus.earliest() - earliestDeparture)); } private EarliestBus earliestDepartureForBus(long earliestDeparture, long bus) { if (earliestDeparture % bus == 0) { return new EarliestBus(earliestDeparture, bus); } return new EarliestBus((earliestDeparture / bus + 1) * bus, bus); } }