OrangeBacon's recent activity

  1. Comment on Day 20: Jurassic Jigsaw in ~comp

    OrangeBacon
    Link
    I finally finished both parts of today's!!! woo! part 2 took a very long time lol, at least the program runs quickly. This was such a hard problem imo. Repo link:...

    I finally finished both parts of today's!!! woo! part 2 took a very long time lol, at least the program runs quickly.
    This was such a hard problem imo.
    Repo link: https://github.com/OrangeBacon/adventofcode2020/blob/main/src/days/day20.rs

    Notes: For part 1 only the edges of each tile needs to be considered, as each edge is included either once or twice, it is possible to get a single way of organising the tiles. To make the edge comparison nicer, the `#` can be replaced with `1` and `.` with `0` and then each edge can be converted to a binary number. To make the rotations easier, I read those numbers clockwise round the edge of each tile, rather than left to right. For this part, the image doesn't need to be constructed as the corners will be the tiles with two edges that are included twice. For part 2, the orientation of the image doesn't matter, so it can be started from any corner. The input is small enough that all rotations of each tile can be checked to find the correct rotation, rather than trying to find a clever way of working out the tile rotations. For finding the monster, I search through the complete image for one monster, if it is not found, i rotate the whole image, repeat for all 4 orientations, flip and repeat again, to find the one orientation and flip when one monster is found. I then search through the input for all monsters, keeping a set of all coordinates included in monsters and subtract the size of that set from the total number of `#` in the input.
    Rust part 1 + 2 (336 lines)
    use anyhow::Result;
    use libaoc::{aoc, AocResult, Timer};
    use regex::Regex;
    use std::cell::RefCell;
    use std::collections::BTreeMap;
    use hashbrown::HashSet;
    
    #[derive(Clone, Debug, Copy)]
    struct Adjacency {
        id: usize,
        side: usize,
        flip: bool,
    }
    /*
    top
    right
    bottom
    left
    */
    #[derive(Clone, Debug)]
    struct Tile {
        data: Vec<Vec<char>>,
        sides: [usize; 4],
        flip_sides: [usize; 4],
        adjacency: [Vec<Adjacency>; 4],
        rotation: usize,
        flip: bool,
    }
    
    impl Tile {
        fn get_side(&self, side: usize) -> Option<usize> {
            let mut adj = self.adjacency.to_vec();
            if self.flip {
                adj.swap(0,2);
            }
            adj.rotate_right(self.rotation);
            adj[side].get(0).and_then(|x|Some(x.id))
        }
    
        /// applies flips and rotation until side side == id
        fn set_transform(&mut self, side: usize, id: usize, side2: usize, id2: usize) {
            let mut adj = self.adjacency.to_vec();
            for i in 0..4 {
                if ((id == 0 && adj[side].len() == 0) || (adj[side].len() > 0 && adj[side][0].id == id))&&((id2 == 0 && adj[side2].len() == 0) || (adj[side2].len() > 0 && adj[side2][0].id == id2)) {
                    self.rotation = i;
                    return;
                }
                adj.rotate_right(1);
            }
            adj.swap(0,2);
            self.flip = true;
            for i in 0..4 {
                if ((id == 0 && adj[side].len() == 0) || (adj[side].len() > 0 && adj[side][0].id == id))&&((id2 == 0 && adj[side2].len() == 0) || (adj[side2].len() > 0 && adj[side2][0].id == id2)) {
                    self.rotation = i;
                    return;
                }
                adj.rotate_right(1);
            }
        }
    }
    
    #[aoc("27803643063307", "1644")]
    pub fn solve(timer: &mut Timer, input: &str) -> Result<AocResult> {
        let line = Regex::new(r"(\r?\n){2}")?;
        let input: BTreeMap<usize, _> = line
            .split(input)
            .map(|x| {
                let parts = x.split_once('\n').unwrap();
                let id = parts.0[5..=8].parse().unwrap();
                let data = parts.1.replace('.', "0").replace('#', "1");
                let data_map: Vec<_> = data.lines().collect();
                let chars = data_map.iter().skip(1).take(8).map(|x|x.chars().skip(1).take(8).collect()).collect();
    
                let top = usize::from_str_radix(data_map[0], 2).unwrap();
                let right = usize::from_str_radix(
                    &data_map
                        .iter()
                        .map(|x| x.chars().rev().next().unwrap())
                        .collect::<String>(),
                    2,
                )
                .unwrap();
                let bottom = usize::from_str_radix(
                    &data_map[data_map.len() - 1]
                        .chars()
                        .rev()
                        .collect::<String>(),
                    2,
                )
                .unwrap();
                let left = usize::from_str_radix(
                    &data_map
                        .iter()
                        .rev()
                        .map(|x| x.chars().next().unwrap())
                        .collect::<String>(),
                    2,
                )
                .unwrap();
    
                let top_flip = usize::from_str_radix(&data_map[0].chars().rev().collect::<String>(), 2).unwrap();
                let right_flip = usize::from_str_radix(
                    &data_map
                        .iter().rev()
                        .map(|x| x.chars().rev().next().unwrap())
                        .collect::<String>(),
                    2,
                )
                .unwrap();
                let bottom_flip = usize::from_str_radix(
                    &data_map[data_map.len() - 1]
                        .chars()
                        .collect::<String>(),
                    2,
                )
                .unwrap();
                let left_flip = usize::from_str_radix(
                    &data_map
                        .iter()
                        .map(|x| x.chars().next().unwrap())
                        .collect::<String>(),
                    2,
                )
                .unwrap();
    
                (
                    id,
                    RefCell::new(Tile {
                        data: chars,
                        sides: [top, right, bottom, left],
                        flip_sides: [top_flip, right_flip, bottom_flip, left_flip],
                        adjacency: [vec![], vec![], vec![], vec![]],
                        rotation: 0,
                        flip: false,
                    }),
                )
            })
            .collect();
    
        timer.lap("Parse");
    
        for (&id, image) in &input {
            let mut adjacency = [vec![], vec![], vec![], vec![]];
            for (side_id, &side) in image.borrow().sides.iter().enumerate() {
                for (&test_id, test_image) in &input {
                    if test_id == id {continue;}
                    for (test_side_id, &test_side) in test_image.borrow().sides.iter().enumerate() {
                        if side == test_side {
                            adjacency[side_id].push(Adjacency {
                                id: test_id,
                                side: test_side_id+2,
                                flip: false,
                            })
                        }
                        if image.borrow().flip_sides[side_id] == test_side {
                            adjacency[side_id].push(Adjacency {
                                id: test_id,
                                side: test_side_id,
                                flip: true,
                            })
                        }
                    }
                }
            }
            image.borrow_mut().adjacency = adjacency;
        }
    
        // it apears that adjacency lists contain either 0 or 1 adjacency, which
        // makes things significantly easier assuming this holds
    
        let adjacency_sums:Vec<_> = input.iter().map(|(&id, x)| {
            (id, x.borrow().adjacency.iter().map(|x|x.len()).sum::<usize>())
        }).collect();
    
        let part1 = adjacency_sums.iter().fold(1, |acc, (id, val)| {
            if *val == 2 {
                acc * id
            } else {
                acc
            }
        });
    
        timer.lap("Part 1");
    
        let image_size = (input.len() as f32).sqrt() as usize;
        let mut image = vec![vec![0usize; image_size]; image_size];
    
        // first cell
        image[0][0] = adjacency_sums.iter().filter(|(_,v)|*v==2).next().unwrap().0;
        input[&image[0][0]].borrow_mut().set_transform(0, 0, 3, 0);
    
        // first row
        for i in 1..image_size {
            let left = image[0][i-1];
            let new_id = input[&left].borrow().get_side(1).unwrap();
            image[0][i] = new_id;
            input[&new_id].borrow_mut().set_transform(0, 0, 3, left);
        }
    
        // first column
        for i in 1..image_size {
            let above = image[i-1][0];
            let new_id = input[&above].borrow().get_side(2).unwrap();
            image[i][0] = new_id;
            input[&new_id].borrow_mut().set_transform(0, above, 3, 0);
        }
    
        // other cells
        for col in 1..image_size {
            for row in 1..image_size {
                let above = image[row-1][col];
                let left = image[row][col-1];
                let new_id = input[&above].borrow().get_side(2).unwrap();
                image[row][col] = new_id;
                input[&new_id].borrow_mut().set_transform(0, above, 3, left);
            }
        }
    
        for tile in input.values() {
            let mut tile = tile.borrow_mut();
            if tile.flip {
                tile.data.reverse();
            }
    
            for _ in 0..tile.rotation {
                let mut new = vec![vec![]; 8];
                for col in 0..8 {
                    for row in (0..8).rev() {
                        new[col].push(tile.data[row][col]);
                    }
                }
                tile.data = new;
            }
        }
    
        let mut i = vec![];
        for row in &image {
            for tile_row in 0..8 {
                let mut row_str: Vec<char> = vec![];
                for tile in row {
                    row_str.extend(input[&tile].borrow().data[tile_row].iter());
                }
                i.push(row_str);
            }
        }
    
        fn check_monster(i: &[Vec<char>], quick_exit: bool, found_set: &mut HashSet<(usize, usize)>) -> i32 {
            let mut count = 0;
            for r in 0..(i.len() - 2) {
                for c in 0..(i.len()-19) {
                    //                   #
                    // #    ##    ##    ###
                    //  #  #  #  #  #  #
                    let monster = [
                        (r,c+18),
                        (r+1,c),
                        (r+1,c+5),
                        (r+1,c+6),
                        (r+1,c+11),
                        (r+1,c+12),
                        (r+1,c+17),
                        (r+1,c+18),
                        (r+1,c+19),
                        (r+2,c+1),
                        (r+2,c+4),
                        (r+2,c+7),
                        (r+2,c+10),
                        (r+2,c+13),
                        (r+2,c+16),
                    ];
                    let is_monster = monster.iter().all(|&(r,c)|i[r][c]=='1');
                    if is_monster && quick_exit {
                        return 1;
                    }
                    if is_monster {
                        count += 1;
                        for coord in &monster {
                            found_set.insert(*coord);
                        }
                    }
                }
            }
    
            count
        }
    
        'out: loop {
            for _ in 0..4 {
                if check_monster(&i, true, &mut HashSet::new()) > 0 {
                    break 'out;
                }
    
                let mut new = vec![vec![]; i.len()];
                for col in 0..i.len() {
                    for row in (0..i.len()).rev() {
                        new[col].push(i[row][col]);
                    }
                }
                i = new;
            }
            i.reverse();
            for _ in 0..4 {
                if check_monster(&i, true, &mut HashSet::new()) > 0 {
                    break 'out;
                }
    
                let mut new = vec![vec![]; i.len()];
                for col in 0..i.len() {
                    for row in (0..i.len()).rev() {
                        new[col].push(i[row][col]);
                    }
                }
                i = new;
            }
    
            break 'out;
        }
    
        let ones = i.iter().fold(0, |acc, row| {
            acc + row.iter().fold(0, |acc, tile| {
                if *tile == '1' {
                    acc + 1
                } else {
                    acc
                }
            })
        });
    
        let mut found_set = HashSet::new();
        check_monster(&i, false, &mut found_set);
        let part2 = ones - found_set.len();
    
        timer.lap("Part 2");
    
        Ok(AocResult::new(part1, part2))
    }
    
    3 votes
  2. Comment on Day 19: Monster Messages in ~comp

    OrangeBacon
    Link
    Today's one, used regexes for both parts, compiled the input into a tree and then executed it, had to move from rust regex to pcre2 for pt 2. I kinda enjoyed this, was interesting to learn about...

    Today's one, used regexes for both parts, compiled the input into a tree and then executed it, had to move from rust regex to pcre2 for pt 2. I kinda enjoyed this, was interesting to learn about new regex features.
    Runs in around 10ms for parsing and both parts
    Repo link: https://github.com/OrangeBacon/adventofcode2020/blob/main/src/days/day19.rs

    Rust code
    use anyhow::Result;
    use hashbrown::HashMap;
    use libaoc::{aoc, AocResult, Timer};
    use pcre2::bytes::Regex as RegexPcre2;
    use regex::Regex;
    use std::fmt::{self, Write};
    
    #[derive(Clone, Copy, Debug)]
    enum RuleType {
        One(usize),
        Two(usize, usize),
        OneOne(usize, usize),
        TwoTwo(usize, usize, usize, usize),
        Letter(char),
        Rule8(usize),
        Rule11(usize, usize),
    }
    
    impl RuleType {
        fn to_regex(
            self,
            out: &mut String,
            rules: &HashMap<usize, RuleType>,
        ) -> Result<(), fmt::Error> {
            use RuleType::*;
    
            match self {
                Letter(a) => write!(out, "{}", a),
                One(a) => rules[&a].to_regex(out, rules),
                Two(a, b) => {
                    rules[&a].to_regex(out, rules)?;
                    rules[&b].to_regex(out, rules)
                }
                OneOne(a, b) => {
                    write!(out, "(?:(")?;
                    rules[&a].to_regex(out, rules)?;
                    write!(out, ")|(?:")?;
                    rules[&b].to_regex(out, rules)?;
                    write!(out, "))")
                }
                TwoTwo(a, b, c, d) => {
                    write!(out, "(?:(?:")?;
                    rules[&a].to_regex(out, rules)?;
                    rules[&b].to_regex(out, rules)?;
                    write!(out, ")|(?:")?;
                    rules[&c].to_regex(out, rules)?;
                    rules[&d].to_regex(out, rules)?;
                    write!(out, "))")
                }
                Rule8(a) => {
                    write!(out, "(?:")?;
                    rules[&a].to_regex(out, rules)?;
                    write!(out, ")+")
                }
                Rule11(a, b) => {
                    write!(out, "(?<rule11>(?:")?;
                    rules[&a].to_regex(out, rules)?;
                    rules[&b].to_regex(out, rules)?;
                    write!(out, ")|(?:")?;
                    rules[&a].to_regex(out, rules)?;
                    write!(out, "(?&rule11)")?;
                    rules[&b].to_regex(out, rules)?;
                    write!(out, "))")
                }
            }
        }
    
        fn from_str(x: &str) -> (usize, Self) {
            use RuleType::*;
    
            let parts = x.split_once(':').unwrap();
            let left = parts.0.parse().unwrap();
            let right = parts.1.split('|');
            let right: Vec<Vec<(&str, Result<usize, _>)>> = right
                .map(|x| x.trim().split(' ').map(|x| (x, x.parse())).collect())
                .collect();
    
            let kind = match right.len() {
                1 => match right[0].len() {
                    2 => Two(
                        *(right[0][0].1.as_ref().unwrap()),
                        *(right[0][1].1.as_ref().unwrap()),
                    ),
                    1 => {
                        if let Ok(num) = right[0][0].1 {
                            One(num)
                        } else {
                            Letter(right[0][0].0.chars().nth(1).unwrap())
                        }
                    }
                    _ => panic!(),
                },
                2 => match right[0].len() {
                    1 => OneOne(
                        *(right[0][0].1.as_ref().unwrap()),
                        *(right[1][0].1.as_ref().unwrap()),
                    ),
                    2 => TwoTwo(
                        *(right[0][0].1.as_ref().unwrap()),
                        *(right[0][1].1.as_ref().unwrap()),
                        *(right[1][0].1.as_ref().unwrap()),
                        *(right[1][1].1.as_ref().unwrap()),
                    ),
                    _ => panic!(),
                },
                _ => panic!(),
            };
    
            (left, kind)
        }
    }
    
    #[aoc("250", "359")]
    pub fn solve(timer: &mut Timer, input: &str) -> Result<AocResult> {
        let line = Regex::new(r"(\r?\n){2}")?;
        let input: Vec<_> = line.split(input).collect();
    
        let mut rules: HashMap<usize, RuleType> = input[0].lines().map(RuleType::from_str).collect();
    
        timer.lap("Parse");
    
        let mut reg = String::new();
        write!(reg, "^(?:")?;
        rules[&0].to_regex(&mut reg, &rules)?;
        write!(reg, ")$")?;
        let reg = Regex::new(&reg)?;
    
        let part1 = input[1].lines().fold(
            0,
            |acc, line| {
                if reg.is_match(line) {
                    acc + 1
                } else {
                    acc
                }
            },
        );
    
        timer.lap("Part 1");
    
        rules.insert(8, RuleType::Rule8(42));
        rules.insert(11, RuleType::Rule11(42, 31));
    
        let mut reg = String::new();
        write!(reg, "^(?:")?;
        rules[&0].to_regex(&mut reg, &rules)?;
        write!(reg, ")$")?;
    
        let reg = RegexPcre2::new(&reg)?;
    
        let part2 = input[1].lines().fold(0, |acc, line| {
            if reg.is_match(&line.bytes().collect::<Vec<u8>>()).unwrap() {
                acc + 1
            } else {
                acc
            }
        });
    
        timer.lap("Part 2");
    
        Ok(AocResult::new(part1, part2))
    }
    
    3 votes
  3. Comment on Day 7: Handy Haversacks in ~comp

    OrangeBacon
    Link
    Rust This one seemed much harder than the previous days. I spent a while fighting the borrow checker/learning how to use rc + refcell to get the compiler to be happy. Repo link Solution to both...

    Rust

    This one seemed much harder than the previous days. I spent a while fighting the borrow checker/learning how to use rc + refcell to get the compiler to be happy.

    Repo link

    Solution to both parts
    use regex::Regex;
    use std::cell::RefCell;
    use std::collections::HashMap;
    use std::rc::Rc;
    
    #[derive(Debug, Clone)]
    struct Bag {
        name: String,
        contains: Vec<(u32, Rc<RefCell<Bag>>)>,
    }
    
    pub fn day07(input: String) {
        let mut bags: HashMap<String, Rc<RefCell<Bag>>> = HashMap::new();
    
        let input: Vec<Vec<_>> = input
            .lines()
            .map(|x| x.split("contain").collect())
            .collect();
    
        let remove_bag_suffix = Regex::new(r" (bag|bags)\.*$").unwrap();
    
        for line in input {
            let name = remove_bag_suffix.replace(line[0].trim(), "");
            let contains: Vec<_> = line[1]
                .split(",")
                .map(|x| remove_bag_suffix.replace(x.trim(), ""))
                .collect();
            let contains = contains
                .iter()
                .map(|x| x.splitn(2, " ").collect::<Vec<_>>())
                .map(|x| {
                    if x[0] == "no" {
                        None
                    } else {
                        Some((x[0].parse::<u32>().unwrap(), x[1]))
                    }
                })
                .filter(|&x| x != None)
                .map(|x| x.unwrap())
                .map(|(num, x)| {
                    let bag = if bags.contains_key(&String::from(x)) {
                        bags.get(&String::from(x)).unwrap().clone()
                    } else {
                        bags.insert(
                            String::from(x),
                            Rc::new(RefCell::new(Bag {
                                name: String::from(x),
                                contains: vec![],
                            })),
                        );
                        bags.get(&String::from(x)).unwrap().clone()
                    };
                    (num, bag)
                })
                .collect::<Vec<_>>();
    
            let bag = if bags.contains_key(&String::from(name.clone())) {
                bags.get(&String::from(name)).unwrap().clone()
            } else {
                bags.insert(
                    String::from(name.clone()),
                    Rc::new(RefCell::new(Bag {
                        name: String::from(name.clone()),
                        contains: vec![],
                    })),
                );
                bags.get(&String::from(name)).unwrap().clone()
            };
    
            bag.borrow_mut().contains = contains;
        }
    
        fn find_recurse(bag: Rc<RefCell<Bag>>) -> bool {
            bag.borrow().contains.iter().fold(false, |acc, val| {
                acc | (val.1.borrow().name == "shiny gold")
                    | (find_recurse(Rc::new(RefCell::new(val.1.borrow().clone()))))
            })
        }
    
        let res = bags.iter().fold(0, |acc, (_, bag)| {
            if find_recurse(bag.clone()) {
                acc + 1
            } else {
                acc
            }
        });
    
        println!("{}", res);
    
        fn count_recurse(bag: Rc<RefCell<Bag>>) -> u32 {
            bag.borrow().contains.iter().fold(1, |acc, val| {
                acc + val.0 * count_recurse(Rc::new(RefCell::new(val.1.borrow().clone())))
            })
        }
    
        let res = Rc::new(RefCell::new(
            bags.get("shiny gold").unwrap().borrow().clone(),
        ));
    
        println!("{}", count_recurse(res) - 1);
    }
    
    2 votes
  4. Comment on Day 5: Binary Boarding in ~comp

    OrangeBacon
    Link
    My solution in rust: Was fun to do, was expecting something much harder given that it is Saturday. Link to the repository, including test runner main.rs use std::cmp::{max}; pub fn day05(input:...

    My solution in rust:
    Was fun to do, was expecting something much harder given that it is Saturday.

    Link to the repository, including test runner

    main.rs
    use std::cmp::{max};
    
    pub fn day05(input: String) {
        let lines : Vec<_> = input.lines().collect();
    
        let mut highest = 0;
    
        let mut seats = [[(false, 0); 8]; 128];
    
        for line in lines {
            let mut row = 0;
            let mut col = 0;
            let mut row_size = 128;
            let mut col_size = 8;
            for c in line.chars() {
                match c {
                    'F' => row_size /= 2,
                    'B' => { // upper
                        row += row_size;
                        row_size /= 2;
                    }
                    'R' => { // upper
                        col += col_size;
                        col_size /= 2;
                    }
                    'L' => col_size /= 2,
                    _ => panic!()
                }
            }
            seats[row/2][col/2] = (true, row/2 * 8 + col/2);
            highest = max(highest, row/2 * 8 + col/2);
        }
    
        let mut found = false;
        let mut id = 0;
        'out: for (y, row) in seats.iter().enumerate() {
            if !found {
                for seat in row.iter() {
                    if (*seat).0 {
                        found = true;
                    }
                }
            } else {
                for (x, seat) in row.iter().enumerate() {
                    if !(*seat).0 {
                        id = y * 8 + x;
                        break 'out;
                    }
                }
            }
        }
    
        println!("{}", highest);
        println!("{}", id);
    }
    
    3 votes
  5. Comment on Day 6: Universal Orbit Map in ~comp

    OrangeBacon
    Link
    Been doing it in rust this year, all solutions so far on my github. I feel like my code is really quite messy and probably could have benefited from a proper graph library, rather than a hashmap...

    Been doing it in rust this year, all solutions so far on my github.

    I feel like my code is really quite messy and probably could have benefited from a proper graph library, rather than a hashmap of node => value and having the edges as vec[(start, end)].

    Part 1
    use std::error::Error;
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::Path;
    use indexmap::IndexMap;
    
    pub fn day6a() {
        let path = Path::new("data/day6.txt");
        let display = path.display();
    
        let mut file = match File::open(&path) {
            Err(why) => panic!("Couldn't open {}: {}", display, why.description()),
            Ok(file) => file,
        };
    
        let mut s = String::new();
        match file.read_to_string(&mut s) {
            Err(why) => panic!("Couldn't read {}: {}", display, why.description()),
            Ok(_) => {}
        }
    
        let mut nodes: IndexMap<&str, usize> = IndexMap::new();
        let mut edges: Vec<(usize, usize)> = vec![];
        for line in s.lines() {
            let parts: Vec<&str> = line.split(")").collect();
            if !nodes.contains_key(parts[0]) {
                nodes.insert(parts[0], 0);
            }
            let index1 = nodes.get_full(parts[0]).unwrap().0;
            if !nodes.contains_key(parts[1]) {
                nodes.insert(parts[1], 0);
            }
            let index2 = nodes.get_full(parts[1]).unwrap().0;
            edges.push((index1, index2));
        }
    
        let root = nodes.get_full("COM").unwrap().0;
        let mut to_scan = vec![root];
        while to_scan.len() > 0 {
            let node_index = to_scan.pop().unwrap();
            let node_value = *nodes.get_index(node_index).unwrap().1;
            for edge in &edges {
                if edge.0 == node_index {
                    to_scan.push(edge.1);
                    let x = nodes.get_index_mut(edge.1).unwrap().1;
                    *x = node_value + 1;
                }
            }
        }
    
        let mut count = 0;
        for node in &nodes {
            count += node.1
        }
    
        println!("{}", count);
    }
    
    Part 2
    use std::error::Error;
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::Path;
    use indexmap::IndexMap;
    use std::collections::HashSet;
    
    pub fn day6b() {
        let path = Path::new("data/day6.txt");
        let display = path.display();
    
        let mut file = match File::open(&path) {
            Err(why) => panic!("Couldn't open {}: {}", display, why.description()),
            Ok(file) => file,
        };
    
        let mut s = String::new();
        match file.read_to_string(&mut s) {
            Err(why) => panic!("Couldn't read {}: {}", display, why.description()),
            Ok(_) => {}
        }
    
        let mut nodes: IndexMap<&str, usize> = IndexMap::new();
        let mut edges: Vec<(usize, usize)> = vec![];
        for line in s.lines() {
            let parts: Vec<&str> = line.split(")").collect();
            if !nodes.contains_key(parts[0]) {
                nodes.insert(parts[0], 0);
            }
            let index1 = nodes.get_full(parts[0]).unwrap().0;
            if !nodes.contains_key(parts[1]) {
                nodes.insert(parts[1], 0);
            }
            let index2 = nodes.get_full(parts[1]).unwrap().0;
            edges.push((index1, index2));
        }
    
        let get_path = |start: usize, end: usize| {
            let mut current = start;
            let mut ret: HashSet<usize> = HashSet::new();
            ret.insert(current);
            while current != end {
                for edge in &edges {
                    if edge.1 == current {
                        current = edge.0;
                        break;
                    }
                }
                ret.insert(current);
            }
            ret
        };
    
        let you_path = get_path(nodes.get_full("YOU").unwrap().0, nodes.get_full("COM").unwrap().0);
        let san_path = get_path(nodes.get_full("SAN").unwrap().0, nodes.get_full("COM").unwrap().0);
    
        println!("{}", you_path.symmetric_difference(&san_path).count() - 2);
    }
    
    3 votes
  6. Comment on Daily Tildes discussion - minor group updates in ~tildes.official

    OrangeBacon
    Link
    I think that there isn't really a need for new groups, a lot of topics have places and there is always ~misc for other things. I think it would be good not to create any more new groups for a now,...

    I think that there isn't really a need for new groups, a lot of topics have places and there is always ~misc for other things. I think it would be good not to create any more new groups for a now, to allow more people to join so the are enough people to keep all the groups active.

    19 votes
  7. Comment on What's on everyone's mind today? in ~talk

    OrangeBacon
    Link Parent
    AQA for me, I don't know how it compares with OCR, though I imagine they are roughly similar

    AQA for me, I don't know how it compares with OCR, though I imagine they are roughly similar

  8. Comment on Covers that you love much more than the originals in ~music

    OrangeBacon
    Link
    Disturbed's cover of the sound of silence by Simon and Garfunkel is mine, I prefer the lower octave, it makes it easier to sing along to!

    Disturbed's cover of the sound of silence by Simon and Garfunkel is mine, I prefer the lower octave, it makes it easier to sing along to!

    5 votes
  9. Comment on What's on everyone's mind today? in ~talk

    OrangeBacon
    Link
    I have a physics exam for my A-levels tomorrow and I am really nervous for it, I hadn't studied any of the content for a year until last week and I am finding it hard to remember it all.

    I have a physics exam for my A-levels tomorrow and I am really nervous for it, I hadn't studied any of the content for a year until last week and I am finding it hard to remember it all.

    13 votes
  10. Comment on <deleted topic> in ~tv

    OrangeBacon
    Link
    I really like ethoslab, he mainly posts minecraft videos and is very good at redstone / I like how his chanel is more technical rather than design based

    I really like ethoslab, he mainly posts minecraft videos and is very good at redstone / I like how his chanel is more technical rather than design based

    9 votes
  11. Comment on A minor suggestion regarding voting and karma in ~tildes

    OrangeBacon
    Link
    I agree that I am glad that ~ does not use reddit's karma system and think that post made is an alright metric, however it could lead to lots of low quality short posts for a different sort of...

    I agree that I am glad that ~ does not use reddit's karma system and think that post made is an alright metric, however it could lead to lots of low quality short posts for a different sort of meaningless Internet points.

    I think it might be better if no number is actually visible. Instead, possibly a number acessible to the server, not any user, which should help to discourage low effirt/quality posts. I am not sure what should be used for this, @Deimos has already written about a reputation system so this might be what is needed?

    9 votes
  12. Comment on What hobby do you wish you could do but can't? in ~hobbies

    OrangeBacon
    Link
    Something I have been wanting to get in to is electronics, making circuits, etc. I would love to eventually make a custom computer from logic gates. I imagine it would be very satisfying to see a...

    Something I have been wanting to get in to is electronics, making circuits, etc. I would love to eventually make a custom computer from logic gates. I imagine it would be very satisfying to see a pile of chips I made and designed run a program!

    8 votes
  13. Comment on Where are you from? in ~talk

    OrangeBacon
    Link
    UK for me, near London, only a 20min train journey! I live in a small ish town though (~36,000), there are lots of fields nearby!

    UK for me, near London, only a 20min train journey!
    I live in a small ish town though (~36,000), there are lots of fields nearby!

    1 vote
  14. Comment on Repost check in ~tildes

    OrangeBacon
    Link Parent
    I totally agree, I think that that time for the repost check to come off should help to ensure that the content is not on here all the time, however new users still get to see it as they might not...

    I totally agree, I think that that time for the repost check to come off should help to ensure that the content is not on here all the time, however new users still get to see it as they might not recognise it as a repost.

    3 votes
  15. Comment on Write a ~ story! in ~creative

    OrangeBacon
    Link Parent
    Well, it all started when I was walking down the high street to get a new pen, then I saw her in a shop.

    Well, it all started when I was walking down the high street to get a new pen, then I saw her in a shop.

    3 votes