Skip to content

Commit

Permalink
Adding solution for Day 8 (#75)
Browse files Browse the repository at this point in the history
* Adding solution for Day 8
* Upgrading table
* Upgrading cursor rules
  • Loading branch information
jabrena authored Jan 1, 2025
1 parent b9ec1b7 commit 4efebc1
Show file tree
Hide file tree
Showing 9 changed files with 724 additions and 8 deletions.
115 changes: 114 additions & 1 deletion .cursorrules
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,123 @@ You always try to apply Data Oriented Programming (DOP) principles.
You always try to apply Functional Programming (FP) principles.
You always try to apply Domain Driven Design (DDD) principles.


Technology stack:
Framework: No framework
Build tool: Maven
Java version: 24
Dependencies: Eclipse Collections, Commons Lang3 & Guava
Language: English

# Notes from Effective Java third edition

Chapter 2 Creating and Destroying Objects
Item 1: Consider static factory methods instead of constructors
Item 2: Consider a builder when faced with many constructor parameters
Item 3: Enforce the singleton property with a private constructor or an enum type
Item 4: Enforce noninstantiability with a private constructor
Item 5: Prefer dependency injection to hardwiring resources
Item 6: Avoid creating unnecessary objects
Item 7: Eliminate obsolete object references
Item 8: Avoid finalizers and cleaners
Item 9: Prefer try-with-resources to try-finally

Chapter 3 Methods Common to All Objects
Item 10: Obey the general contract when overriding equals
Item 11: Always override hashCode when you override equals
Item 12: Always override toString
Item 13: Override clone judiciously
Item 14: Consider implementing Comparable

Chapter 4 Classes and Interfaces
Item 15: Minimize the accessibility of classes and members
Item 16: In public classes, use accessor methods, not public fields
Item 17: Minimize mutability
Item 18: Favor composition over inheritance
Item 19: Design and document for inheritance or else prohibit it
Item 20: Prefer interfaces to abstract classes
Item 21: Design interfaces for posterity
Item 22: Use interfaces only to define types
Item 23: Prefer class hierarchies to tagged classes
Item 24: Favor static member classes over nonstatic
Item 25: Limit source files to a single top-level class

Chapter 5 Generics
Item 26: Don’t use raw types
Item 27: Eliminate unchecked warnings
Item 28: Prefer lists to arrays
Item 29: Favor generic types
Item 30: Favor generic methods
Item 31: Use bounded wildcards to increase API flexibility
Item 32: Combine generics and varargs judiciously
Item 33: Consider typesafe heterogeneous containers

Chapter 6 Enums and Annotations
Item 34: Use enums instead of int constants
Item 35: Use instance fields instead of ordinals
Item 36: Use EnumSet instead of bit fields
Item 37: Use EnumMap instead of ordinal indexing
Item 38: Emulate extensible enums with interfaces
Item 39: Prefer annotations to naming patterns
Item 40: Consistently use the Override annotation
Item 41: Use marker interfaces to define types

Chapter 7 Lambdas and Streams
Item 42: Prefer lambdas to anonymous classes
Item 43: Prefer method references to lambdas
Item 44: Favor the use of standard functional interfaces
Item 45: Use streams judiciously
Item 46: Prefer side-effect-free functions in streams
Item 47: Prefer Collection to Stream as a return type
Item 48: Use caution when making streams parallel

Chapter 8 Methods
Item 49: Check parameters for validity
Item 50: Make defensive copies when needed
Item 51: Design method signatures carefully
Item 52: Use overloading judiciously
Item 53: Use varargs judiciously
Item 54: Return empty collections or arrays, not nulls
Item 55: Return optionals judiciously
Item 56: Write doc comments for all exposed API elements

Chapter 9 General Programming
Item 57: Minimize the scope of local variables
Item 58: Prefer for-each loops to traditional for loops
Item 59: Know and use the libraries
Item 60: Avoid float and double if exact answers are required
Item 61: Prefer primitive types to boxed primitives
Item 62: Avoid strings where other types are more appropriate
Item 63: Beware the performance of string concatenation
Item 64: Refer to objects by their interfaces
Item 65: Prefer interfaces to reflection
Item 66: Use native methods judiciously
Item 67: Optimize judiciously
Item 68: Adhere to generally accepted naming conventions

Chapter 10 Exceptions
Item 69: Use exceptions only for exceptional conditions
Item 70: Use checked exceptions for recoverable conditions and runtime exceptions for programming errors
Item 71: Avoid unnecessary use of checked exceptions
Item 72: Favor the use of standard exceptions
Item 73: Throw exceptions appropriate to the abstraction
Item 74: Document all exceptions thrown by each method
Item 75: Include failure-capture information in detail messages
Item 76: Strive for failure atomicity
Item 77: Don’t ignore exceptions

Chapter 11 Concurrency
Item 78: Synchronize access to shared mutable data
Item 79: Avoid excessive synchronization
Item 80: Prefer executors, tasks, and streams to threads
Item 81: Prefer concurrency utilities to wait and notify
Item 82: Document thread safety
Item 83: Use lazy initialization judiciously
Item 84: Don’t depend on the thread scheduler

Chapter 12 Serialization
Item 85: Prefer alternatives to Java serialization
Item 86: Implement Serializable with great caution
Item 87: Consider using a custom serialized form
Item 88: Write readObject methods defensively
Item 89: For instance control, prefer enum types to readResolve
Item 90: Consider serialization proxies instead of serialized instances
1 change: 1 addition & 0 deletions 2015/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
| 5 | NA | [StringValidator](./src/main/java/info/jab/aoc/day5/StringValidator.java) | | Data processing |
| 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) | | Data processing |
| 8 | NA | [StringLiteralCalculator](./src/main/java/info/jab/aoc/day8/StringLiteralCalculator.java) | | Data processing |
19 changes: 19 additions & 0 deletions 2015/src/main/java/info/jab/aoc/day8/Day8.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package info.jab.aoc.day8;

