package de.szimnau; import de.szimnau.tools.CommonTools; import de.szimnau.tools.FormatTools; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; import java.nio.charset.StandardCharsets; import java.text.DecimalFormat; import java.time.LocalTime; import java.time.temporal.ChronoUnit; import static de.szimnau.tools.CommonTools.print; public class DrinkingBar extends AbstractLoadingBar { private static final int MINS_PER_HALF_HOUR = CommonTools.MINS_PER_HOUR / 2; private static final int MINUTES_BEFORE_PAUSE = 4 * CommonTools.MINS_PER_HOUR + MINS_PER_HALF_HOUR; private static final int MINUTES_WITH_PAUSE = 6 * CommonTools.MINS_PER_HOUR; private static final int DEFAULT_TOTAL_TIME = 8 * CommonTools.MINS_PER_HOUR + MINS_PER_HALF_HOUR; private static final BigDecimal DEFAULT_TOTAL_TIME_BD = BigDecimal.valueOf(DEFAULT_TOTAL_TIME); private static final BigDecimal DEFAULT_TOTAL_LITRES = BigDecimal.valueOf(2.0); private static final BigDecimal QUARTER_LITRE = BigDecimal.valueOf(0.25); private static final DecimalFormat LITRE_FORMAT = new DecimalFormat("0.00"); private BigDecimal totalLitres; public static void main(String[] args) throws IOException { var br = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8)); print("Ankunftszeit: "); var startTime = LocalTime.parse(br.readLine(), FormatTools.TIME_FORMATTER).truncatedTo(ChronoUnit.MINUTES); var db = new DrinkingBar(startTime); db.showLoadingBar(); } protected DrinkingBar(LocalTime startTime) { super(startTime, DEFAULT_TOTAL_TIME); this.totalLitres = DEFAULT_TOTAL_LITRES; } @Override protected void extraInitEndTimeTotalMinutes() { // correct necessary litres to drink based on the end time. // lower the volume in quarter litre steps BigDecimal calcTotalLitres = DEFAULT_TOTAL_LITRES; BigDecimal totalLitresFromMinutes = DEFAULT_TOTAL_LITRES .multiply(getTotalMinutesBD()) // reverse dreisatz .divide(DEFAULT_TOTAL_TIME_BD, MathContext.DECIMAL64); do { calcTotalLitres = calcTotalLitres.subtract(QUARTER_LITRE); } while (calcTotalLitres.compareTo(totalLitresFromMinutes) >= 0); // add quarter since we always did a step "too many", due to the do ... while loop this.totalLitres = calcTotalLitres.add(QUARTER_LITRE); } @Override protected String fillLoadingBar(long passedMinutes, boolean progressive) { long effectivePassedMinutes = passedMinutes < 0 ? 0 : passedMinutes; if (getTotalMinutes() > MINUTES_WITH_PAUSE && passedMinutes > MINUTES_BEFORE_PAUSE && passedMinutes <= MINUTES_WITH_PAUSE) { effectivePassedMinutes = MINUTES_BEFORE_PAUSE; } var effectivePassedMinutesBD = BigDecimal.valueOf(effectivePassedMinutes); BigDecimal currentLitres = totalLitres .multiply(effectivePassedMinutesBD) // reverse dreisatz .divide(getTotalMinutesBD(), MathContext.DECIMAL64) .add(QUARTER_LITRE); BigDecimal printedLitres = currentLitres.subtract(currentLitres.remainder(QUARTER_LITRE, MathContext.DECIMAL64)); /* BigDecimal currentProgressToNextStep = ONE_HUNDRED_PERCENT .multiply(currentLitres.subtract(printedLitres)) // reverse dreisatz .divide(QUARTER_LITRE, MathContext.DECIMAL64); */ BigDecimal minutesToNextStep = getMinutesToNextStep(currentLitres); String progressivePart = progressive ? "\r" : ""; return progressivePart + "Aktuelles Volumen: " + LITRE_FORMAT.format(printedLitres) + "L - " // + FormatTools.PERCENTAGE_FORMAT.format(currentProgressToNextStep) + "% - " + FormatTools.minutesToTimeString(minutesToNextStep); } private BigDecimal getMinutesToNextStep(BigDecimal currentLitres) { // berechne Liter benötigt bis zum nächsten 0.25er Schritt BigDecimal litresToNextStep = QUARTER_LITRE.subtract(currentLitres.remainder(QUARTER_LITRE)); // berechne Minuten benötigt für 1 Liter BigDecimal minutesPerLitre = getTotalMinutesBD().divide(totalLitres, MathContext.DECIMAL64); // berechne Minuten benötigt bis zum nächsten 0.25er Schritt return minutesPerLitre.multiply(litresToNextStep).setScale(0, RoundingMode.HALF_EVEN); } }