I have used and enjoyed lawnchair for the past year. It's quite minimal and I've found it very stable.
Personally, I think it's great. It's a smaller community than HN and the registration requirements, whilst not a perfect solution, do create a litmus test and ultimately creates an envrionment of mostly high quality posting.
To get in, you need to be invited in by an existing user. If you don't know anybody, you can hang around on their IRC channel and once you're familiar, somebody may be willing to invite you.
This should have been posted in programming.dev/c/meta. I'm leaving it up here as the question has been answered.
Thanks - appreciate the feedback!
I'm a bit less extreme about it than many here. But, in short, back when Reddit made sweeping API changes it immediately gave me 'the ick' and so I sought less centralised platforms. Lemmy is the closest thing I've found to people just hosting their own message boards like back in the early internet.
I'm a big fan of decentralized platforms and I love the concept of ActivityPub.
That said, I still use Reddit and have recently started to really enjoy BlueSky, so I'm not militantly against the corporate platforms or anything.
Finally, I just like the natural selection things like Lemmy and Mastodon have for those who are naturally more techy and nerdy.
Gleam
Late as usual. This one challenged me. Functional programming is a lot of fun, but it's kicking my ass.
import gleam/dict
import gleam/io
import gleam/list
import gleam/option.{None, Some}
import gleam/result
import gleam/set.{type Set}
import gleam/string
import simplifile
pub type Point =
#(Int, Int)
pub type Grid(a) =
dict.Dict(Point, a)
pub type Direction {
North
East
South
West
}
pub type Loops {
DoesLoop
DoesNotLoop
}
pub type Guard {
Guard(position: Point, direction: Direction)
}
fn get_guard(grid: Grid(String)) -> Guard {
let pos = dict.filter(grid, fn(_pos, char) { char == "^" })
let assert Ok(pos) = case dict.size(pos) {
1 -> list.first(dict.keys(pos))
0 -> panic as "No guard found in input!"
_ -> panic as "More than one guard found in input!"
}
Guard(pos, North)
}
fn move_guard(guard: Guard) -> Guard {
let new_pos = case guard.direction {
North -> #(-1, 0)
East -> #(0, 1)
South -> #(1, 0)
West -> #(0, -1)
}
Guard(
#(guard.position.0 + new_pos.0, guard.position.1 + new_pos.1),
guard.direction,
)
}
fn turn_guard(guard: Guard) -> Guard {
let new_dir = case guard.direction {
North -> East
East -> South
South -> West
West -> North
}
Guard(guard.position, new_dir)
}
fn get_obstacles(grid: Grid(String)) -> List(Point) {
dict.filter(grid, fn(_pos, char) { char == "#" })
|> dict.keys()
}
fn recurse_grid(
grid: Grid(String),
guard: Guard,
obstacles: List(#(Int, Int)),
visited: Set(#(#(Int, Int), Direction)),
) -> #(Set(#(#(Int, Int), Direction)), Loops) {
let new_guard = move_guard(guard)
let position = new_guard.position
let dir = new_guard.direction
case dict.has_key(grid, position) {
False -> #(visited, DoesNotLoop)
True -> {
case set.contains(visited, #(position, dir)) {
True -> {
#(visited, DoesLoop)
}
False -> {
case list.contains(obstacles, position) {
True -> recurse_grid(grid, turn_guard(guard), obstacles, visited)
False ->
recurse_grid(
grid,
new_guard,
obstacles,
set.insert(visited, #(position, dir)),
)
}
}
}
}
}
}
fn get_grid_input(filename: String) -> Grid(String) {
let lines =
filename
|> simplifile.read()
|> result.unwrap("")
|> string.trim()
|> string.split("\n")
use grid, row, row_idx <- list.index_fold(lines, dict.new())
use grid, col, col_idx <- list.index_fold(string.to_graphemes(row), grid)
dict.insert(grid, #(row_idx, col_idx), col)
}
fn part_one(
grid: Grid(String),
) -> #(#(Set(#(#(Int, Int), Direction)), Loops), Int) {
let guard = get_guard(grid)
let obstacles = get_obstacles(grid)
let visited = set.new() |> set.insert(#(guard.position, guard.direction))
let visited = recurse_grid(grid, guard, obstacles, visited)
let visited_without_dir =
set.fold(visited.0, set.new(), fn(acc, x) { set.insert(acc, x.0) })
#(visited, visited_without_dir |> set.size())
}
fn check_loop(grid: Grid(String), blocker: Point) -> Loops {
let blocked_grid =
dict.upsert(grid, blocker, fn(x) {
case x {
Some("^") -> "^"
Some(_) -> "#"
None -> "#"
}
})
let visited = part_one(blocked_grid).0
visited.1
}
fn part_two(grid: Grid(String), visited: Set(#(#(Int, Int), Direction))) {
let visited =
set.fold(visited, set.new(), fn(acc, x) { set.insert(acc, x.0) })
use counter, position <- set.fold(visited, 0)
case check_loop(grid, position) {
DoesLoop -> counter + 1
DoesNotLoop -> counter
}
}
pub fn main() {
let input = "input.in"
let p1 = input |> get_grid_input() |> part_one
let visited = p1.0.0
io.debug(p1.1)
input |> get_grid_input |> part_two(visited) |> io.debug()
}
Gleam
Struggled with the second part as I am still very new to this very cool language, but got there after scrolling for some inspiration.
import gleam/int
import gleam/io
import gleam/list
import gleam/regex
import gleam/result
import gleam/string
import simplifile
pub fn main() {
let assert Ok(data) = simplifile.read("input.in")
part_one(data) |> io.debug
part_two(data) |> io.debug
}
fn part_one(data) {
let assert Ok(multiplication_pattern) =
regex.from_string("mul\\(\\d{1,3},\\d{1,3}\\)")
let assert Ok(digit_pattern) = regex.from_string("\\d{1,3},\\d{1,3}")
let multiplications =
regex.scan(multiplication_pattern, data)
|> list.flat_map(fn(reg) {
regex.scan(digit_pattern, reg.content)
|> list.map(fn(digits) {
digits.content
|> string.split(",")
|> list.map(fn(x) { x |> int.parse |> result.unwrap(0) })
|> list.reduce(fn(a, b) { a * b })
|> result.unwrap(0)
})
})
|> list.reduce(fn(a, b) { a + b })
|> result.unwrap(0)
}
fn part_two(data) {
let data = "do()" <> string.replace(data, "\n", "") <> "don't()"
let assert Ok(pattern) = regex.from_string("do\\(\\).*?don't\\(\\)")
regex.scan(pattern, data)
|> list.map(fn(input) { input.content |> part_one })
|> list.reduce(fn(a, b) { a + b })
}
Elixir
defmodule Day02 do
defp part1(reports) do
reports
|> Enum.map(fn report ->
levels =
report
|> String.split()
|> Enum.map(&String.to_integer/1)
cond do
sequence_is_safe?(levels) ->
:safe
true ->
:unsafe
end
end)
|> Enum.count(fn x -> x == :safe end)
end
defp part2(reports) do
reports
|> Enum.map(fn report ->
levels =
report
|> String.split()
|> Enum.map(&String.to_integer/1)
sequences =
0..(length(levels) - 1)
|> Enum.map(fn i ->
List.delete_at(levels, i)
end)
cond do
sequence_is_safe?(levels) ->
:safe
Enum.any?(sequences, &sequence_is_safe?/1) ->
:safe
true ->
:unsafe
end
end)
|> Enum.count(fn x -> x == :safe end)
end
defp all_gaps_within_max_diff?(numbers) do
numbers
|> Enum.chunk_every(2, 1, :discard)
|> Enum.all?(fn [a, b] -> abs(b - a) <= 3 end)
end
defp is_strictly_increasing?(numbers) do
numbers
|> Enum.chunk_every(2, 1, :discard)
|> Enum.all?(fn [a, b] -> a < b end)
end
defp is_strictly_decreasing?(numbers) do
numbers
|> Enum.chunk_every(2, 1, :discard)
|> Enum.all?(fn [a, b] -> a > b end)
end
defp sequence_is_safe?(numbers) do
(is_strictly_increasing?(numbers) or
is_strictly_decreasing?(numbers)) and all_gaps_within_max_diff?(numbers)
end
def run(data) do
reports = data |> String.split("\n", trim: true)
p1 = part1(reports)
p2 = part2(reports)
IO.puts(p1)
IO.puts(p2)
end
end
data = File.read!("input.in")
Day02.run(data)
I'm late to the party, as usual. Damned timezones.
This year I'm going to tackle with a small handful of languages, but primarily Elixir and Gleam. This is my first time trying this languages in earnest, so expect some terrible, inefficient and totally unidiomatic code!
Here's day one:
Elixir
part_one =
File.read!("input.in")
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
line
|> String.split()
|> Enum.map(&String.to_integer/1)
end)
|> Enum.reduce({[], []}, fn [first, second], {list1, list2} ->
{[first | list1], [second | list2]}
end)
|> then(fn {list1, list2} ->
{Enum.sort(list1), Enum.sort(list2)}
end)
|> then(fn {list1, list2} ->
Enum.zip(list1, list2)
|> Enum.map(fn {x, y} -> abs(x - y) end)
end)
|> Enum.sum()
part_two =
File.read!("input.in")
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
line
|> String.split()
|> Enum.map(&String.to_integer/1)
end)
|> Enum.reduce({[], []}, fn [first, second], {list1, list2} ->
{[first | list1], [second | list2]}
end)
|> then(fn {list1, list2} ->
Enum.map(list1, fn line ->
line * Enum.count(list2, fn x -> x === line end)
end)
|> Enum.sum()
end)
IO.inspect(part_one)
IO.inspect(part_two)
She was 89 and no doubt lead a truly fulfilling life, and so I think objectively it's not a sad passing - she had a truly remarkable life and long life.
That said, she was a significant part of my childhood, and always on the television in the various households I've lived in for one show or another. It feels like losing a beloved grandmother, and I'm devastated. RIP Maggie.
It’s Lemmy.