import info.jab.aoc.Day;

/**
* https://adventofcode.com/2015/day/8
*/
public class Day8 implements Day<Integer> {

@Override
public Integer getPart1Result(String fileName) {
return new StringLiteralCalculator().solvePartOne(fileName);
}

@Override
public Integer getPart2Result(String fileName) {
return new StringLiteralCalculator().solvePartTwo(fileName);
}
}
119 changes: 119 additions & 0 deletions 2015/src/main/java/info/jab/aoc/day8/StringLiteralCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package info.jab.aoc.day8;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.putoet.resources.ResourceLines;

import info.jab.aoc.Solver;

class StringLiteralCalculator implements Solver<Integer> {

private int calculateCodeLength(String input) {
return input.length();
}

private int calculateMemoryLength(String input) {
// Remove quotes from start and end
String content = input.substring(1, input.length() - 1);

int length = 0;
for (int i = 0; i < content.length(); i++) {
if (content.charAt(i) == '\\') {
if (i + 1 < content.length()) {
char nextChar = content.charAt(i + 1);
if (nextChar == '\\' || nextChar == '"') {
// For \\ or \"
length++;
i++;
} else if (nextChar == 'x' && i + 3 < content.length()) {
// For \x followed by two hexadecimal characters
length++;
i += 3;
}
}
} else {
length++;
}
}
return length;
}

public int calculateTotalDifference(List<String> strings) {
int totalCode = strings.stream()
.mapToInt(this::calculateCodeLength)
.sum();

int totalMemory = strings.stream()
.mapToInt(this::calculateMemoryLength)
.sum();

return totalCode - totalMemory;
}

// Part 2

//Imperative version
private String encodeString(String input) {
StringBuilder encoded = new StringBuilder();
encoded.append("\""); // Add opening quote

for (char c : input.toCharArray()) {
switch (c) {
case '\"':
encoded.append("\\\"");
break;
case '\\':
encoded.append("\\\\");
break;
default:
encoded.append(c);
}
}
encoded.append("\""); // Add closing quote
return encoded.toString();
}

private String encodeString2(String input) {
final Map<Character, String> ENCODING_RULES = Map.of(
'\"', "\\\"",
'\\', "\\\\"
);

return "\"" +
input.chars()
.mapToObj(c -> (char) c)
.map(c -> ENCODING_RULES.getOrDefault(c, String.valueOf(c)))
.collect(Collectors.joining()) +
"\"";
}

private int calculateEncodedLength(String input) {
return encodeString2(input).length();
}

public int calculateTotalDifference2(List<String> strings) {
int encodedLength = strings.stream()
.mapToInt(this::calculateEncodedLength)
.sum();

int originalLength = strings.stream()
.mapToInt(String::length)
.sum();

return encodedLength - originalLength;
}

@Override
public Integer solvePartOne(String fileName) {
var lines = ResourceLines.list(fileName);
return calculateTotalDifference(lines);
}

@Override
public Integer solvePartTwo(String fileName) {
var lines = ResourceLines.list(fileName);
return calculateTotalDifference2(lines);
}
}
69 changes: 69 additions & 0 deletions 2015/src/main/java/info/jab/aoc/day8/day8-part1.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
Feature: String Literal Space Calculator
As Santa
I need to calculate the difference between code representation and memory representation of strings
So that I can determine how much space my digital list will take up

