Lemmy is open source, so you can easily download its source code and open it in neovim :)
Gobbel2000
The article only summarizes it shortly, but the parallels to the Munich Agreement from 1938 are really scary.
Hitler's aim was to take over all of Czechoslovakia by breaking it apart. The subject of the Munich Agreement was the Sudetenland, the region bordering Germany. Before there were some votes and local political forces expressing the wish of the German minority in the Sudetenland to create an independent state (See the parallels with DNR, LNR and Crimea). This was used by Hitler to justify taking over the region. Suddenly it wasn't about independence anymore, but about inclusion into Germany.
The Czechoslovakian government in Prague obviously hated the idea, but they were not invited to the talks in Munich. Only afterwards were they made aware of the decision that would be imposed on their nation. Who was invited was fellow fascist Mussolini from Italy, as well as France and UK, who gave in and signed this agreement, giving international support to Germany just taking over parts of neighboring nations.
Their reasoning was, if they were to disagree, Hitler would assert his will by force and take Czechoslovakia militarily, starting a large European war (that is also the reason Prague was forced to accept the decision: the alternative was a war they could never win, they could not count on any outside help). This was the so-called appeasement policy by the UK. They bought "peace" in exchange for territories they didn't own but felt the right to decide over. We all know how this heavily-priced peace turned out. At most it gave the allied forces one more year to prepare for WWII.
Reminds me of the beginning of Zelenskys presidency in 2020 when he refused the deal with Trump to investigate Hunter Biden. Trump really believes he can get Ukraine to do anything for him.
Just wait until they figure out how much carbon is captured by planting a tree.
Only if you convert rubles by "purchase power parity" as opposed to the market rate, which seems like a weird way to manipulate data to fit some narrative.
Funny idea, but good luck getting this leaky bucket from the Baltic sea all the way via Gibraltar to the Black sea.
"Fraunce" is my favorite part of this map.
Rust
Nice ending for this year. Lock and key arrays are just added together and all elements must be <= 5. Merry Christmas!
Solution
fn flatten_block(block: Vec<Vec<bool>>) -> [u8; 5] {
let mut flat = [0; 5];
for row in &block[1..=5] {
for x in 0..5 {
if row[x] {
flat[x] += 1;
}
}
}
flat
}
fn parse(input: &str) -> (Vec<[u8; 5]>, Vec<[u8; 5]>) {
let mut locks = Vec::new();
let mut keys = Vec::new();
for block_s in input.split("\n\n") {
let block: Vec<Vec<bool>> = block_s
.lines()
.map(|l| l.bytes().map(|b| b == b'#').collect::<Vec<bool>>())
.collect();
assert_eq!(block.len(), 7);
// Lock
if block[0].iter().all(|e| *e) {
locks.push(flatten_block(block));
} else {
keys.push(flatten_block(block));
}
}
(locks, keys)
}
fn part1(input: String) {
let (locks, keys) = parse(&input);
let mut count = 0u32;
for l in locks {
for k in &keys {
if l.iter().zip(k).map(|(li, ki)| li + ki).all(|sum| sum <= 5) {
count += 1;
}
}
}
println!("{count}");
}
fn part2(_input: String) {
println!("⭐");
}
util::aoc_main!();
Also on github
Rust + Pen and Paper
Yikers. Part 2 took a while, staring at this diagram for hours. Eventually I noticed that each of these blocks has two pairs of (XOR, AND) gates sharing the same inputs (and inputs aren't changed). So I matched up these pairs based on a distance metric of how much needs to be swapped to fit together. This helped me identify 4 blocks with errors, the rest was solved using pen and paper (one block is missing as it became apparent at that point):
There is also some code, but do yourself and me a favor and don't look at it. While it does turn up the correct solution, it probably won't with any other input, especially not the examples.
Rust
Finding cliques in a graph, which is actually NP-comlete. For part two I did look up how to do it and implemented the Bron-Kerbosch algorithm. Adding the pivoting optimization improved the runtime from 134ms to 7.4ms, so that is definitely worth it (in some sense, of course I already had the correct answer without pivoting).
Solution
use rustc_hash::{FxHashMap, FxHashSet};
fn parse(input: &str) -> (Vec<Vec<usize>>, FxHashMap<&str, usize>) {
let mut graph = Vec::new();
let mut names: FxHashMap<&str, usize> = FxHashMap::default();
for l in input.lines() {
let (vs, ws) = l.split_once('-').unwrap();
let v = *names.entry(vs).or_insert_with(|| {
graph.push(vec![]);
graph.len() - 1
});
let w = *names.entry(ws).or_insert_with(|| {
graph.push(vec![]);
graph.len() - 1
});
graph[v].push(w);
graph[w].push(v);
}
(graph, names)
}
fn part1(input: String) {
let (graph, names) = parse(&input);
let mut triples: FxHashSet<[usize; 3]> = FxHashSet::default();
for (_, &v) in names.iter().filter(|(name, _)| name.starts_with('t')) {
for (i, &u) in graph[v].iter().enumerate().skip(1) {
for w in graph[v].iter().take(i) {
if graph[u].contains(w) {
let mut triple = [u, v, *w];
triple.sort();
triples.insert(triple);
}
}
}
}
println!("{}", triples.len());
}
// Bron-Kerbosch algorithm for finding all maximal cliques in a graph
fn bron_kerbosch(
graph: &[Vec<usize>],
r: &mut Vec<usize>,
mut p: FxHashSet<usize>,
mut x: FxHashSet<usize>,
) -> Vec<Vec<usize>> {
if p.is_empty() && x.is_empty() {
return vec![r.to_vec()];
}
let mut maximal_cliques = Vec::new();
let Some(&u) = p.iter().next() else {
return maximal_cliques;
};
let mut p_pivot = p.clone();
for w in &graph[u] {
p_pivot.remove(w);
}
for v in p_pivot {
let pn = graph[v].iter().filter(|w| p.contains(w)).copied().collect();
let xn = graph[v].iter().filter(|w| x.contains(w)).copied().collect();
r.push(v);
let new_cliques = bron_kerbosch(graph, r, pn, xn);
r.pop();
maximal_cliques.extend(new_cliques);
p.remove(&v);
x.insert(v);
}
maximal_cliques
}
fn part2(input: String) {
let (graph, names) = parse(&input);
let p = (0..graph.len()).collect();
let mut r = Vec::new();
let maximal_cliques = bron_kerbosch(&graph, &mut r, p, FxHashSet::default());
let maximum_clique = maximal_cliques
.iter()
.max_by_key(|clique| clique.len())
.unwrap();
let mut lan_names: Vec<&str> = names
.iter()
.filter(|(_, v)| maximum_clique.contains(v))
.map(|(name, _)| *name)
.collect();
lan_names.sort_unstable();
println!("{}", lan_names.join(","));
}
util::aoc_main!();
Also on github
Glad to be able to help. This one really was a doozy.
It's the part in the video where you can see the Linux Desktop.