I can highly recommend Magic Earth as a Google Maps alternative (also available for Android). It uses OSM data and has some traffic info. It's not as good as Google, but it's the closest I've found so far.
eco_game
AFAIK you can enable the snapcast server and then use an app like SnapCast to stream to your mobile devices.
I also really liked day 17, because at one point the solution for part 2 just clicked and now it makes so much sense.
I think my favorite was the full adder on day 24. Even though I only solved part 2 manually, it was still a lot of fun to reverse an actual full adder and get familiar with all the required logic gates.
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.
::: spoiler 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
}
}
This program is a client for the very solid Tvheadend TV streaming server. Tvheadend supports pretty much any source you can think of, but is a little more complicated to setup.
Tvheadend is a selfhosted service meant to be run on your own server with your own TV dongles / IPTV channels / etc.
If you only want to watch TV on your PC, doing so with something like Kodi is probably a better idea, as Kodi also supports USB tuners and is simpler to setup (doesn't require a separate server).
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.
I really like Pop!_OS, AFAIK it doesn't have any telemetry. It's basically a Ubuntu fork but without the stupid Ubuntu stuff, and they're currently even working on their own Desktop Environment.
I also use Posteo, one thing to note though is that Posteo doesn't (and probably won't any time soon) support custom domains. If that doesn't bother you, it's a great choice.
The other alternative I found during my research, which doesn't have that limitation, is mailbox.org.
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
I actually use both apps, I find Organic Maps a lot nicer for looking at a map and navigating by foot or bike, and Magic Earth seems to pick more sensible car routes some times. Also the live traffic data makes it more fitting for car navigation (Organic Maps doesn't have traffic data).