-
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
6 changed files
with
223 additions
and
2 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
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,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
85
2015/src/main/java/info/jab/aoc/day11/PasswordValidator.java
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,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); | ||
} | ||
} |
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,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" |
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,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"); | ||
}); | ||
} | ||
|
||
} |
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