• 6 Posts
  • 229 Comments
Joined 2 years ago
cake
Cake day: June 17th, 2023

help-circle








  • I also solved part2 manually today, by outputting the correct addition and program output in binary and then reversing the path for all wrong outputs.

    Then I just had to compare that to the formulas for a full adder and I found my swaps pretty quickly that way.

    I did all of this in Kotlin and on paper, with a handy helper method to construct the paths.

    It’s at the very bottom of this file on Github.

    I suspect that comparing the bits and then comparing the paths to the full adder formulas can also be done ‘automatically’ decently easily, but I was too lazy to implement that today.


  • Kotlin

    Part1 was pretty simple, just check all neighbors of a node for overlap, then filter out triples which don’t have nodes beginning with ‘t’.

    For part2, I seem to have picked a completely different strategy to everyone else. I was a bit lost, then just boldly assumed, that if I take overlap of all triples with 1 equal node, I might be able to find the answer that way. To my surprise, this worked for my input. I’d be very curious to know if I just got lucky or if the puzzle is designed to work with this approach.

    The full code is also on GitHub.

    Solution
    class Day23 : Puzzle {
    
        private val connections = ArrayList<Pair<String, String>>()
    
        private val tripleCache = HashSet<Triple<String, String, String>>()
    
        override fun readFile() {
            val input = readInputFromFile("src/main/resources/day23.txt")
            for (line in input.lines()) {
                val parts = line.split("-")
                connections.add(Pair(parts[0], parts[1]))
            }
        }
    
        override fun solvePartOne(): String {
            val triples = getConnectionTriples(connections)
            tripleCache.addAll(triples) // for part 2
            val res = triples.count { it.first.startsWith("t") || it.second.startsWith("t") || it.third.startsWith("t") }
            return res.toString()
        }
    
        private fun getConnectionTriples(connectionList: List<Pair<String, String>>): List<Triple<String, String, String>> {
            val triples = ArrayList<Triple<String, String, String>>()
            for (connection in connectionList) {
                val connectionListTemp = getAllConnections(connection.first, connectionList)
                for (i in connectionListTemp.indices) {
                    for (j in i + 1 until connectionListTemp.size) {
                        val con1 = connectionListTemp[i]
                        val con2 = connectionListTemp[j]
                        if (Pair(con1, con2) in connectionList || Pair(con2, con1) in connectionList) {
                            val tripleList = mutableListOf(connection.first, con1, con2)
                            tripleList.sort()
                            triples.add(Triple(tripleList[0], tripleList[1], tripleList[2]))
                        }
                    }
                }
            }
            return triples.distinct()
        }
    
        private fun getAllConnections(connection: String, connectionList: List<Pair<String, String>>): List<String> {
            val res = HashSet<String>()
            for (entry in connectionList) {
                when (connection) {
                    entry.first -> res.add(entry.second)
                    entry.second -> res.add(entry.first)
                }
            }
            return res.toList()
        }
    
        override fun solvePartTwo(): String {
            val pools = getPools(connections)
            println(pools)
            val res = pools.maxByOrNull { it.size }!!
            return res.joinToString(",")
        }
    
        // will get all pools with a minimum size of 4
        // this method makes some naive assumptions, but works for the example and my puzzle input
        private fun getPools(connectionList: List<Pair<String, String>>): List<List<String>> {
            val pools = ArrayList<List<String>>()
            val triples = tripleCache
            val nodes = connectionList.map { listOf(it.first, it.second) }.flatten().toHashSet()
    
            for (node in nodes) {
                val contenders = triples.filter { it.first == node || it.second == node || it.third == node }
                if (contenders.size < 2) continue // expect the minimum result to be 4, for efficiency
    
                // if *all* nodes within *all* triples are interconnected, add to pool
                // this may not work for all inputs!
                val contenderList = contenders.map { listOf(it.first, it.second, it.third) }.flatten().distinct()
                if (checkAllConnections(contenderList, connectionList)) {
                    pools.add(contenderList.sorted())
                }
            }
    
            return pools.distinct()
        }
    
        private fun checkAllConnections(pool: List<String>, connectionList: List<Pair<String, String>>): Boolean {
            for (i in pool.indices) {
                for (j in i + 1 until pool.size) {
                    val con1 = pool[i]
                    val con2 = pool[j]
                    if (Pair(con1, con2) !in connectionList && Pair(con2, con1) !in connectionList) {
                        return false
                    }
                }
            }
            return true
        }
    }
    




  • I was pretty neutral towards Ubuntu, up until an automatic system update removed my deb Firefox and replaced it with the snap version, even though I specifically set the apt repo to a higher priority.

    The entire reason I left Windows is because I don’t want (for example) Edge shoved down my throat after every update, and yet Ubuntu has gone and done the exact same thing with snaps.

    After literal hours of fighting, the only solution I found was to fully disable automatic updates. With Pop OS I have all the benefits of Ubuntu, but I also get a company (System76) that does cool stuff and doesn’t try shoving snaps down my throat.




  • You can absolutely re-encode h265 video, but you can’t do it losslessly. In the end, it’s always a balance between quality and filesize.

    I decided for myself, that 1080p30 crf28 h265 is good enough for home video, which lead to a 50% to 80% storage space reduction on videos from my phone.

    If you don’t obsess over quality, I would highly recommend just messing around with ffmpeg a little bit and decide how much quality you’re willing to lose in order to save disk space. When you’re happy with your settings, you can either use ffmpeg itself or some fancy batch program like Tdarr to transcode all (or parts of) your video library.

    My goto command is:
    for file in *.mp4; do ffmpeg -i "$file" -movflags use_metadata_tags -map_metadata 0 -vcodec libx265 -crf 28 -vf scale=1920:-1 -r 30 "${file%.*}_transcoded.mp4"; done



  • My personal gripe with mobile Firefox is searching by using the address bar.

    I have had countless times where I put in my search prompt, followed by pressing the little X all the way on the right and thus clearing the address bar. My brain just really expects an enter button to be there.

    I think my current record is entering a search term and then clearing it literally directly 3 times in a row, getting more and more confused each time.