akk's recent activity
-
Comment on Day 4: Scratchcards in ~comp.advent_of_code
-
Comment on Day 3: Gear Ratios in ~comp.advent_of_code
akk Not too easy, not too hard. Had to take some breaks to help with my mother who is currently recovering from neck/back surgery. It's also a lot verbose than I've seen compared to others. I also...Not too easy, not too hard. Had to take some breaks to help with my mother who is currently recovering from neck/back surgery. It's also a lot verbose than I've seen compared to others. I also switched over to using JetBrains IntelliJ IDEA's built-in HTTP client for sending my input vs using the excellent RapidAPI for Mac (formerly Paw)
Ran into a lot of issues with an off-by-one, but I solved it :-D
Java
package com.michaeleisemann.aoc23.services; import com.michaeleisemann.aoc23.interfaces.DayInterface; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; // https://adventofcode.com/2023/day/3 @Service public class Day3Service implements DayInterface { private static class Schematic { private record PartNumber(int partNumber, int startX, int endX, int y) { } private record PartSymbol(String symbol, int x, int y) { } private final List<String> schematic = new ArrayList<>(); private final List<PartNumber> partNumbers = new ArrayList<>(); private final List<PartSymbol> partSymbols = new ArrayList<>(); public Schematic(String schematic) { String[] lines = schematic.split("\n"); this.schematic.addAll(Arrays.asList(lines)); parseSchematic(); } public List<String> getSchematic() { return schematic; } public List<PartNumber> getPartNumbers() { return partNumbers; } public List<PartSymbol> getPartSymbols() { return partSymbols; } private void parseSchematic() { for (int y = 0; y < schematic.size(); y++) { String line = schematic.get(y); StringBuilder partNumber = new StringBuilder(); int startX = 0; int endX = 0; for (int x = 0; x < line.length(); x++) { if (Character.isDigit(line.charAt(x))) { if (partNumber.isEmpty()) { startX = x; } partNumber.append(line.charAt(x)); // I hate off by one errors if (x == line.length() - 1) { endX = x - 1; PartNumber part = new PartNumber( Integer.parseInt(partNumber.toString()), startX, endX, y ); partNumber = new StringBuilder(); partNumbers.add(part); } } else { // we are done collecting part numbers if (!partNumber.isEmpty()) { endX = x - 1; PartNumber part = new PartNumber( Integer.parseInt(partNumber.toString()), startX, endX, y ); partNumber = new StringBuilder(); partNumbers.add(part); } if (line.charAt(x) != '.') { PartSymbol partSymbol = new PartSymbol( String.valueOf(line.charAt(x)), x, y ); partSymbols.add(partSymbol); } } } } } } public String part1(String puzzleInput) { Schematic schematic = new Schematic(puzzleInput); int partNumberSum = 0; for (Schematic.PartNumber partNumber : schematic.getPartNumbers()) { for (Schematic.PartSymbol partSymbol : schematic.getPartSymbols()) { if (partNumber.y() == partSymbol.y()) { if (partNumber.startX() - 1 <= partSymbol.x() && partNumber.endX() + 1 >= partSymbol.x()) { logger.debug("Same line: {} {} {}", partNumber.partNumber(), partSymbol.symbol()); partNumberSum += partNumber.partNumber(); } } else if (partNumber.y() - 1 <= partSymbol.y() && partNumber.y() + 1 >= partSymbol.y()) { if (partNumber.startX() - 1 <= partSymbol.x() && partNumber.endX() + 1 >= partSymbol.x()) { logger.debug("Different line: {} {} {}", partNumber.partNumber(), partSymbol.symbol()); partNumberSum += partNumber.partNumber(); } } } } return String.valueOf(partNumberSum); } public String part2(String puzzleInput) { Schematic schematic = new Schematic(puzzleInput); HashMap<Schematic.PartSymbol, ArrayList<Schematic.PartNumber>> partSymbolPartNumberHashMap = new HashMap<>(); for (Schematic.PartNumber partNumber : schematic.getPartNumbers()) { for (Schematic.PartSymbol partSymbol : schematic.getPartSymbols()) { if (partNumber.y() == partSymbol.y()) { addPartToSymbol((HashMap<Schematic.PartSymbol, ArrayList<Schematic.PartNumber>>) partSymbolPartNumberHashMap, partNumber, partSymbol); } else if (partNumber.y() - 1 <= partSymbol.y() && partNumber.y() + 1 >= partSymbol.y()) { addPartToSymbol((HashMap<Schematic.PartSymbol, ArrayList<Schematic.PartNumber>>) partSymbolPartNumberHashMap, partNumber, partSymbol); } } } // go through the hashmap and see which * have exactly 2 part numbers int gearRatioSum = 0; for (Schematic.PartSymbol partSymbol : partSymbolPartNumberHashMap.keySet()) { if (partSymbol.symbol().equals("*")) { if (partSymbolPartNumberHashMap.get(partSymbol).size() == 2) { // multiply the part numbers together int gearRatio = 1; for (Schematic.PartNumber partNumber : partSymbolPartNumberHashMap.get(partSymbol)) { gearRatio *= partNumber.partNumber(); } gearRatioSum += gearRatio; } } } return String.valueOf(gearRatioSum); } private void addPartToSymbol(HashMap<Schematic.PartSymbol, ArrayList<Schematic.PartNumber>> partSymbolPartNumberHashMap, Schematic.PartNumber partNumber, Schematic.PartSymbol partSymbol) { if (partNumber.startX() - 1 <= partSymbol.x() && partNumber.endX() + 1 >= partSymbol.x()) { // add the part number to the hashmap if (partSymbolPartNumberHashMap.containsKey(partSymbol)) { partSymbolPartNumberHashMap.get(partSymbol).add(partNumber); } else { ArrayList<Schematic.PartNumber> partNumbers = new ArrayList<>(); partNumbers.add(partNumber); partSymbolPartNumberHashMap.put(partSymbol, partNumbers); } } } }
-
Comment on Day 2: Cube Conundrum in ~comp.advent_of_code
akk More Java. I didn't need to make a class or anything, but I figured why not. I'm still pretty noob at Java (< 12 months), so I'm not sure what counts as "idiomatic java" or not. I'm happy with it,...More Java. I didn't need to make a class or anything, but I figured why not. I'm still pretty noob at Java (< 12 months), so I'm not sure what counts as "idiomatic java" or not. I'm happy with it, though.
Solution
package com.michaeleisemann.aoc23.services; import com.michaeleisemann.aoc23.interfaces.DayInterface; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; // https://adventofcode.com/2023/day/2 @Service public class Day2Service implements DayInterface { private final static int RED_AMOUNT = 12; private final static int GREEN_AMOUNT = 13; private final static int BLUE_AMOUNT = 14; private static class Game { private final List<Round> rounds = new ArrayList<>(); private final int id; private static class Round { private int red; private int blue; private int green; public Round(int red, int blue, int green) { this.red = red; this.blue = blue; this.green = green; } public Round(String round) { String[] cubes = round.split(","); for (String cube : cubes) { cube = cube.trim(); String[] colors = cube.split(" "); switch (colors[1]) { case "red": red = Integer.parseInt(colors[0]); break; case "blue": blue = Integer.parseInt(colors[0]); break; case "green": green = Integer.parseInt(colors[0]); break; } } } public int getRed() { return red; } public int getBlue() { return blue; } public int getGreen() { return green; } @Override public String toString() { return "Round: " + red + " red, " + blue + " blue, " + green + " green"; } } public Game(int id, String rounds) { // rounds are semi-colon delimited // cubes are comma delimited this.id = id; String[] roundStrings = rounds.split(";"); for (String round : roundStrings) { this.rounds.add(new Round(round.trim())); } } public int getId() { return id; } public int getMaxRed() { int max = 0; for (Round round : rounds) { if (round.getRed() > max) { max = round.getRed(); } } return max; } public int getMaxBlue() { int max = 0; for (Round round : rounds) { if (round.getBlue() > max) { max = round.getBlue(); } } return max; } public int getMaxGreen() { int max = 0; for (Round round : rounds) { if (round.getGreen() > max) { max = round.getGreen(); } } return max; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Game: ").append(id).append("\n"); for (Round round : rounds) { sb.append(round).append("\n"); } return sb.toString(); } } public String part1(String puzzleInput) { String[] lines = puzzleInput.split("\n"); List<Game> games = new ArrayList<>(); for (String line : lines) { games.add(buildGame(line)); } int gameSum = 0; for (Game game : games) { int reds = game.getMaxRed(); int blues = game.getMaxBlue(); int greens = game.getMaxGreen(); if (reds <= RED_AMOUNT && blues <= BLUE_AMOUNT && greens <= GREEN_AMOUNT) { logger.debug("Game {} is valid", game.getId()); gameSum += game.getId(); } } return String.valueOf(gameSum); } public String part2(String puzzleInput) { String[] lines = puzzleInput.split("\n"); List<Game> games = new ArrayList<>(); for (String line : lines) { games.add(buildGame(line)); } int powerSum = 0; for (Game game : games) { int reds = game.getMaxRed(); int blues = game.getMaxBlue(); int greens = game.getMaxGreen(); int power = 1; power *= reds; power *= blues; power *= greens; powerSum += power; } return String.valueOf(powerSum); } private Game buildGame(String line) { String[] parts = line.split(":"); // remove ervything that is not a number from the first part String id = parts[0].replaceAll("\\D+", ""); String rounds = parts[1].trim(); return new Game(Integer.parseInt(id), rounds); } }
-
Comment on Day 1: Trebuchet?! in ~comp.advent_of_code
akk (edited )LinkI started using Java since the last year, so this year I did them in Java. Other people have posted a repo, so here's mine:...I started using Java since the last year, so this year I did them in Java. Other people have posted a repo, so here's mine: https://michaeleisemann.com/source/aoc23/browse/master/src/main/java/com/michaeleisemann/aoc23/services/
If other people have pointers about my somewhat rudimentary Spring Boot webapp layout, I would love feedback on that, too.
Everything I've done so far with Java has been spring boot, so my AoC this year is a web app using Spring Boot.
Java
package com.michaeleisemann.aoc23.services; import com.michaeleisemann.aoc23.interfaces.DayInterface; import org.apache.commons.lang3.ArrayUtils; import org.springframework.stereotype.Service; // https://adventofcode.com/2023/day/1 @Service public class Day1Service implements DayInterface { private final String[] wordToNumbers = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; // Fundamentally, we have to just get the first and last digit of the String. // The first and last number can be the same. e.g. asdf1asdf produces the first and last number as 1. public String day1Part1(String puzzleInput) { logger.info("Day 1 Part 1"); logger.debug("Puzzle Input:\n{}", puzzleInput); int sum = 0; for (String line : puzzleInput.split("\n")) { // remove all non-digits String digits = line.replaceAll("\\D+", ""); int calibrationValue = getFirstAndLastDigits(digits); logger.debug("Calibration Value: {}", calibrationValue); sum += calibrationValue; } return String.valueOf(sum); } public String day1Part2(String puzzleInput) { logger.info("Day 1 Part 2"); logger.debug("Puzzle Input:\n{}", puzzleInput); int sum = 0; for (String line : puzzleInput.split("\n")) { // search through the line for either a digit or the word for a digit StringBuilder realDigits = new StringBuilder(); StringBuilder tempString = new StringBuilder(); for (String letter : line.split("")) { if (letter.matches("\\d")) { realDigits.append(letter); tempString = new StringBuilder(); continue; } tempString.append(letter); for (String wordNumber : wordToNumbers) { if (tempString.toString().contains(wordNumber)) { realDigits.append(ArrayUtils.indexOf(wordToNumbers, wordNumber)); tempString = new StringBuilder(); tempString.append(letter); break; } } } String digits = realDigits.toString(); int calibrationValue = getFirstAndLastDigits(digits); logger.debug("Calibration Value: {}", calibrationValue); sum += calibrationValue; } return String.valueOf(sum); } private int getFirstAndLastDigits(String digits) { String firstDigit = String.valueOf(digits.charAt(0)); String lastDigit = String.valueOf(digits.charAt(digits.length() - 1)); return Integer.parseInt(firstDigit + lastDigit); } }
-
Comment on Good, quality YouTube channels? in ~tech
akk VWestlife is a really fun channel if you're into old computers or electronics I love the deep dives into whatever the creator is interested in making a video about. I am especially fascinated with...VWestlife is a really fun channel if you're into old computers or electronics I love the deep dives into whatever the creator is interested in making a video about. I am especially fascinated with the videos on various radios and radio technologies.
-
Comment on What are you self-hosting currently? in ~tech
akk I've got a couple different computers running several things, everything is tailnetted together and I have a VPS that acts as my public IP and funnels traffic to my home. Honestly, I love...I've got a couple different computers running several things, everything is tailnetted together and I have a VPS that acts as my public IP and funnels traffic to my home. Honestly, I love Tailscale
My main stack looks like:
Ubuntu 22.04 LTS Server box that lives in my basement closet
- ZNC for IRC
- Transmission for one-off torrents (linux ISOs, the Llama model when that leaked etc)
- Paperless-ngx since I've been trying (and failing) to catalog all the paper I come into
- Caddy websever for directing to the websites that live in my house
- A private pastebin
- Samba share for sharing files in my house
OpenSUSE Tumbleweed running on the Framework laptop 11th gen
- Currently it just runs Phorge that is my personal website, git host, blog, calendar, and it also does a ton of other stuff -- I find new features in Phorge almost every day!
Debian 11 box
- Runs Akkoma for my microblogging needs
HTPC running Windows 10
- This is my Plex box that gathers all the media. Use your imagine as to what software runs on it ;)
-
Comment on Day 4: Camp Cleanup in ~comp
akk (edited )LinkPretty similar to yesterday if you ask me. Still love Swift! Part 1 and 2 import Foundation var totalFullSubRanges: Int = 0 var totalAnySubRanges: Int = 0 while let line = readLine() { let...Pretty similar to yesterday if you ask me. Still love Swift!
Part 1 and 2
import Foundation var totalFullSubRanges: Int = 0 var totalAnySubRanges: Int = 0 while let line = readLine() { let sectionRanges = line.components(separatedBy: ",").map { $0.components(separatedBy: "-").map { Int($0) ?? -1 } } let rangeOne = Set(Array(sectionRanges[0][0]...sectionRanges[0][1])) let rangeTwo = Set(Array(sectionRanges[1][0]...sectionRanges[1][1])) if rangeOne.isSubset(of: rangeTwo) || rangeTwo.isSubset(of: rangeOne) { totalFullSubRanges += 1 } if !rangeOne.intersection(rangeTwo).isEmpty { totalAnySubRanges += 1 } } print(totalFullSubRanges) print(totalAnySubRanges)
-
Comment on Day 3: Rucksack Reorganization in ~comp
akk More swift! Parts 1 and 2 import Foundation // Source: https://www.hackingwithswift.com/example-code/language/how-to-split-an-array-into-chunks extension Array { func chunked(into size: Int) ->...More swift!
Parts 1 and 2
import Foundation // Source: https://www.hackingwithswift.com/example-code/language/how-to-split-an-array-into-chunks extension Array { func chunked(into size: Int) -> [[Element]] { return stride(from: 0, to: count, by: size).map { Array(self[$0 ..< Swift.min($0 + size, count)]) } } } func checkPriority(for item: String.Element) -> Int { if item.isUppercase { return Int(item.asciiValue!) - 64 + 26 } else { return Int(item.asciiValue!) - 96 } } func partOne(_ input: [String]) { var totalPriority: Int = 0 for line in input { let sacks = Array(line).chunked(into: line.count / 2).map { Set($0) } guard let uniqueCompartment = sacks[0].intersection(sacks[1]).first else { break } totalPriority += checkPriority(for: uniqueCompartment) } print(totalPriority) } func partTwo(_ input: [String]) { let sackGroups = input.chunked(into: 3) var totalPriority: Int = 0 for group in sackGroups { let sackSet = group.map { Set($0) } guard let uniqueItem = sackSet[0].intersection(sackSet[1].intersection(sackSet[2])).first else { break } totalPriority += checkPriority(for: uniqueItem) } print(totalPriority) } var puzzleInput: [String] = [] while let line = readLine() { puzzleInput.append(line) } partOne(puzzleInput) partTwo(puzzleInput)
-
Comment on Day 2: Dive! in ~comp
akk Did mine in Swift! Solution import Foundation enum Heading: String { case up = "up" case down = "down" case forward = "forward" } struct Direction { let heading: Heading let magnitude: Int } class...Did mine in Swift!
Solution
import Foundation enum Heading: String { case up = "up" case down = "down" case forward = "forward" } struct Direction { let heading: Heading let magnitude: Int } class Submarine { var directions: [Direction] = [] var depth: Int = 0 var aim: Int = 0 var horizontalPosition: Int = 0 func processDirectionsAndResetPosition(calculateAim: Bool) { for direction in directions { switch direction.heading { case .up: if calculateAim { aim = aim - direction.magnitude } else { depth = depth - direction.magnitude } case .down: if calculateAim { aim = aim + direction.magnitude } else { depth = depth + direction.magnitude } case .forward: if calculateAim { horizontalPosition = horizontalPosition + direction.magnitude depth = depth + (aim * direction.magnitude) } else { horizontalPosition = horizontalPosition + direction.magnitude } } } print("\(self.depth * self.horizontalPosition)") self.resetPosition() } private func resetPosition() { self.aim = 0 self.depth = 0 self.horizontalPosition = 0 } } var sub = Submarine() while let line = readLine() { let splitLine = line.components(separatedBy: " ") let direction = Direction(heading: Heading(rawValue: String(splitLine[0]))!, magnitude: Int(splitLine[1])!) sub.directions.append(direction) } sub.processDirectionsAndResetPosition(calculateAim: false) sub.processDirectionsAndResetPosition(calculateAim: true)
Dayjob made me put this off until after work and other responsibilities. Kinda messy. Part 2 had me stumped for a while. I conceptually knew what to do, but couldn't figure out what to type into IntelliJ.
Java Solution