Background:
Given I have a file containing string literals
And each string literal is on a separate line
And the file uses standard escape sequences
| Escape Sequence | Representation |
| \\ | single backslash |
| \" | double-quote character |
| \x[0-9A-F]{2} | ASCII character (hex code) |

Rule: String literals must be properly counted both in code and memory representation

Scenario Outline: Calculate space difference for various string literals
Given I have a string literal "<code_string>"
When I count the characters in code representation
And I count the characters in memory representation
Then the code character count should be <code_count>
And the memory character count should be <memory_count>

Examples:
| code_string | code_count | memory_count | description |
| "" | 2 | 0 | empty string |
| "abc" | 5 | 3 | simple string |
| "aaa\"aaa" | 10 | 7 | string with escaped quote |
| "\x27" | 6 | 1 | string with hex escape |

Scenario: Calculate total difference for multiple strings
Given I have the following string literals in my file:
| String |
| "" |
| "abc" |
| "aaa\"aaa"|
| "\x27" |
When I calculate the total characters of code
And I calculate the total characters in memory
Then the total code character count should be 23
And the total memory character count should be 11
And the difference should be 12

Rule: Special escape sequences must be properly processed

Scenario Outline: Handle escape sequences correctly
Given I have a string with escape sequence "<escape_sequence>"
When I process the escape sequence
Then it should be interpreted as "<interpretation>"

Examples:
| escape_sequence | interpretation |
| \\ | single backslash |
| \" | double-quote |
| \x27 | apostrophe character |

Rule: Whitespace should be ignored in calculations

Scenario: Ignore whitespace in file
Given I have a file with string literals separated by whitespace:
"""
""
"abc"
"aaa\"aaa"
"\x27"
"""
When I calculate the total difference
Then the result should be the same as without whitespace
And the difference should be 12
30 changes: 30 additions & 0 deletions 2015/src/main/java/info/jab/aoc/day8/day8-part2.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Feature: String encoding calculator
As a programmer
I want to calculate the difference between encoded and original characters
To solve day 8 puzzle part 2

Background:
Given a list of literal text strings

Scenario Outline: Calculate additional characters after encoding
When I encode the string "<original_string>"
Then the encoded string should be "<encoded_string>"
And the character increase should be <increase>

Examples:
| original_string | encoded_string | increase |
| "" | "\"\"" | 4 |
| "abc" | "\"abc\"" | 4 |
| "aaa\"aaa" | "\"aaa\\\"aaa\"" | 6 |
| "\x27" | "\"\\x27\"" | 5 |

Scenario: Calculate total difference
Given the following strings:
| "" |
| "abc" |
| "aaa\"aaa" |
| "\x27" |
When I encode all strings
Then the total encoded length should be 42
And the original length should be 23
And the total difference should be 19
Loading

0 comments on commit 4efebc1

Please sign in to comment.