-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
278 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
/* | ||
* BSD Zero Clause License | ||
* | ||
* Copyright (c) 2021-2023 zodac.me | ||
* | ||
* Permission to use, copy, modify, and/or distribute this software for any | ||
* purpose with or without fee is hereby granted. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR | ||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
*/ | ||
|
||
package me.zodac.advent; | ||
|
||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import me.zodac.advent.pojo.ScratchCard; | ||
|
||
/** | ||
* Solution for 2023, Day 4. | ||
* | ||
* @see <a href="https://adventofcode.com/2023/day/4">[2023: 04] Scratchcards</a> | ||
*/ | ||
public final class Day04 { | ||
|
||
private static final int DEFAULT_NUMBER_OF_COPIES = 0; | ||
|
||
private Day04() { | ||
|
||
} | ||
|
||
/** | ||
* Given a {@link Collection} of {@link ScratchCard}s, we calculate the points for each {@link ScratchCard}, then sum them. | ||
* | ||
* @param scratchCards the input {@link ScratchCard}s | ||
* @return the sum of points for all {@link ScratchCard}s | ||
*/ | ||
public static long totalPointsForScratchCards(final Collection<ScratchCard> scratchCards) { | ||
return scratchCards | ||
.stream() | ||
.mapToLong(ScratchCard::calculatePoints) | ||
.sum(); | ||
} | ||
|
||
/** | ||
* Given a {@link Collection} of {@link ScratchCard}s, each winning digit in a {@link ScratchCard} provides a copy of the next <i>n</i> | ||
* {@link ScratchCard}s. The number of copies (and original {@link ScratchCard}s) are added up and returned. | ||
* | ||
* @param scratchCards the input {@link ScratchCard}s | ||
* @return the total number of {@link ScratchCard}s, including copies | ||
*/ | ||
public static long countTotalNumberOfScratchCards(final Collection<ScratchCard> scratchCards) { | ||
final Map<Integer, Integer> copiesById = new HashMap<>(); | ||
long numberOfCopies = 0L; | ||
|
||
for (final ScratchCard scratchCard : scratchCards) { | ||
final int id = scratchCard.id(); | ||
final int numberOfTimesToExecute = copiesById.getOrDefault(id, DEFAULT_NUMBER_OF_COPIES) + 1; | ||
|
||
final int currentCopiesForId = copiesById.getOrDefault(id, DEFAULT_NUMBER_OF_COPIES); | ||
copiesById.put(id, currentCopiesForId + 1); | ||
|
||
if (scratchCard.winners().isEmpty()) { | ||
continue; | ||
} | ||
|
||
for (int i = 1; i <= scratchCard.winners().size(); i++) { | ||
numberOfCopies += numberOfTimesToExecute; | ||
final int currentCopiesForNextId = copiesById.getOrDefault(id + i, DEFAULT_NUMBER_OF_COPIES); | ||
copiesById.put(id + i, currentCopiesForNextId + numberOfTimesToExecute); | ||
} | ||
} | ||
|
||
return scratchCards.size() + numberOfCopies; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* BSD Zero Clause License | ||
* | ||
* Copyright (c) 2021-2023 zodac.me | ||
* | ||
* Permission to use, copy, modify, and/or distribute this software for any | ||
* purpose with or without fee is hereby granted. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR | ||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
*/ | ||
|
||
package me.zodac.advent.pojo; | ||
|
||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import me.zodac.advent.util.CollectionUtils; | ||
import me.zodac.advent.util.StringUtils; | ||
|
||
/** | ||
* Record defining a scratchcard. The scratchcard will contain valid winning digits and the drawn digits, and we will look for any drawn winners. | ||
* | ||
* @param id the ID of the {@link ScratchCard} | ||
* @param winners the drawn digits that were winners | ||
*/ | ||
public record ScratchCard(int id, Set<Integer> winners) { | ||
|
||
private static final Pattern VALID_SCRATCHCARD = Pattern.compile("Card\\s+(?<id>\\d+):\\s+(?<winners>(\\d+\\s+)*)\\|(?<drawn>(\\s+\\d+)*)"); | ||
|
||
/** | ||
* Creates a {@link ScratchCard} from a {@link CharSequence} in the format: | ||
* <pre> | ||
* Card [id]: [winning digits, space separated] | [drawn digits, space separated] | ||
* </pre> | ||
* | ||
* @param input the {@link CharSequence} to parse | ||
* @return the {@link ScratchCard} | ||
* @throws IllegalArgumentException thrown if the input does not match the expected format | ||
*/ | ||
public static ScratchCard parse(final CharSequence input) { | ||
final Matcher matcher = VALID_SCRATCHCARD.matcher(input); | ||
if (!matcher.matches()) { | ||
throw new IllegalArgumentException(String.format("Invalid input: '%s'", input)); | ||
} | ||
|
||
final int id = Integer.parseInt(matcher.group("id")); | ||
final List<Integer> winningDigits = StringUtils.collectIntegersInOrder(matcher.group("winners")); | ||
final List<Integer> drawnDigits = StringUtils.collectIntegersInOrder(matcher.group("drawn")); | ||
return new ScratchCard(id, CollectionUtils.intersection(new HashSet<>(winningDigits), drawnDigits)); | ||
} | ||
|
||
/** | ||
* Calculates the points for the {@link ScratchCard}. The first winning digit for the {@link ScratchCard} is worth <b>1</b> point, and the points | ||
* double for each subsequent winning digit. This can be simplified to: | ||
* <pre> | ||
* 2 ^ (numberOfWinners - 1) | ||
* </pre> | ||
* | ||
* <p> | ||
* If there were no winning digits, <b>0</b> is returned. | ||
* | ||
* @return the points for the {@link ScratchCard} | ||
*/ | ||
public long calculatePoints() { | ||
return winners.isEmpty() ? 0L : (long) StrictMath.pow(2, winners().size() - 1); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* | ||
* BSD Zero Clause License | ||
* | ||
* Copyright (c) 2021-2023 zodac.me | ||
* | ||
* Permission to use, copy, modify, and/or distribute this software for any | ||
* purpose with or without fee is hereby granted. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | ||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR | ||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
*/ | ||
|
||
package me.zodac.advent; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
import java.util.List; | ||
import me.zodac.advent.input.ExampleInput; | ||
import me.zodac.advent.input.PuzzleInput; | ||
import me.zodac.advent.pojo.ScratchCard; | ||
import org.junit.jupiter.api.Test; | ||
|
||
/** | ||
* Tests to verify answers for {@link Day04}. | ||
*/ | ||
public class Day04Test { | ||
|
||
private static final String INPUT_FILENAME = "day04.txt"; | ||
|
||
@Test | ||
void example() { | ||
final List<ScratchCard> values = ExampleInput.readLines(INPUT_FILENAME) | ||
.stream() | ||
.map(ScratchCard::parse) | ||
.toList(); | ||
|
||
final long part1Result = Day04.totalPointsForScratchCards(values); | ||
assertThat(part1Result) | ||
.isEqualTo(13L); | ||
|
||
final long part2Result = Day04.countTotalNumberOfScratchCards(values); | ||
assertThat(part2Result) | ||
.isEqualTo(30L); | ||
} | ||
|
||
@Test | ||
void part1() { | ||
final List<ScratchCard> values = PuzzleInput.readLines(INPUT_FILENAME) | ||
.stream() | ||
.map(ScratchCard::parse) | ||
.toList(); | ||
|
||
final long part1Result = Day04.totalPointsForScratchCards(values); | ||
assertThat(part1Result) | ||
.isEqualTo(18_519L); | ||
} | ||
|
||
@Test | ||
void part2() { | ||
final List<ScratchCard> values = PuzzleInput.readLines(INPUT_FILENAME) | ||
.stream() | ||
.map(ScratchCard::parse) | ||
.toList(); | ||
|
||
final long part2Result = Day04.countTotalNumberOfScratchCards(values); | ||
assertThat(part2Result) | ||
.isEqualTo(11_787_590L); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53 | ||
Card 2: 13 32 20 16 61 | 61 30 68 82 17 32 24 19 | ||
Card 3: 1 21 53 59 44 | 69 82 63 72 16 21 14 1 | ||
Card 4: 41 92 73 84 69 | 59 84 76 51 58 5 54 83 | ||
Card 5: 87 83 26 28 32 | 88 30 70 12 93 22 82 36 | ||
Card 6: 31 18 13 56 72 | 74 77 10 23 35 67 36 11 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule advent-of-code-inputs
updated
from d3ae74 to 751a9a
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters