• 0 Posts
  • 97 Comments
Joined 3 years ago
cake
Cake day: June 29th, 2023

help-circle





  • On the one hand, this is very funny. On the other hand, however, it’s still very funny, but also maybe we shouldn’t turn running full speed into a house of religion, no matter how hokey that religion may be, into a trend? Yes, the whole enterprise is shady at best, and they believe in some weird space alien magic. They also have a history of harassing former members and anyone who dares to pull back the veil on the secretive organization’s scare tactics.

    Fuck off with this whitewashing. Scientology isn’t “hokey” or “shady”. It’s outright evil.




  • This is very different from my experience, but I’ve purposely lagged behind in adoption and I often do things the slow way because I like programming and I don’t want to get too lazy and dependent.

    I just recently started using Claude Code CLI. With how I use it: asking it specific questions and often telling it exactly what files and lines to analyze, it feels more like taking to an extremely knowledgeable programmer who has very narrow context and often makes short-sighted decisions.

    I find it super helpful in troubleshooting. But it also feels like a trap, because I can feel it gaining my trust and I know better than to trust it.





  • I pushed my team to use trunk based development. We did cherry-picks from trunk to release branches for a couple years with no issues. Since then, I’ve written a GitHub action that automates the cherry-picks based on tickets in the commit messages.

    But even before the automation, it drastically improved our dev processes.

    We weren’t on Git Flow exactly, but it was a bastardized version of it.

    Having used TBD successfully for like 5-6 years now. I can’t imagine using Git Flow.





  • Kotlin

    Looking at the puzzle, I knew that I had no clue how to solve it. So I came here to see if I was missing something or if there were any hints.

    And the hint I saw was to do the simplest check possible, so I gave it a shot.

    And that got the test input wrong, but I ran it against the real input anyway just to see if it was right. And it was.

    I think if I had gone on my instincts and just tried to solve this, I could have gone around in circles for hours or days trying to get it right.

    fun main() {
        val input = getInput(12)
        val (gifts, regions) = parseInput1(input)
        var total = 0
        for (i in regions.indices) {
            val totalAreaOfGifts = regions[i].gifts.mapIndexed { index, count -> count * gifts[index].area }.sum()
            if (totalAreaOfGifts <= regions[i].area) {
                total++
            }
        }
        println(total)
    }
    
    data class Gift(val shape: List<List<Char>>, val area: Int)
    
    data class Region(val width: Int, val height: Int, val area: Int, val gifts: List<Int>)
    
    fun parseInput1(input: String): Pair<List<Gift>, List<Region>> {
        val gifts: MutableList<Gift> = mutableListOf()
        val regions: MutableList<Region> = mutableListOf()
        val lines = input.lines()
        lines.forEachIndexed { index, line ->
            if (line.contains(":")) {
                if (line.contains("x")) {
                    val split = line.split(" ")
                    val shape = split.first().replace(":", "").split("x")
                    val width = shape.first().toInt()
                    val height = shape.last().toInt()
                    regions.add(
                        Region(
                            width,
                            height,
                            width * height,
                            split.slice(1..<split.size).map { str -> str.toInt() })
                    )
                } else {
                    var nextBlankLineIndex = 0
                    for (i in index + 1..<lines.size) {
                        if (lines[i].isBlank()) {
                            nextBlankLineIndex = i
                            break
                        }
                    }
                    val shape = lines.slice(index + 1..<nextBlankLineIndex).map { it.toCharArray().toList() }
                    val area = shape.flatten().filter { it == '#' }.size
                    gifts.add(Gift(shape, area))
                }
            }
        }
        return gifts to regions
    }
    


  • Kotlin

    Part 1 had me assuming, like a lot of other folks, that Part 2 would be a simple weighted graph. So I coded Part 1 as a non-weighted graph and it was great.

    Part 2 looked simple enough, but different. Part 1 was breadth first, I assumed depth first would work for Part 2. When it worked great on the test input, but took 12 seconds, I knew I was in trouble. So I added caching. And it was super quick on the test input.

    Real input was a whole 'nother story. I watched my system resources balloon. At last count it was using 8GB of RAM before I killed it. And that was before solving even the first line.

    So I went online to find what I’m missing to see people saying it’s a linear algebra problem, and that it’s best to use some kind of library for it.

    I will admit that I leaned pretty heavily on asking Gemini questions to figure out how to use the Google OR-Tools library.

    So here’s my Part 2 code:

    import com.google.ortools.Loader
    import com.google.ortools.linearsolver.MPSolver
    import com.google.ortools.linearsolver.MPVariable
    import utils.*
    
    fun main() {
        val input = getInput(10)
        val machines = parseInput1(input)
        Loader.loadNativeLibraries()
        var total = 0
        for (machine in machines) {
            val buttons = machine.buttons
            val joltages = machine.joltages
            val solver = MPSolver.createSolver("SCIP") ?: throw Exception("Could not create solver")
            val x = arrayOfNulls<MPVariable>(machine.buttons.size)
            for (i in buttons.indices) {
                x[i] = solver.makeIntVar(0.0, Double.POSITIVE_INFINITY, "x$i")
            }
            val target = joltages.map { it.toDouble() }
            val aMatrix = joltages.indices.map { joltageToArray(it, buttons) }.toTypedArray()
            for (j in joltages.indices) {
                val ct = solver.makeConstraint(target[j], target[j], "joltage_constraint_$j")
                for (i in buttons.indices) {
                    ct.setCoefficient(x[i], aMatrix[j][i])
                }
            }
            val objective = solver.objective()
            for (i in buttons.indices) {
                objective.setCoefficient(x[i], 1.0)
            }
            objective.setMinimization()
            val resultStatus = solver.solve()
            if (resultStatus == MPSolver.ResultStatus.OPTIMAL) {
                val result = objective.value().toInt()
                total += result
            } else {
                println("Problem could not be solved.")
            }
        }
        println(total)
    }
    
    data class Machine(val configuration: List<Boolean>, val buttons: List<List<Int>>, val joltages: List<Int>)
    
    fun parseInput1(input: String): List<Machine> {
        return input.lines()
            .filter { it.isNotBlank() }
            .map {
                val split = it.split(" ")
                val configuration = split.first().toCharArray()
                    .slice(1..<split.first().length - 1)
                    .map { char ->
                        when (char) {
                            '#' -> true
                            else -> false
                        }
                    }
                val buttons = split.slice(1..<split.size - 1)
                    .map { str ->
                        str.slice(1..<str.length - 1)
                            .split(",")
                            .map { number -> number.toInt() }
                    }
                val joltages = split.last()
                    .slice(1..<split.last().length - 1)
                    .split(",")
                    .map { number -> number.toInt() }
                Machine(configuration, buttons, joltages)
            }
    }
    
    fun joltageToArray(joltageIndex: Int, buttons: List<List<Int>>): Array<Double> {
        val array = DoubleArray(buttons.size) { 0.0 }.toTypedArray()
        for (i in buttons.indices) {
            if (joltageIndex in buttons[i]) {
                array[i] = 1.0
            }
        }
        return array
    }
    

  • Kotlin

    This was substantially easier than yesterday’s problem. Especially considering I still haven’t done Part 2 from yesterday.

    Anyway, here is my Part 2 solution for today. Given how quickly Part 1 ran without a cache, I didn’t think Part 2 would be much different, until my computer fans spun up and stayed there for over a minute. So I added a cache and re-ran it and it ran in 31ms.

    const val end = "out"
    var map: Map<String, List<String>>? = null
    val problemVertices = "dac" to "fft"
    val cache: MutableMap<Pair<String, Pair<Boolean, Boolean>>, Long> = mutableMapOf()
    
    fun main() {
        val input = getInput(11)
        map = parseInput1(input)
        val total = countPaths2("svr", false to false).first
        println(total)
    }
    
    fun countPaths2(vertex: String, problemVerticesEncountered: Pair<Boolean, Boolean>): Pair<Long, Pair<Boolean, Boolean>> {
        val otherVertices = map!![vertex]!!
        var total = 0L
        val nextProblemVerticesEncountered =
            (problemVerticesEncountered.first || vertex == problemVertices.first) to (problemVerticesEncountered.second || vertex == problemVertices.second)
        for (otherVertex in otherVertices) {
            val key = otherVertex to nextProblemVerticesEncountered
            if (cache.contains(key)) {
                total += cache[key]!!
            } else if (otherVertex == end) {
                if (nextProblemVerticesEncountered.first && nextProblemVerticesEncountered.second) {
                    total++
                }
            } else {
                total += countPaths2(otherVertex, nextProblemVerticesEncountered).first
            }
        }
        cache[vertex to nextProblemVerticesEncountered] = total
        return total to nextProblemVerticesEncountered
    }
    
    
    fun parseInput1(input: String): Map<String, List<String>> = input.lines()
        .filter { it.isNotBlank() }
        .associate {
            val split = it.split(": ")
            split[0] to split[1].split(" ").toList()
        }