Skip to content

Commit

Permalink
Adding solution for Day 11 (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
jabrena authored Jan 5, 2025
1 parent b66df22 commit 0f2c347
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 2 deletions.
4 changes: 3 additions & 1 deletion 2015/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@
| 6 | NA | [LightCounter](./src/main/java/info/jab/aoc/day6/LightCounter.java) | | Data processing |
| 7 | NA | [Circuit](./src/main/java/info/jab/aoc/day7/Circuit.java) | Complex String parsing | Data processing |
| 8 | NA | [StringLiteralCalculator](./src/main/java/info/jab/aoc/day8/StringLiteralCalculator.java) | | Data processing |
| 9 | NA | [RouteOptimizer](./src/main/java/info/jab/aoc/day9/RouteOptimizer.java) | | Data processing |
| 9 | NA | [RouteOptimizer](./src/main/java/info/jab/aoc/day9/RouteOptimizer.java) | | Data processing |
| 10 | NA | [LookAndSay](./src/main/java/info/jab/aoc/day10/LookAndSay.java) | | Data processing |
| 11 | NA | [PasswordValidator](./src/main/java/info/jab/aoc/day11/PasswordValidator.java) | | Data processing |
22 changes: 22 additions & 0 deletions 2015/src/main/java/info/jab/aoc/day11/Day11.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package info.jab.aoc.day11;

import info.jab.aoc.Day;

/**
* https://adventofcode.com/2015/day/10
*/
public class Day11 implements Day<String> {

@Override
public String getPart1Result(String input) {
PasswordValidator validator = new PasswordValidator();
String nextPassword = validator.findNextValidPassword(input);
return nextPassword;
}

@Override
public String getPart2Result(String input) {
var newPassword = this.getPart1Result(input);
return this.getPart1Result(newPassword);
}
}
85 changes: 85 additions & 0 deletions 2015/src/main/java/info/jab/aoc/day11/PasswordValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package info.jab.aoc.day11;

import java.util.stream.IntStream;

public class PasswordValidator {

public String findNextValidPassword(String currentPassword) {
String nextPassword = currentPassword;
do {
nextPassword = incrementPassword(nextPassword);
} while (!isValidPassword(nextPassword));
return nextPassword;
}

private String incrementPassword(String password) {
char[] chars = password.toCharArray();
int i = chars.length - 1;

while (i >= 0) {
chars[i] = (char) (chars[i] + 1);
if (chars[i] > 'z') {
chars[i] = 'a';
i--;
} else {
if (isProhibitedLetter(chars[i])) {
chars[i]++;
// Reset all following characters to 'a'
for (int j = i + 1; j < chars.length; j++) {
chars[j] = 'a';
}
}
break;
}
}
return new String(chars);
}

private boolean containsProhibitedLetters(String password) {
return password.chars()
.mapToObj(c -> (char) c)
.anyMatch(this::isProhibitedLetter);
}

private boolean containsStraightSequence(String password) {
return IntStream.range(0, password.length() - 2)
.anyMatch(i -> {
char current = password.charAt(i);
return password.charAt(i + 1) == current + 1 &&
password.charAt(i + 2) == current + 2;
});
}

private boolean containsTwoDifferentPairs(String password) {
int pairCount = 0;
char lastPairChar = '\0';

for (int i = 0; i < password.length() - 1; i++) {
if (password.charAt(i) == password.charAt(i + 1)) {
if (password.charAt(i) != lastPairChar) {
pairCount++;
lastPairChar = password.charAt(i);
i++; // Skip next character as it's part of the pair
}
}
}
return pairCount >= 2;
}

private static final char[] PROHIBITED_LETTERS = {'i', 'o', 'l'};

private boolean isProhibitedLetter(char c) {
for (char prohibited : PROHIBITED_LETTERS) {
if (c == prohibited) {
return true;
}
}
return false;
}

private boolean isValidPassword(String password) {
return !containsProhibitedLetters(password) &&
containsStraightSequence(password) &&
containsTwoDifferentPairs(password);
}
}
70 changes: 70 additions & 0 deletions 2015/src/test/gherkin/day11-part1.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
Feature: Corporate Password Policy Validation
As a Security-Elf
I want to enforce strict password policies
So that Santa's password remains secure

Background:
Given passwords must be exactly 8 lowercase letters
And passwords cannot contain the letters 'i', 'o', or 'l'
And the current password is "hepxcrrq"

Rule: Password must contain an increasing straight of three letters

Scenario: Password contains valid straight sequence
Given a password "abcdefgh"
When I check for a straight sequence
Then it should be valid because it contains "abc"

Scenario: Password lacks straight sequence
Given a password "abbceffg"
When I check for a straight sequence
Then it should be invalid
And the validation should indicate "missing straight sequence of three letters"

Rule: Password must contain two different non-overlapping pairs

Scenario: Password contains two different pairs
Given a password "abcdffaa"
When I check for letter pairs
Then it should be valid because it contains "ff" and "aa"

Scenario: Password contains only one pair
Given a password "abbcegjk"
When I check for letter pairs
Then it should be invalid
And the validation should indicate "needs two different pairs"

Rule: Password incrementing follows specific rules

Scenario Outline: Incrementing password characters
Given a password "<initial>"
When I increment the password
Then the result should be "<result>"

Examples:
| initial | result |
| xx | xy |
| xz | ya |
| ya | yb |

Scenario: Skip prohibited letters when incrementing
Given a password "ghijklmn"
When I increment the password
Then it should skip all passwords containing 'i'
And the result should be "ghjaabcc"

Rule: Complete password update process

Scenario: Finding next valid password
Given the current password "abcdefgh"
When I search for the next valid password
Then I should find "abcdffaa"
And it should contain a straight sequence
And it should contain two different pairs
And it should not contain prohibited letters

Scenario: Finding next valid password from puzzle input
Given the current password "hepxcrrq"
When I search for the next valid password
Then the result should meet all validation rules
And it should be the first valid password after "hepxcrrq"
42 changes: 42 additions & 0 deletions 2015/src/test/java/info/jab/aoc/day11/Day11Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package info.jab.aoc.day11;

import static org.assertj.core.api.BDDAssertions.then;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import com.putoet.utils.Timer;

class Day11Test {

@Test
void should_solve_day11_part1() {
Timer.run(() -> {
//Given
String input = "hepxcrrq";

//When
var day = new Day11();
var result = day.getPart1Result(input);

//Then
then(result).isEqualTo("hepxxyzz");
});
}

@Test
void should_solve_day11_part2() {
Timer.run(() -> {
//Given
String input = "hepxcrrq";

//When
var day = new Day11();
var result = day.getPart2Result(input);

//Then
then(result).isEqualTo("heqaabcc");
});
}

}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ sdk env install
./mvnw clean verify -T 8C
./mvnw -pl 2015 clean compile -am
./mvnw -pl 2015 clean verify -am
./mvnw -pl 2015 clean test -Dtest=Day10Test
./mvnw -pl 2015 clean test -Dtest=Day11Test
./mvnw -pl 2015 clean test -Dtest=GherkinValidatorTest
./mvnw -pl 2015 clean dependency:tree
./mvnw -pl 2016 clean verify surefire-report:report -DshowSuccess=false
Expand Down

0 comments on commit 0f2c347

Please sign in to comment.