Bauke's recent activity

  1. Comment on Is there a way to globally switch out a word in ~comp

    Bauke
    Link
    A few years ago I was looking for the same thing and came across FoxReplace (Firefox only) which I found to be good enough. There's probably something similar for <your favorite browser> if it...

    A few years ago I was looking for the same thing and came across FoxReplace (Firefox only) which I found to be good enough. There's probably something similar for <your favorite browser> if it isn't Firefox.

    6 votes
  2. Comment on Fortnightly Programming Q&A Thread in ~comp

    Bauke
    (edited )
    Link Parent
    If you're willing to write everything from scratch you don't really need any external libraries to accomplish what you're trying to do, so I'll just give some general pointers and links to native...

    If you're willing to write everything from scratch you don't really need any external libraries to accomplish what you're trying to do, so I'll just give some general pointers and links to native JS functionality that I would use if I was making this.

    To start you'd need to get the JSON data somehow, the likely option here would be fetch(), where await (await fetch('episodes.json')).json() would get you your episodes array already parsed into JS (note that this is async).

    Then to create the table on the page Element.insertAdjacentHTML() is what you'd want. For example to insert a div as the last element of the body, document.body.insertAdjacentHTML('beforeend', '<div></div>'); would do the trick. And you can put anything in there with template literals or good old concatenating strings like 'a' + 'b'.

    Since insertAdjacentHTML is defined on any Element, you'd want to use document.querySelector to grab either a pre-made table element or the parent (or sibling) element you want to insert the table next to.

    If you do however want to use external libraries like from npm, I'd recommend using Vite to build your website. I don't have the required vocabulary to explain how much of a clusterfuck importing code is in JS and in my experience Vite is pretty easy to use and makes it a lot less painful.

    4 votes
  3. Comment on Dylan Cartlidge - Yellow Brick Road (2020) in ~music

    Bauke
    Link Parent
    I don't know if searching for a video and picking the first result would be a good solution, I think there would be too high a chance that you don't get what you're looking for. Maybe a better...

    I don't know if searching for a video and picking the first result would be a good solution, I think there would be too high a chance that you don't get what you're looking for.

    Maybe a better option would be to check if there is a regular YouTube link in the links and then embed that? At least then it'll be a lot more accurate and it could also be done for other platforms like SoundCloud and Bandcamp.

    1 vote
  4. Comment on What do you think about this potential alternative to Odesli/Song.link? in ~music

    Bauke
    Link Parent
    I'd want to keep it as short as possible, so probably href.plus over audiohref.plus but other variations with "audio"/"song"/"music"/... could work too.

    I'd want to keep it as short as possible, so probably href.plus over audiohref.plus but other variations with "audio"/"song"/"music"/... could work too.

    2 votes
  5. Comment on What do you think about this potential alternative to Odesli/Song.link? in ~music

    Bauke
    Link
    I added a simple search bar to the site yesterday and just finished some basic explaining info on the home page, hopefully that'll make it easier to understand what's going on and how to use it. I...

    I added a simple search bar to the site yesterday and just finished some basic explaining info on the home page, hopefully that'll make it easier to understand what's going on and how to use it.

    I was also wondering if anyone here had any ideas for a better name, since I just picked "blink" on a whim (brainz link, get it, terrible :P). The main one I'm thinking of right now is href+ (with the href.plus domain). Short, kind of unique and has to do with linking stuff, and has the potential in the future to be used for more than just linking to music (wink wink @Amarok).

    Anyways, let me know what you think, the positive response has been great! ๐Ÿ˜Š

    4 votes
  6. Comment on What do you think about this potential alternative to Odesli/Song.link? in ~music

    Bauke
    (edited )
    Link Parent
    Ooh, that's a good idea! Edit: It has been added. :)

    Ooh, that's a good idea!

    Edit: It has been added. :)

    1 vote
  7. Comment on What do you think about this potential alternative to Odesli/Song.link? in ~music

    Bauke
    Link Parent
    There will be some usage info on the home page soon but in short: you have to get a MusicBrainz Identifier (mbid) of a release somehow (I'm working on adding search to the website right now) and...

    There will be some usage info on the home page soon but in short: you have to get a MusicBrainz Identifier (mbid) of a release somehow (I'm working on adding search to the website right now) and then put it in https://blink.bauke.xyz/release/<mbid>. Then going to that website will show you the links for that release, for example.

    3 votes
  8. Comment on What do you think about this potential alternative to Odesli/Song.link? in ~music

    Bauke
    Link
    There is now a very basic version available at https://blink.bauke.xyz, it works like the original post describes but I'll be working on adding the other things @cfabbro mentioned and also usage...
    • Exemplary

    There is now a very basic version available at https://blink.bauke.xyz, it works like the original post describes but I'll be working on adding the other things @cfabbro mentioned and also usage information on the home page.

    7 votes
  9. Comment on What do you think about this potential alternative to Odesli/Song.link? in ~music

    Bauke
    Link Parent
    Yeah it would be like a frontend that just shows you the links and whatever other information is useful. I could add search directly on the website too, there's an API for that, but it would take...

    Yeah it would be like a frontend that just shows you the links and whatever other information is useful.

    I could add search directly on the website too, there's an API for that, but it would take a bit longer to figure out.

    Optimistically I think I could replicate song.link's functionality almost entirely, with the exception of being able to add songs/albums, that you'd have to do yourself through the MusicBrainz interface.

    4 votes
  10. What do you think about this potential alternative to Odesli/Song.link?

    Once upon a time we used to use Odesli/Song.link links pretty frequently here on Tildes so people could play the music through whatever supported platform that music was on, but then they changed...

    Once upon a time we used to use Odesli/Song.link links pretty frequently here on Tildes so people could play the music through whatever supported platform that music was on, but then they changed their name and usage of it mostly faded out (at least on Tildes).

    So the other day I was looking through MusicBrainz releases and I noticed that you can add external links to them that link to various other places, and it dawned on me that you could essentially make a collaborative alternative to Odesli using MusicBrainz as the database. I've spent a little bit of time looking through the MetaBrainz APIs and everything this would require can be accessed through it primarily song data, external links and cover art.

    The general usage of it would be you simply use the MusicBrainz search, navigate to the release you want and then replace the musicbrainz.org with alternative.whatever.

    So here comes my question, what do you think about this idea and would you use it if it existed?

    8 votes
  11. Comment on Liquicity Drum & Bass Yearmix 2021 (Mixed by Maduk) in ~music

    Bauke
    Link Parent
    Hahaha, oops. I forgot there was a setting that displays them all. :P

    Hahaha, oops. I forgot there was a setting that displays them all. :P

    5 votes
  12. Comment on Liquicity Drum & Bass Yearmix 2021 (Mixed by Maduk) in ~music

    Bauke
    Link
    The 10th Liquicity yearmix has arrived with some of the best drum & bass music from 2021.

    The 10th Liquicity yearmix has arrived with some of the best drum & bass music from 2021.

    1 vote
  13. Comment on What will prevent this site from becoming Reddit 2.0? in ~tildes

    Bauke
    Link Parent
    Here are the numbers for ~tildes.official subscribers every 30 days. Looks something like 20-40 new people each month. Data tildes-stats=# select (snapshot_id, subscribers) from group_datas where...

    Here are the numbers for ~tildes.official subscribers every 30 days. Looks something like 20-40 new people each month.

    Data
    tildes-stats=# select (snapshot_id, subscribers) from group_datas where name = 'tildes.official' and snapshot_id % 30 = 0;
         row     
    -------------
     (30,11990)
     (60,12135)
     (90,12188)
     (120,12221)
     (150,12274)
     (180,12317)
     (210,12358)
     (240,12427)
     (270,12471)
     (300,12501)
     (330,12537)
     (360,12560)
     (390,12602)
     (420,12621)
     (450,12651)
     (480,12655)
     (510,12657)
    
    6 votes
  14. Comment on Day 19: Beacon Scanner in ~comp.advent_of_code

    Bauke
    Link
    Potential spoilers about the puzzle but a question I have Computerphile did a video on iterative closest point a few days ago and when reading the puzzle I remembered it and wondered whether that...
    Potential spoilers about the puzzle but a question I have

    Computerphile did a video on iterative closest point a few days ago and when reading the puzzle I remembered it and wondered whether that kind of algorithm is what you should be using to solve this?

    2 votes
  15. Comment on Day 15: Chiton in ~comp.advent_of_code

    Bauke
    Link
    I decided to use the pathfinding crate because I didn't want to figure all that out myself, so today's puzzle for me was mostly figuring out how I need to set everything up to use the A*...

    I decided to use the pathfinding crate because I didn't want to figure all that out myself, so today's puzzle for me was mostly figuring out how I need to set everything up to use the A* implementation. Thankfully they have excellent documentation.

    Runtime
    Day 15 Part 1: 386
    Day 15 Part 2: 2806
    - Runtime: 157.77425ms
    
    Imports and setup
    use std::collections::HashMap;
    
    use color_eyre::{eyre::eyre, Result};
    use pathfinding::prelude::{absdiff, astar};
    
    pub fn solve() -> Result<()> {
      let input_data = include_str!("../../data/day_15.txt").trim();
      println!("Day 15 Part 1: {}", part_1(input_data)?);
      println!("Day 15 Part 2: {}", part_2(input_data)?);
      Ok(())
    }
    
    Setting up the grid and pathfinding

    This code is almost verbatim the example from the documentation.

    type Grid = HashMap<Coordinate, isize>;
    
    #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
    struct Coordinate(isize, isize);
    
    impl Coordinate {
      fn distance(&self, target: &Coordinate) -> isize {
        absdiff(self.0, target.0) + absdiff(self.1, target.1)
      }
    
      fn successors(&self, grid: &Grid) -> Vec<(Coordinate, isize)> {
        let &Coordinate(x, y) = self;
        let mut successors = vec![];
    
        for coordinate in [
          Coordinate(x, y - 1), // Up
          Coordinate(x - 1, y), // Left
          Coordinate(x, y + 1), // Down
          Coordinate(x + 1, y), // Right
        ] {
          if let Some(value) = grid.get(&coordinate) {
            successors.push((coordinate, *value));
          }
        }
    
        successors
      }
    }
    
    Parsing the grid
    fn parse(input: &str) -> Result<(Grid, Coordinate)> {
      let mut grid = Grid::new();
      let mut end = Coordinate(0, 0);
    
      for (y, line) in input.lines().enumerate() {
        let y = (y + 1).try_into()?;
    
        for (x, character) in line.char_indices() {
          let x = (x + 1).try_into()?;
          grid.insert(Coordinate(x, y), character.to_string().parse()?);
    
          if end.0 < x && end.1 < y {
            end = Coordinate(x, y);
          }
        }
      }
    
      Ok((grid, end))
    }
    
    fn enlarge_grid(grid: Grid, end: Coordinate) -> (Grid, Coordinate) {
      let Coordinate(width, height) = end;
      let mut larger_grid = grid.clone();
    
      for (Coordinate(x, y), risk) in grid {
        for step_x in 0..5 {
          for step_y in 0..5 {
            let risk = match (risk + step_x + step_y) % 9 {
              0 => 9,
              n => n,
            };
            let x = x + (width * step_x);
            let y = y + (height * step_y);
            larger_grid.insert(Coordinate(x, y), risk);
          }
        }
      }
    
      (larger_grid, Coordinate(width * 5, height * 5))
    }
    
    Solving both parts
    fn run(grid: Grid, end: Coordinate) -> Result<isize> {
      Ok(
        astar(
          &Coordinate(1, 1),
          |p| p.successors(&grid),
          |p| p.distance(&end),
          |p| p == &end,
        )
        .ok_or_else(|| eyre!("No path found"))?
        .1,
      )
    }
    
    fn part_1(input: &str) -> Result<isize> {
      let (grid, end) = parse(input)?;
      run(grid, end)
    }
    
    fn part_2(input: &str) -> Result<isize> {
      let (grid, end) = parse(input)?;
      let (grid, end) = enlarge_grid(grid, end);
      run(grid, end)
    }
    
    3 votes
  16. Comment on Day 13: Transparent Origami in ~comp.advent_of_code

    Bauke
    Link
    Runtime Day 13 Part 1: 712 Day 13 Part 2: โ–ˆโ–ˆโ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆโ–ˆโ–ˆโ–ˆ โ–ˆโ–ˆ โ–ˆโ–ˆโ–ˆ โ–ˆโ–ˆ โ–ˆโ–ˆโ–ˆโ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆโ–ˆโ–ˆ โ–ˆ โ–ˆโ–ˆโ–ˆโ–ˆ โ–ˆโ–ˆโ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆโ–ˆโ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆโ–ˆโ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆโ–ˆโ–ˆ โ–ˆโ–ˆโ–ˆโ–ˆ โ–ˆ โ–ˆ โ–ˆ โ–ˆโ–ˆ โ–ˆ โ–ˆโ–ˆ โ–ˆ -...
    Runtime
    Day 13 Part 1: 712
    Day 13 Part 2:
     โ–ˆโ–ˆโ–ˆ   โ–ˆ     โ–ˆ  โ–ˆ  โ–ˆโ–ˆโ–ˆโ–ˆ    โ–ˆโ–ˆ  โ–ˆโ–ˆโ–ˆ     โ–ˆโ–ˆ  โ–ˆโ–ˆโ–ˆโ–ˆ 
     โ–ˆ  โ–ˆ  โ–ˆ     โ–ˆ  โ–ˆ  โ–ˆ        โ–ˆ  โ–ˆ  โ–ˆ     โ–ˆ  โ–ˆ    
     โ–ˆโ–ˆโ–ˆ   โ–ˆ     โ–ˆโ–ˆโ–ˆโ–ˆ  โ–ˆโ–ˆโ–ˆ      โ–ˆ  โ–ˆ  โ–ˆ     โ–ˆ  โ–ˆโ–ˆโ–ˆ  
     โ–ˆ  โ–ˆ  โ–ˆ     โ–ˆ  โ–ˆ  โ–ˆ        โ–ˆ  โ–ˆโ–ˆโ–ˆ      โ–ˆ  โ–ˆ    
     โ–ˆ  โ–ˆ  โ–ˆ     โ–ˆ  โ–ˆ  โ–ˆ     โ–ˆ  โ–ˆ  โ–ˆ     โ–ˆ  โ–ˆ  โ–ˆ    
     โ–ˆโ–ˆโ–ˆ   โ–ˆโ–ˆโ–ˆโ–ˆ  โ–ˆ  โ–ˆ  โ–ˆ      โ–ˆโ–ˆ   โ–ˆ      โ–ˆโ–ˆ   โ–ˆ    
    
    - Runtime: 632.801ยตs
    
    Setup and imports
    use std::collections::HashSet;
    
    use color_eyre::{eyre::eyre, Result};
    use itertools::Itertools;
    
    mod canvas;
    
    use canvas::{Canvas, Fold, Point};
    
    pub fn solve() -> Result<()> {
      let input_data = include_str!("../../data/day_13.txt").trim();
      println!("Day 13 Part 1: {}", part_1(input_data)?);
      println!("Day 13 Part 2:\n{}", part_2(input_data)?);
      Ok(())
    }
    
    Data structures setup and implementation
    use std::{collections::HashSet, fmt::Display};
    
    #[derive(Debug, Hash, PartialEq, Eq)]
    pub struct Point(pub isize, pub isize);
    
    #[derive(Debug)]
    pub enum Fold {
      Horizontal(isize),
      Vertical(isize),
    }
    
    #[derive(Debug)]
    pub struct Canvas {
      pub width: isize,
      pub height: isize,
      pub points: HashSet<Point>,
    }
    
    impl Canvas {
      pub fn fold(self, fold: &Fold) -> Self {
        let (width, height) = match fold {
          Fold::Horizontal(amount) => (self.width, *amount),
          Fold::Vertical(amount) => (*amount, self.height),
        };
    
        let mut points = HashSet::new();
        for Point(x, y) in self.points {
          if y > height {
            points.insert(Point(x, height - (y - height)));
            continue;
          }
    
          if x > width {
            points.insert(Point(width - (x - width), y));
            continue;
          }
    
          points.insert(Point(x, y));
        }
    
        Self {
          width,
          height,
          points,
        }
      }
    }
    
    impl Display for Canvas {
      fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        for y in 0..self.height {
          for x in 0..self.width {
            if x % (self.width / 8) == 0 {
              write!(f, " ")?;
            }
    
            if self.points.contains(&Point(x, y)) {
              write!(f, "โ–ˆ")?;
            } else {
              write!(f, " ")?;
            }
          }
    
          writeln!(f)?;
        }
    
        Ok(())
      }
    }
    
    Parsing the canvas and folds
    fn parse(input: &str) -> Result<(Canvas, Vec<Fold>)> {
      let mut canvas = Canvas {
        width: 0,
        height: 0,
        points: HashSet::new(),
      };
    
      let mut in_folds_section = false;
      let mut folds = vec![];
    
      for line in input.lines() {
        if line == "" {
          in_folds_section = true;
          continue;
        }
    
        if in_folds_section {
          let mut split = line.split("=");
          let is_x_axis = split
            .next()
            .map(|s| s.ends_with("x"))
            .ok_or_else(|| eyre!("Invalid line: {}", line))?;
    
          let amount = split
            .next()
            .map(str::parse)
            .ok_or_else(|| eyre!("Expected number: {}", line))??;
    
          if is_x_axis {
            folds.push(Fold::Vertical(amount));
          } else {
            folds.push(Fold::Horizontal(amount));
          }
        } else {
          let (x, y) = line
            .split(",")
            .tuples()
            .next()
            .ok_or_else(|| eyre!("Invalid line: {}", line))?;
    
          let x = x.parse()?;
          let y = y.parse()?;
          if canvas.width < x {
            canvas.width = x;
          }
    
          if canvas.height < y {
            canvas.height = y;
          }
    
          canvas.points.insert(Point(x, y));
        }
      }
    
      Ok((canvas, folds))
    }
    
    Solving both parts
    fn part_1(input: &str) -> Result<usize> {
      let (mut canvas, folds) = parse(input)?;
      canvas = canvas.fold(&folds[0]);
      Ok(canvas.points.into_iter().count())
    }
    
    fn part_2(input: &str) -> Result<String> {
      let (mut canvas, folds) = parse(input)?;
    
      for fold in folds {
        canvas = canvas.fold(&fold);
      }
    
      Ok(format!("{}", canvas))
    }
    
    3 votes
  17. Comment on Day 14: Extended Polymerization in ~comp.advent_of_code

    Bauke
    (edited )
    Link
    Stuck on Day 11 & 12 For some reason I have been stuck on day 11 and 12. Even reading other people's solutions and explanations I can't seem to figure it out for myself, though I really don't like...
    Stuck on Day 11 & 12

    For some reason I have been stuck on day 11 and 12. Even reading other people's solutions and explanations I can't seem to figure it out for myself, though I really don't like the whole Game Of Life-ish puzzles and graphing/pathing/whatever puzzles so to be honest I might just not even bother with them. Anyway long story short, it was nice today wasn't as difficult for me. I read through 13 and I'm gonna try that now, I think I can do that one at least.

    Spoilies

    For part 1 I initially did the "growing string" kind of thing but using Itertools' tuple_windows to get the character pairs and then using interleave to put the new characters into the string, which I thought was a pretty neat solution. Buuut my RAM really didn't like that once I tried part 2... It got to step 27 before it took up all 16GB I have.

    So I reworked everything to count pairs instead, hit my head through a few walls of not knowing where the problem was and then finally changed something in the code and got the correct result. So, yay!

    Runtime
    Day 14 Part 1: 3411
    Day 14 Part 2: 7477815755570
    - Runtime: 395.987ยตs
    
    Imports and setup
    use std::collections::HashMap;
    
    use color_eyre::{eyre::eyre, Result};
    use itertools::Itertools;
    
    type PairMap = HashMap<(char, char), char>;
    type PairCounts = HashMap<(char, char), isize>;
    
    pub fn solve() -> Result<()> {
      let input_data = include_str!("../../data/day_14.txt").trim();
      println!("Day 14 Part 1: {}", part_1(input_data)?);
      println!("Day 14 Part 2: {}", part_2(input_data)?);
      Ok(())
    }
    
    Parsing the input
    fn parse(input: &str) -> Result<(String, PairMap)> {
      let mut lines = input.lines();
      let template = lines
        .next()
        .ok_or_else(|| eyre!("Invalid input: {}", input))?
        .to_string();
    
      let mut pairs = HashMap::new();
    
      for line in lines.skip(1) {
        let (a, b, c) = line
          .replace(" -> ", "")
          .chars()
          .collect_tuple()
          .ok_or_else(|| eyre!("Invalid line: {}", line))?;
    
        pairs.insert((a, b), c);
      }
    
      Ok((template, pairs))
    }
    
    Applying the pairs and counting the totals
    fn apply(counts: &PairCounts, pairs: &PairMap) -> PairCounts {
      let mut to_add = PairCounts::new();
    
      for (pair, count) in counts {
        if let Some(character) = pairs.get(pair) {
          *to_add.entry((pair.0, *character)).or_default() += count;
          *to_add.entry((*character, pair.1)).or_default() += count;
        }
      }
    
      to_add
    }
    
    fn count_totals(counts: &PairCounts) -> HashMap<char, isize> {
      let mut totals = HashMap::new();
    
      for ((_, b), count) in counts {
        // If I count the first character in the pair the end result ends up being
        // off by one...?
        *totals.entry(*b).or_default() += count;
      }
    
      totals
    }
    
    Solving both parts
    fn run(input: &str, steps: isize) -> Result<isize> {
      let (template, pairs) = parse(input)?;
    
      let mut counts = PairCounts::new();
      for (a, b) in template.chars().tuple_windows() {
        *counts.entry((a, b)).or_default() += 1;
      }
    
      for _ in 0..steps {
        counts = apply(&counts, &pairs);
      }
    
      let totals = count_totals(&counts)
        .into_iter()
        .sorted_by(|(_, a), (_, b)| a.cmp(b));
    
      let (_, min) = totals
        .clone()
        .next()
        .ok_or_else(|| eyre!("No minimum found"))?;
      let (_, max) = totals
        .clone()
        .last()
        .ok_or_else(|| eyre!("No maximum found"))?;
    
      Ok(max - min)
    }
    
    fn part_1(input: &str) -> Result<isize> {
      run(input, 10)
    }
    
    fn part_2(input: &str) -> Result<isize> {
      run(input, 40)
    }
    
    4 votes