mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-25 21:00:31 +01:00
Compare commits
23 Commits
1dc59c18eb
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| bc6f3dc8c6 | |||
| a8a1c85498 | |||
| ff8b8dac0c | |||
| 51ca5db42e | |||
| e60bfbf8c4 | |||
| 768a3ff10b | |||
| c3d3116f8a | |||
| 13592a60ee | |||
| be6c3d37ea | |||
| ff2c86a11b | |||
| a737a35227 | |||
| 29e02c819e | |||
| a01eb547d1 | |||
| 1485eb3cd5 | |||
| 0a7ec71a97 | |||
| f2204e554b | |||
| 6f4b02af33 | |||
| 7e23cf94a6 | |||
| f132842b5c | |||
| 027a7bdde6 | |||
| 2277721010 | |||
| 5e9a24c8d7 | |||
| 1468c87347 |
17
2025/day01/README.md
Normal file
17
2025/day01/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Day 01: Nix
|
||||
|
||||
Nix is a functional language made for the Nix package manager. As
|
||||
|
||||
To run the solution program, start the `nix` repl with the solution program and call the `solve`
|
||||
function with the path to the input file.
|
||||
|
||||
```console
|
||||
$ nix repl --option max-call-depth 10000 --file solve.nix
|
||||
nix-repl> solve ./sample.txt
|
||||
```
|
||||
|
||||
Some observations:
|
||||
|
||||
- The `max-call-depth` needs to be bumped to at least 10k for the main input files, otherwise you
|
||||
hit the limit in the recursion.
|
||||
- The standard library is lacking several basics but most of those you can build yourself
|
||||
@@ -4,28 +4,34 @@
|
||||
data = builtins.readFile input_file;
|
||||
lines = builtins.filter (s: s != "" && builtins.isString s) (builtins.split "\n" data);
|
||||
|
||||
# Basic maths because the standard library doesn't have it
|
||||
mod = a: b: a - (a / b) * b;
|
||||
abs = n: if n < 0 then -n else n;
|
||||
|
||||
recurse = list: position:
|
||||
recurse = list: position: score1: score2:
|
||||
let
|
||||
first = builtins.head list;
|
||||
# This is not guaranteed to work but it does
|
||||
# This is not guaranteed to work but it's good enough
|
||||
num_part = builtins.substring 1 999 first;
|
||||
num = builtins.fromJSON num_part;
|
||||
next = if (builtins.substring 0 1 first) == "R"
|
||||
then
|
||||
position + num
|
||||
else
|
||||
position - num;
|
||||
delta = mod (if (builtins.substring 0 1 first) == "R" then num else -num) 100;
|
||||
next = mod (position + delta + 100) 100;
|
||||
|
||||
new_position = mod ((mod next 100) + 100) 100;
|
||||
score = if next == 0 then 1 else 0;
|
||||
circles = num / 100;
|
||||
|
||||
score = if new_position == 0 then 1 else 0;
|
||||
in
|
||||
if list == [] then
|
||||
passed = if position == 0 then
|
||||
0
|
||||
else
|
||||
score + (recurse (builtins.tail list) new_position);
|
||||
if delta < 0 && delta + position <= 0 || delta > 0 && delta + position >= 100 then
|
||||
1
|
||||
else
|
||||
0;
|
||||
in
|
||||
if list == [] then
|
||||
[score1 score2]
|
||||
else
|
||||
recurse (builtins.tail list) next (score + score1) (score2 + passed + circles);
|
||||
in
|
||||
recurse lines 50;
|
||||
recurse lines 50 0 0;
|
||||
}
|
||||
|
||||
29
2025/day02/README.md
Normal file
29
2025/day02/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Day 02: Terraform
|
||||
|
||||
The code assumes an input file at `../inputs/02.txt`. Other than that, simply try to run as follows:
|
||||
|
||||
```console
|
||||
$ terraform init
|
||||
…
|
||||
Initializing the backend...
|
||||
Initializing modules...
|
||||
Initializing provider plugins...
|
||||
|
||||
Terraform has been successfully initialized!
|
||||
|
||||
You may now begin working with Terraform. Try running "terraform plan" to see
|
||||
any changes that are required for your infrastructure. All Terraform commands
|
||||
should now work.
|
||||
|
||||
If you ever set or change modules or backend configuration for Terraform,
|
||||
rerun this command to reinitialize your working directory. If you forget, other
|
||||
commands will detect it and remind you to do so if necessary.
|
||||
$ terraform plan
|
||||
….
|
||||
|
||||
Changes to Outputs:
|
||||
+ part1 = secret
|
||||
+ part2 = also secret
|
||||
|
||||
You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.
|
||||
```
|
||||
29
2025/day02/main.tf
Normal file
29
2025/day02/main.tf
Normal file
@@ -0,0 +1,29 @@
|
||||
locals {
|
||||
input = file("../inputs/02.txt")
|
||||
ranges = split(",", chomp(local.input))
|
||||
min_max = [for r in local.ranges : split("-", r)]
|
||||
}
|
||||
|
||||
module "check_range" {
|
||||
source = "./range"
|
||||
count = length(local.min_max)
|
||||
|
||||
min = local.min_max[count.index][0]
|
||||
max = local.min_max[count.index][1]
|
||||
}
|
||||
|
||||
module "check_range2" {
|
||||
source = "./range2"
|
||||
count = length(local.min_max)
|
||||
|
||||
min = local.min_max[count.index][0]
|
||||
max = local.min_max[count.index][1]
|
||||
}
|
||||
|
||||
output "part1" {
|
||||
value = sum(module.check_range[*].invalid_sum)
|
||||
}
|
||||
|
||||
output "part2" {
|
||||
value = sum(module.check_range2[*].invalid_sum)
|
||||
}
|
||||
15
2025/day02/range/item/main.tf
Normal file
15
2025/day02/range/item/main.tf
Normal file
@@ -0,0 +1,15 @@
|
||||
variable "part" {
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "repetitions" {
|
||||
type = number
|
||||
}
|
||||
|
||||
locals {
|
||||
repeated = [for _ in range(var.repetitions) : tostring(var.part)]
|
||||
}
|
||||
|
||||
output "full" {
|
||||
value = join("", local.repeated)
|
||||
}
|
||||
46
2025/day02/range/main.tf
Normal file
46
2025/day02/range/main.tf
Normal file
@@ -0,0 +1,46 @@
|
||||
variable "min" {
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "max" {
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "repetitions" {
|
||||
type = number
|
||||
default = 2
|
||||
}
|
||||
|
||||
locals {
|
||||
digits = floor(length(tostring(var.max)) / var.repetitions)
|
||||
maximum = substr(tostring(var.max), 0, local.digits)
|
||||
real_maximum = length(tostring(var.max)) % var.repetitions == 0 ? tonumber(local.maximum) : pow(10, local.digits)
|
||||
|
||||
minimum_prefix = substr(tostring(var.min), 0, length(tostring(var.min)) - local.digits * (var.repetitions - 1))
|
||||
minimum = local.minimum_prefix == "" ? 1 : tonumber(local.minimum_prefix)
|
||||
|
||||
count = max(local.real_maximum - local.minimum + 1, 1)
|
||||
|
||||
can_work = anytrue([for n in range(length(tostring(var.min)), length(tostring(var.max)) + 1) : n % var.repetitions == 0])
|
||||
}
|
||||
|
||||
// This "candidates" module ought really be a list comprehension from range, but Terraform does not
|
||||
// allow you to create ranges longer than 1024.
|
||||
module "candidates" {
|
||||
source = "./item"
|
||||
count = local.can_work ? local.count : 0
|
||||
part = count.index + local.minimum
|
||||
repetitions = var.repetitions
|
||||
}
|
||||
|
||||
locals {
|
||||
invalid = [for n in module.candidates[*].full : n if n >= var.min && n <= var.max]
|
||||
}
|
||||
|
||||
output "invalid_sum" {
|
||||
value = length(local.invalid) > 0 ? sum(local.invalid) : 0
|
||||
}
|
||||
|
||||
output "invalid" {
|
||||
value = toset(local.invalid)
|
||||
}
|
||||
27
2025/day02/range2/main.tf
Normal file
27
2025/day02/range2/main.tf
Normal file
@@ -0,0 +1,27 @@
|
||||
variable "min" {
|
||||
type = number
|
||||
}
|
||||
|
||||
variable "max" {
|
||||
type = number
|
||||
}
|
||||
|
||||
locals {
|
||||
digits = length(tostring(var.max))
|
||||
}
|
||||
|
||||
module "range" {
|
||||
source = "../range"
|
||||
count = local.digits - 1
|
||||
max = var.max
|
||||
min = var.min
|
||||
repetitions = count.index + 2
|
||||
}
|
||||
|
||||
locals {
|
||||
results = setunion(module.range[*].invalid...)
|
||||
}
|
||||
|
||||
output "invalid_sum" {
|
||||
value = length(local.results) > 0 ? sum(local.results) : 0
|
||||
}
|
||||
128
2025/day02/tests.tftest.hcl
Normal file
128
2025/day02/tests.tftest.hcl
Normal file
@@ -0,0 +1,128 @@
|
||||
run "sample-1-1" {
|
||||
module {
|
||||
source = "./range"
|
||||
}
|
||||
|
||||
variables {
|
||||
min = 11
|
||||
max = 22
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.invalid_sum == 33
|
||||
error_message = "Incorrect result"
|
||||
}
|
||||
}
|
||||
|
||||
run "sample-1-2" {
|
||||
module {
|
||||
source = "./range"
|
||||
}
|
||||
|
||||
variables {
|
||||
min = 95
|
||||
max = 115
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.invalid_sum == 99
|
||||
error_message = "Incorrect result"
|
||||
}
|
||||
}
|
||||
|
||||
run "sample-2-1" {
|
||||
module {
|
||||
source = "./range2"
|
||||
}
|
||||
|
||||
variables {
|
||||
min = 11
|
||||
max = 22
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.invalid_sum == 33
|
||||
error_message = "Incorrect result"
|
||||
}
|
||||
}
|
||||
|
||||
run "sample-2-2" {
|
||||
module {
|
||||
source = "./range2"
|
||||
}
|
||||
|
||||
variables {
|
||||
min = 95
|
||||
max = 115
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.invalid_sum == 210
|
||||
error_message = "Incorrect result"
|
||||
}
|
||||
}
|
||||
|
||||
run "sample-2-3" {
|
||||
module {
|
||||
source = "./range2"
|
||||
}
|
||||
|
||||
variables {
|
||||
min = 998
|
||||
max = 1012
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.invalid_sum == 2009
|
||||
error_message = "Incorrect result"
|
||||
}
|
||||
}
|
||||
|
||||
run "sample-2-2-detail" {
|
||||
module {
|
||||
source = "./range"
|
||||
}
|
||||
|
||||
variables {
|
||||
min = 95
|
||||
max = 115
|
||||
repetitions = 3
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.invalid_sum == 111
|
||||
error_message = "Incorrect result"
|
||||
}
|
||||
}
|
||||
|
||||
run "sample-2-10" {
|
||||
module {
|
||||
source = "./range2"
|
||||
}
|
||||
|
||||
variables {
|
||||
min = 824824821
|
||||
max = 824824827
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.invalid_sum == 824824824
|
||||
error_message = "Incorrect result"
|
||||
}
|
||||
}
|
||||
|
||||
run "sample-2-11" {
|
||||
module {
|
||||
source = "./range2"
|
||||
}
|
||||
|
||||
variables {
|
||||
min = 2121212118
|
||||
max = 2121212124
|
||||
}
|
||||
|
||||
assert {
|
||||
condition = output.invalid_sum == 2121212121
|
||||
error_message = "Incorrect result"
|
||||
}
|
||||
}
|
||||
4
2025/day03/README.md
Normal file
4
2025/day03/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Day 03: Bash
|
||||
|
||||
Simple as can be, simply run `./solve.sh <input file>` and get both answers. While I allowed myself
|
||||
to use `coreutils` with bash, they turned out to be entirely unnecessary. Pure bash just works.
|
||||
4
2025/day03/sample.txt
Normal file
4
2025/day03/sample.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
987654321111111
|
||||
811111111111119
|
||||
234234234234278
|
||||
818181911112111
|
||||
64
2025/day03/solve.sh
Executable file
64
2025/day03/solve.sh
Executable file
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <input file>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
joltage() {
|
||||
local first second c i
|
||||
|
||||
first=0
|
||||
second=0
|
||||
|
||||
for ((i = 0; i < ${#1}; i++)); do
|
||||
c="${1:$i:1}"
|
||||
|
||||
if [[ $second -gt $first ]]; then
|
||||
first="$second"
|
||||
second="$c"
|
||||
elif [[ $c -gt $second ]]; then
|
||||
second="$c"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "$first$second"
|
||||
}
|
||||
|
||||
joltage2() {
|
||||
local c i d e n digits
|
||||
|
||||
digits=(0 0 0 0 0 0 0 0 0 0 0 0)
|
||||
|
||||
for ((i = 0; i < ${#1}; i++)); do
|
||||
c="${1:$i:1}"
|
||||
|
||||
for ((d = 0; d < 11; d++)); do
|
||||
if [[ ${digits[((d + 1))]} -gt ${digits[$d]} ]]; then
|
||||
for ((e = d; e < 11; e++)); do
|
||||
n=$((e + 1))
|
||||
digits[e]=${digits[n]}
|
||||
done
|
||||
digits[11]="0"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $c -gt ${digits[11]} ]]; then
|
||||
digits[11]="$c"
|
||||
fi
|
||||
done
|
||||
|
||||
printf "%s" "${digits[@]}"
|
||||
}
|
||||
|
||||
total=0
|
||||
total2=0
|
||||
|
||||
while IFS="" read -r line || [[ -n "$p" ]]; do
|
||||
((total += $(joltage "$line")))
|
||||
((total2 += $(joltage2 "$line")))
|
||||
done <"$1"
|
||||
|
||||
echo "$total"
|
||||
echo "$total2"
|
||||
11
2025/day04/README.md
Normal file
11
2025/day04/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Day 04: SQLite sql
|
||||
|
||||
Did you know SQLite does not have procedural extensions? I did not when I started this. Regardless,
|
||||
to run:
|
||||
|
||||
```console
|
||||
$ sqlite3 < solve.sql
|
||||
part1
|
||||
-----
|
||||
13
|
||||
```
|
||||
10
2025/day04/sample.txt
Normal file
10
2025/day04/sample.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
..@@.@@@@.
|
||||
@@@.@.@.@@
|
||||
@@@@@.@.@@
|
||||
@.@@@@..@.
|
||||
@@.@@@@.@@
|
||||
.@@@@@@@.@
|
||||
.@.@.@.@@@
|
||||
@.@@@.@@@@
|
||||
.@@@@@@@@.
|
||||
@.@.@@@.@.
|
||||
759
2025/day04/solve.sql
Normal file
759
2025/day04/solve.sql
Normal file
@@ -0,0 +1,759 @@
|
||||
-- First import raw data into a table so we can work
|
||||
CREATE TABLE raw_data(line_data VARCHAR NOT NULL);
|
||||
.import --csv './sample.txt' raw_data
|
||||
-- Then use the auto-incrementing ID to add a y coordinate
|
||||
CREATE TABLE grid_lines(
|
||||
y INTEGER PRIMARY KEY,
|
||||
line_data VARCHAR NOT NULL
|
||||
);
|
||||
INSERT INTO grid_lines(line_data)
|
||||
SELECT line_data
|
||||
FROM raw_data;
|
||||
-- Now create a table to hold the paper rolls
|
||||
CREATE TABLE rolls(
|
||||
x INTEGER NOT NULL,
|
||||
y INTEGER NOT NULL,
|
||||
PRIMARY KEY (x, y)
|
||||
);
|
||||
WITH RECURSIVE cte AS (
|
||||
SELECT y,
|
||||
1 x,
|
||||
line_data,
|
||||
substr(line_data, 1, 1) c
|
||||
FROM grid_lines
|
||||
UNION ALL
|
||||
SELECT y,
|
||||
x + 1,
|
||||
line_data,
|
||||
substr(line_data, x + 1, 1)
|
||||
FROM cte
|
||||
WHERE x <= length(line_data)
|
||||
)
|
||||
INSERT INTO rolls
|
||||
SELECT x,
|
||||
y
|
||||
FROM cte
|
||||
WHERE c = '@';
|
||||
-- Now compute part 1
|
||||
SELECT COUNT(*) as part1
|
||||
FROM rolls r
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls o
|
||||
WHERE o.x >= r.x - 1
|
||||
AND o.x <= r.x + 1
|
||||
AND o.y >= r.y - 1
|
||||
AND o.y <= r.y + 1
|
||||
) < 4;
|
||||
--- Create a scratch table where we're going to delete rolls from
|
||||
CREATE TABLE rolls2(
|
||||
x INTEGER NOT NULL,
|
||||
y INTEGER NOT NULL,
|
||||
PRIMARY KEY (x, y)
|
||||
);
|
||||
INSERT INTO rolls2
|
||||
SELECT *
|
||||
FROM rolls;
|
||||
-- Delete the outer rolls of paper 77 times. This turns out to be enough.
|
||||
-- I tried really hard not to do this.
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
DELETE FROM rolls2
|
||||
WHERE (
|
||||
SELECT COUNT(*) - 1
|
||||
FROM rolls2 o
|
||||
WHERE o.x >= rolls2.x - 1
|
||||
AND o.x <= rolls2.x + 1
|
||||
AND o.y >= rolls2.y - 1
|
||||
AND o.y <= rolls2.y + 1
|
||||
) < 4;
|
||||
-- See how many we've deleted
|
||||
SELECT (
|
||||
SELECT COUNT(*)
|
||||
FROM rolls
|
||||
) - (
|
||||
SELECT COUNT(*)
|
||||
FROM rolls2
|
||||
) as part2;
|
||||
1
2025/day05/.gitignore
vendored
Normal file
1
2025/day05/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
solve
|
||||
6
2025/day05/Makefile
Normal file
6
2025/day05/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
CFLAGS=-Wall -Wextra -O2 -g
|
||||
|
||||
all: solve
|
||||
|
||||
clean:
|
||||
$(RM) solve
|
||||
12
2025/day05/README.md
Normal file
12
2025/day05/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# Day 05: C
|
||||
|
||||
C is weird. It's a very simple language but it's made complicated by the fact that you have to do
|
||||
everything yourself. Relatively straightforward solution.
|
||||
|
||||
```console
|
||||
$ make
|
||||
cc -Wall -Wextra -O2 -g solve.c -o solve
|
||||
$ ./solve sample.txt
|
||||
Part1: 3
|
||||
Part2: 14
|
||||
```
|
||||
11
2025/day05/sample.txt
Normal file
11
2025/day05/sample.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
3-5
|
||||
10-14
|
||||
16-20
|
||||
12-18
|
||||
|
||||
1
|
||||
5
|
||||
8
|
||||
11
|
||||
17
|
||||
32
|
||||
160
2025/day05/solve.c
Normal file
160
2025/day05/solve.c
Normal file
@@ -0,0 +1,160 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX(a,b) \
|
||||
({ __typeof__ (a) _a = (a); \
|
||||
__typeof__ (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
||||
|
||||
typedef struct {
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
} range_t;
|
||||
|
||||
typedef struct {
|
||||
size_t length;
|
||||
size_t capacity;
|
||||
range_t* buffer;
|
||||
} ranges_t;
|
||||
|
||||
static int cmp_range(void const* va, void const* vb) {
|
||||
range_t const* a = va;
|
||||
range_t const* b = vb;
|
||||
|
||||
if (a->start == b->start) {
|
||||
return (a->end > b->end) - (a->end < b->end);
|
||||
} else {
|
||||
return (a->start > b->start) - (a->start < b-> start);
|
||||
}
|
||||
}
|
||||
|
||||
static void simplify_ranges(ranges_t* ranges) {
|
||||
// First, sort ranges ascending by start (then end)
|
||||
qsort(ranges->buffer, ranges->length, sizeof(range_t), cmp_range);
|
||||
|
||||
const size_t length = ranges->length;
|
||||
range_t* write_ptr = &ranges->buffer[0];
|
||||
|
||||
// Important, skip the first iteration, it can never be merged
|
||||
for (size_t i = 1; i < length; ++i) {
|
||||
if (ranges->buffer[i].start <= write_ptr->end) {
|
||||
// Merge the two ranges
|
||||
write_ptr->end = MAX(write_ptr->end, ranges->buffer[i].end);
|
||||
ranges->length--;
|
||||
} else {
|
||||
write_ptr++;
|
||||
if (write_ptr != &ranges->buffer[i]) {
|
||||
memcpy(write_ptr, &ranges->buffer[i], sizeof(range_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for (size_t i = 0; i < ranges->length; ++i) {
|
||||
// printf("%" PRIu64 "-%" PRIu64 "\n", ranges->buffer[i].start, ranges->buffer[i].end);
|
||||
// }
|
||||
|
||||
// printf("Original length: %u, new length: %u\n", (unsigned int) length, (unsigned int) ranges->length);
|
||||
}
|
||||
|
||||
bool is_fresh(const uint64_t ingredient, ranges_t const * const ranges) {
|
||||
size_t min = 0;
|
||||
size_t size = ranges->length;
|
||||
range_t const* buffer = ranges->buffer;
|
||||
|
||||
while (size > 1) {
|
||||
size_t half = size / 2;
|
||||
size_t mid = min + half;
|
||||
|
||||
if (buffer[mid].start <= ingredient) {
|
||||
min = mid;
|
||||
}
|
||||
|
||||
size -= half;
|
||||
}
|
||||
|
||||
return buffer[min].start <= ingredient && buffer[min].end >= ingredient;
|
||||
}
|
||||
|
||||
int main(const int argc, char const** argv) {
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <input>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ranges_t ranges = {
|
||||
.length = 0,
|
||||
.capacity = 2,
|
||||
.buffer = malloc(2 * sizeof(range_t)),
|
||||
};
|
||||
|
||||
FILE* input = fopen(argv[1], "r");
|
||||
if (input == NULL) {
|
||||
perror("failed to open file");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
uint64_t ingredient;
|
||||
bool seen_first = false;
|
||||
|
||||
while (!seen_first) {
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
|
||||
switch (fscanf(input, "%" PRIu64 "-%" PRIu64, &start, &end)) {
|
||||
case 1:
|
||||
seen_first = true;
|
||||
ingredient = start;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (ranges.capacity == ranges.length) {
|
||||
size_t new_capacity = ranges.capacity * 2;
|
||||
range_t* buffer = realloc(ranges.buffer, new_capacity * sizeof(range_t));
|
||||
if (buffer == NULL) {
|
||||
printf("Failed to resize ranges buffer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ranges.capacity = new_capacity;
|
||||
ranges.buffer = buffer;
|
||||
}
|
||||
|
||||
ranges.buffer[ranges.length].start = start;
|
||||
ranges.buffer[ranges.length].end = end;
|
||||
ranges.length++;
|
||||
break;
|
||||
default:
|
||||
printf("Unexpected end of file\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
simplify_ranges(&ranges);
|
||||
|
||||
int total_fresh = 0;
|
||||
|
||||
do {
|
||||
if (is_fresh(ingredient, &ranges)) {
|
||||
total_fresh++;
|
||||
}
|
||||
} while (fscanf(input, "%" PRIu64 "\n", &ingredient) == 1);
|
||||
|
||||
printf("Part1: %u\n", total_fresh);
|
||||
|
||||
uint64_t combined_fresh = 0;
|
||||
|
||||
for (size_t i = 0; i < ranges.length; ++i) {
|
||||
combined_fresh += ranges.buffer[i].end - ranges.buffer[i].start + 1;
|
||||
}
|
||||
|
||||
printf("Part2: %" PRIu64 "\n", combined_fresh);
|
||||
|
||||
fclose(input);
|
||||
free(ranges.buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
10
2025/day06/README.md
Normal file
10
2025/day06/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Day 06: PHP
|
||||
|
||||
Simple and straight-forward. This is a normal programming language.
|
||||
|
||||
|
||||
```console
|
||||
$ ./solve.php sample.txt
|
||||
Part1: 4277556
|
||||
Part2: 3263827
|
||||
```
|
||||
4
2025/day06/sample.txt
Normal file
4
2025/day06/sample.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
123 328 51 64
|
||||
45 64 387 23
|
||||
6 98 215 314
|
||||
* + * +
|
||||
81
2025/day06/solve.php
Executable file
81
2025/day06/solve.php
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
if ($argc < 2) {
|
||||
echo "Usage: {$argv[0]} INPUT\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$input = file($argv[1]);
|
||||
|
||||
function part1(string ...$input): int {
|
||||
$lines = [];
|
||||
|
||||
foreach ($input as $line) {
|
||||
$lines[] = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
|
||||
$lines = array_reverse($lines);
|
||||
$cols = count($lines[0]);
|
||||
$rows = count($lines);
|
||||
|
||||
$sum = 0;
|
||||
|
||||
for ($col = 0; $col < $cols; ++$col) {
|
||||
if ($lines[0][$col] === '+') {
|
||||
$acc = 0;
|
||||
for ($row = 1; $row < $rows; ++$row) {
|
||||
$acc += (int) $lines[$row][$col];
|
||||
}
|
||||
} else {
|
||||
$acc = 1;
|
||||
for ($row = 1; $row < $rows; ++$row) {
|
||||
$acc *= (int) $lines[$row][$col];
|
||||
}
|
||||
}
|
||||
|
||||
$sum += $acc;
|
||||
}
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
function part2(string ...$lines): int {
|
||||
$cols = strlen($lines[0]);
|
||||
$rows = count($lines);
|
||||
$numbers = array_fill(0, $cols, "");
|
||||
|
||||
for ($row = 0; $row < $rows - 1; ++$row) {
|
||||
foreach (str_split($lines[$row]) as $col => $c) {
|
||||
if ($c !== ' ') {
|
||||
$numbers[$col] .= $c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sum = 0;
|
||||
|
||||
foreach (str_split($lines[$rows - 1]) as $col => $c) {
|
||||
switch ($c) {
|
||||
case '+':
|
||||
$acc = 0;
|
||||
for ($i = $col; $i < $cols && $numbers[$i] !== ""; ++$i) {
|
||||
$acc += (int) $numbers[$i];
|
||||
}
|
||||
$sum += $acc;
|
||||
break;
|
||||
case '*':
|
||||
$acc = 1;
|
||||
for ($i = $col; $i < $cols && $numbers[$i] !== ""; ++$i) {
|
||||
$acc *= (int) $numbers[$i];
|
||||
}
|
||||
$sum += $acc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $sum;
|
||||
}
|
||||
|
||||
echo "Part1: " . part1(...$input) . "\n";
|
||||
echo "Part2: " . part2(...$input) . "\n";
|
||||
3
2025/day07/.gitignore
vendored
Normal file
3
2025/day07/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
solve
|
||||
*.o
|
||||
*.hi
|
||||
14
2025/day07/Makefile
Normal file
14
2025/day07/Makefile
Normal file
@@ -0,0 +1,14 @@
|
||||
.PHONY: all clean test
|
||||
|
||||
all: solve
|
||||
|
||||
test: solve
|
||||
./solve sample.txt
|
||||
|
||||
solve: solve.hs
|
||||
ghc -dynamic -O -g -o $@ $^
|
||||
|
||||
clean:
|
||||
$(RM) solve
|
||||
$(RM) *.o
|
||||
$(RM) *.hi
|
||||
15
2025/day07/README.md
Normal file
15
2025/day07/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Day 07: Haskell
|
||||
|
||||
This one took me the longest, mostly because I really do not know Haskell. Nevertheless, I find the
|
||||
resulting solution quite elegant. The `Makefile` I made uses dynamic linkage as that's how Haskell
|
||||
works on Arch Linux. If you want to do static linking, `ghc solve.hs` should work.
|
||||
|
||||
```console
|
||||
$ make
|
||||
ghc -dynamic -O -g -o solve solve.hs
|
||||
[1 of 2] Compiling Main ( solve.hs, solve.o )
|
||||
[2 of 2] Linking solve
|
||||
$ ./solve sample.txt
|
||||
21
|
||||
40
|
||||
```
|
||||
16
2025/day07/sample.txt
Normal file
16
2025/day07/sample.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
.......S.......
|
||||
...............
|
||||
.......^.......
|
||||
...............
|
||||
......^.^......
|
||||
...............
|
||||
.....^.^.^.....
|
||||
...............
|
||||
....^.^...^....
|
||||
...............
|
||||
...^.^...^.^...
|
||||
...............
|
||||
..^...^.....^..
|
||||
...............
|
||||
.^.^.^.^.^...^.
|
||||
...............
|
||||
65
2025/day07/solve.hs
Normal file
65
2025/day07/solve.hs
Normal file
@@ -0,0 +1,65 @@
|
||||
import Data.Array
|
||||
import Data.List
|
||||
import Data.Maybe
|
||||
import System.Environment
|
||||
import System.Exit
|
||||
|
||||
main = getArgs >>= parse >>= run
|
||||
|
||||
stringToArray :: [Char] -> Array Int Char
|
||||
stringToArray s = listArray (0, length s - 1) s
|
||||
|
||||
run :: String -> IO ()
|
||||
run input =
|
||||
let gridLines = lines input
|
||||
startingPoint = findStartingPoint $ head gridLines
|
||||
arrLines = Data.List.map stringToArray $ tail gridLines
|
||||
in do
|
||||
print $ part1 arrLines startingPoint
|
||||
print $ part2 arrLines startingPoint
|
||||
|
||||
findStartingPoint :: [Char] -> Int
|
||||
findStartingPoint line = fromJust $ elemIndex 'S' line
|
||||
|
||||
part1 arrLines startingPoint =
|
||||
let initial = [startingPoint]
|
||||
in simulate arrLines 0 initial
|
||||
|
||||
checkHit :: Array Int Char -> Int -> [Int]
|
||||
checkHit line idx = case line ! idx of
|
||||
'^' -> (idx - 1) : [idx + 1]
|
||||
_ -> [idx]
|
||||
|
||||
simulate [] count active = count
|
||||
simulate lines count active =
|
||||
let arr = head lines
|
||||
followUp = nub $ concatMap (checkHit arr) active
|
||||
hits = length $ Data.List.filter (\i -> arr ! i == '^') active
|
||||
remainder = tail lines
|
||||
in simulate remainder (hits + count) followUp
|
||||
|
||||
part2 :: [Array Int Char] -> Int -> Int
|
||||
part2 arrLines startingPosition =
|
||||
let n = length arrLines
|
||||
arr = listArray (0, n - 1) arrLines
|
||||
width = length $ head arrLines
|
||||
compute i pos
|
||||
| i >= n = 1
|
||||
| otherwise =
|
||||
let line = arr ! i
|
||||
in case line ! pos of
|
||||
'^' -> memo ! (i + 1, pos - 1) + memo ! (i + 1, pos + 1)
|
||||
_ -> memo ! (i + 1, pos)
|
||||
memo =
|
||||
array
|
||||
((0, 0), (n, width - 1))
|
||||
[((i, pos), compute i pos) | i <- [0 .. n], pos <- [0 .. width - 1]]
|
||||
in memo ! (0, startingPosition)
|
||||
|
||||
parse ["-h"] = usage >> exitSuccess
|
||||
parse [] = usage >> die usageStr
|
||||
parse fs = concat `fmap` mapM readFile fs
|
||||
|
||||
usageStr = "Usage: solve [-vh] [file ..]"
|
||||
|
||||
usage = putStrLn usageStr
|
||||
1
2025/day08/.gitignore
vendored
Normal file
1
2025/day08/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
solve
|
||||
11
2025/day08/README.md
Normal file
11
2025/day08/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Day 08: Go
|
||||
|
||||
Nice puzzle, got to use an obscure data structure. And implement it, because Go doesn't have it in
|
||||
its standard library.
|
||||
|
||||
```console
|
||||
$ go build
|
||||
$ ./solve sample.txt 10
|
||||
Part 1: 40
|
||||
Part 2: 25272
|
||||
```
|
||||
3
2025/day08/go.mod
Normal file
3
2025/day08/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module bertptrs/solve/v2
|
||||
|
||||
go 1.25.5
|
||||
20
2025/day08/sample.txt
Normal file
20
2025/day08/sample.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
162,817,812
|
||||
57,618,57
|
||||
906,360,560
|
||||
592,479,940
|
||||
352,342,300
|
||||
466,668,158
|
||||
542,29,236
|
||||
431,825,988
|
||||
739,650,466
|
||||
52,470,668
|
||||
216,146,977
|
||||
819,987,18
|
||||
117,168,530
|
||||
805,96,715
|
||||
346,949,466
|
||||
970,615,88
|
||||
941,993,340
|
||||
862,61,35
|
||||
984,92,344
|
||||
425,690,689
|
||||
192
2025/day08/solve.go
Normal file
192
2025/day08/solve.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"container/heap"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type SetEntry struct {
|
||||
parent, size int
|
||||
}
|
||||
|
||||
type DisjointSet struct {
|
||||
set []SetEntry
|
||||
}
|
||||
|
||||
func NewDisjointSet(size int) *DisjointSet {
|
||||
set := make([]SetEntry, size)
|
||||
|
||||
for i := range len(set) {
|
||||
set[i].parent = i
|
||||
set[i].size = 1
|
||||
}
|
||||
|
||||
instance := new(DisjointSet)
|
||||
instance.set = set
|
||||
|
||||
return instance
|
||||
}
|
||||
|
||||
func (d *DisjointSet) Find(item int) int {
|
||||
for d.set[item].parent != item {
|
||||
d.set[item].parent = d.set[d.set[item].parent].parent
|
||||
item = d.set[item].parent
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
func (d *DisjointSet) Union(x, y int) bool {
|
||||
xp := d.Find(x)
|
||||
yp := d.Find(y)
|
||||
|
||||
if xp == yp {
|
||||
return false
|
||||
}
|
||||
|
||||
if yp < xp {
|
||||
xp, yp = yp, xp
|
||||
}
|
||||
|
||||
d.set[xp].size += d.set[yp].size
|
||||
d.set[yp].parent = xp
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (d *DisjointSet) Size(item int) int {
|
||||
if d.set[item].parent == item {
|
||||
return d.set[item].size
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
type DistanceHeap [][3]int
|
||||
|
||||
func (h DistanceHeap) Len() int { return len(h) }
|
||||
func (h DistanceHeap) Less(i, j int) bool { return h[i][0] < h[j][0] }
|
||||
func (h DistanceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
||||
|
||||
func (h *DistanceHeap) Push(x any) {
|
||||
// Push and Pop use pointer receivers because they modify the slice's length,
|
||||
// not just its contents.
|
||||
*h = append(*h, x.([3]int))
|
||||
}
|
||||
|
||||
func (h *DistanceHeap) Pop() any {
|
||||
old := *h
|
||||
n := len(old)
|
||||
x := old[n-1]
|
||||
*h = old[0 : n-1]
|
||||
return x
|
||||
}
|
||||
|
||||
func read_input(filename string) [][3]int {
|
||||
var points [][3]int
|
||||
var point [3]int
|
||||
|
||||
file, err := os.Open(filename)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
reader := bufio.NewReader(file)
|
||||
|
||||
for {
|
||||
parsed, err := fmt.Fscanf(reader, "%d,%d,%d\n", &point[0], &point[1], &point[2])
|
||||
if err != nil || parsed != 3 {
|
||||
break
|
||||
}
|
||||
points = append(points, point)
|
||||
}
|
||||
|
||||
return points
|
||||
}
|
||||
|
||||
func usage() {
|
||||
fmt.Printf("Usage: %v INPUT_FILE [connections]\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func compute_group_sizes(groups *DisjointSet, len int) []int {
|
||||
var sizes []int
|
||||
for i := range len {
|
||||
size := groups.Size(i)
|
||||
if size > 0 {
|
||||
sizes = append(sizes, size)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Ints(sizes)
|
||||
|
||||
return sizes
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
}
|
||||
|
||||
connections := 1000
|
||||
if len(os.Args) >= 3 {
|
||||
parsed, err := strconv.Atoi(os.Args[2])
|
||||
if err != nil {
|
||||
usage()
|
||||
}
|
||||
connections = parsed
|
||||
}
|
||||
|
||||
points := read_input(os.Args[1])
|
||||
|
||||
distances := make([][3]int, 0, len(points)*(len(points)-1)/2)
|
||||
|
||||
for i, a := range points {
|
||||
for j := i + 1; j < len(points); j += 1 {
|
||||
b := points[j]
|
||||
|
||||
square_dist := (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2])
|
||||
|
||||
distances = append(distances, [3]int{square_dist, i, j})
|
||||
}
|
||||
}
|
||||
|
||||
size_heap := DistanceHeap(distances)
|
||||
heap.Init(&size_heap)
|
||||
|
||||
groups := NewDisjointSet(len(points))
|
||||
|
||||
for range connections {
|
||||
first := heap.Pop(&size_heap)
|
||||
d := first.([3]int)
|
||||
groups.Union(d[1], d[2])
|
||||
}
|
||||
|
||||
sizes := compute_group_sizes(groups, len(points))
|
||||
|
||||
product := 1
|
||||
for _, size := range sizes[len(sizes)-3:] {
|
||||
product *= size
|
||||
}
|
||||
|
||||
fmt.Printf("Part 1: %v\n", product)
|
||||
|
||||
to_merge := len(sizes) - 1
|
||||
for {
|
||||
first := heap.Pop(&size_heap)
|
||||
d := first.([3]int)
|
||||
if groups.Union(d[1], d[2]) {
|
||||
to_merge -= 1
|
||||
if to_merge == 0 {
|
||||
fmt.Printf("Part 2: %v\n", points[d[1]][0]*points[d[2]][0])
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
2025/day09/.gitignore
vendored
Normal file
1
2025/day09/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
14
2025/day09/README.md
Normal file
14
2025/day09/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Day 9: Typescript
|
||||
|
||||
Lost a lot of time on a swapped argument order. Oh well, such is life. The `package.json` exists to
|
||||
instruct the interpreter on how to execute the file and doesn't otherwise include any meaningful
|
||||
dependencies. Everything works with the standard library for Node.
|
||||
|
||||
`ts-node` is used for just-in-time Typescript compilation. You can also compile the file manually
|
||||
first, then run it as JS. Also, Oracle, please release the name Javascript.
|
||||
|
||||
```console
|
||||
$ ./solve.ts sample.txt
|
||||
Part 1: 50
|
||||
Part 2: 24
|
||||
```
|
||||
29
2025/day09/package-lock.json
generated
Normal file
29
2025/day09/package-lock.json
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "day09",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.10.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.2.tgz",
|
||||
"integrity": "sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.16.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
6
2025/day09/package.json
Normal file
6
2025/day09/package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.10.2"
|
||||
}
|
||||
}
|
||||
8
2025/day09/sample.txt
Normal file
8
2025/day09/sample.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
7,1
|
||||
11,1
|
||||
11,7
|
||||
9,7
|
||||
9,5
|
||||
2,5
|
||||
2,3
|
||||
7,3
|
||||
78
2025/day09/solve.ts
Executable file
78
2025/day09/solve.ts
Executable file
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env ts-node
|
||||
import * as fs from 'fs';
|
||||
import { exit } from 'process';
|
||||
|
||||
if (process.argv.length < 3) {
|
||||
console.log("Usage: " + process.argv0 + " " + process.argv[1] + " INPUT_FILE");
|
||||
exit(10);
|
||||
}
|
||||
|
||||
const input_file = fs.readFileSync(process.argv[2], "utf-8");
|
||||
const lines = input_file.trim().split("\n");
|
||||
|
||||
class Point {
|
||||
x: number;
|
||||
y: number;
|
||||
|
||||
constructor(x: number, y: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
}
|
||||
|
||||
const points = lines.map(line => {
|
||||
const [x, y] = line.split(",");
|
||||
return new Point(+x, +y);
|
||||
});
|
||||
|
||||
let max_size = 0;
|
||||
let max_size_contained = 0;
|
||||
|
||||
function has_intersection(left: number, right: number, bottom: number, top: number): boolean {
|
||||
for (let i = 0; i < points.length; ++i) {
|
||||
const first = points[i];
|
||||
const second = points[(i + 1) % points.length];
|
||||
|
||||
if (first.x == second.x) {
|
||||
const yMin = Math.min(first.y, second.y);
|
||||
const yMax = Math.max(first.y, second.y);
|
||||
|
||||
if (left < first.x && first.x < right && (yMin <= bottom && bottom < yMax || yMin < top && top <= yMax)) {
|
||||
return true;
|
||||
}
|
||||
} else if (first.y == second.y) {
|
||||
const xMin = Math.min(first.x, second.x);
|
||||
const xMax = Math.max(first.x, second.x);
|
||||
|
||||
if (bottom < first.y && first.y < top && (xMin <= left && left < xMax || xMin < right && right <= xMax)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
throw "Invalid input";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < points.length; ++i) {
|
||||
for (let j = i + 1; j < points.length; ++j) {
|
||||
const left = Math.min(points[i].x, points[j].x);
|
||||
const right = Math.max(points[i].x, points[j].x);
|
||||
const bottom = Math.min(points[i].y, points[j].y);
|
||||
const top = Math.max(points[i].y, points[j].y);
|
||||
|
||||
const width = right - left + 1;
|
||||
const height = top - bottom + 1;
|
||||
|
||||
const area = width * height;
|
||||
|
||||
max_size = Math.max(max_size, area);
|
||||
if (area > max_size_contained && !has_intersection(left, right, bottom, top)) {
|
||||
max_size_contained = area;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Part 1:", max_size);
|
||||
// Too high: 4531758980
|
||||
console.log("Part 2:", max_size_contained);
|
||||
1
2025/day10/.gitignore
vendored
Normal file
1
2025/day10/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
target/
|
||||
7
2025/day10/Cargo.toml
Normal file
7
2025/day10/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "solve"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
microlp = "0.2.11"
|
||||
3
2025/day10/sample.txt
Normal file
3
2025/day10/sample.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
[.##.] (3) (1,3) (2) (2,3) (0,2) (0,1) {3,5,4,7}
|
||||
[...#.] (0,2,3,4) (2,3) (0,4) (0,1,2) (1,2,3,4) {7,5,12,7,2}
|
||||
[.###.#] (0,1,2,3,4) (0,3,4) (0,1,2,4,5) (1,2) {10,11,11,5,10,5}
|
||||
141
2025/day10/src/main.rs
Normal file
141
2025/day10/src/main.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
use std::collections::VecDeque;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
|
||||
use microlp::ComparisonOp;
|
||||
use microlp::LinearExpr;
|
||||
use microlp::OptimizationDirection;
|
||||
use microlp::Problem;
|
||||
|
||||
fn parse_line(line: &str) -> (u32, Vec<u32>, Vec<u8>) {
|
||||
let mut buttons = vec![];
|
||||
let mut target = 0;
|
||||
|
||||
let mut it = line.chars();
|
||||
|
||||
for (i, c) in it.by_ref().skip(1).enumerate() {
|
||||
match c {
|
||||
'#' => target |= 1 << i,
|
||||
'.' => (),
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
match it.nth(1) {
|
||||
Some('{') => break,
|
||||
Some('(') => (),
|
||||
other => panic!("Unexpected character \"{other:?}\" in: {line}"),
|
||||
}
|
||||
|
||||
let mut button = 0;
|
||||
|
||||
while let Some(c) = it.next() {
|
||||
let d = c.to_digit(10).unwrap();
|
||||
button |= 1 << d;
|
||||
|
||||
if let Some(')') = it.next() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buttons.push(button);
|
||||
}
|
||||
|
||||
let rem = it.as_str().trim().trim_end_matches('}');
|
||||
|
||||
let joltage = rem.split(',').map(|j| j.parse().unwrap()).collect();
|
||||
|
||||
(target, buttons, joltage)
|
||||
}
|
||||
|
||||
fn min_joltage(buttons: &[u32], joltage: &[u8]) -> i32 {
|
||||
let mut problem = Problem::new(OptimizationDirection::Minimize);
|
||||
let max = i32::from(*joltage.iter().max().unwrap_or(&0));
|
||||
|
||||
let variables: Vec<_> = buttons
|
||||
.iter()
|
||||
.map(|_| problem.add_integer_var(1.0, (0, max)))
|
||||
.collect();
|
||||
|
||||
for (bit, &value) in joltage.iter().enumerate() {
|
||||
let mut equation = LinearExpr::empty();
|
||||
|
||||
for (&button, &variable) in buttons.iter().zip(&variables) {
|
||||
if button & (1 << bit) != 0 {
|
||||
equation.add(variable, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
problem.add_constraint(equation, ComparisonOp::Eq, value.into());
|
||||
}
|
||||
|
||||
problem.solve().unwrap().objective().round() as i32
|
||||
}
|
||||
|
||||
fn minimum_clicks(target: u32, buttons: &[u32]) -> i32 {
|
||||
let max = buttons
|
||||
.iter()
|
||||
.map(|s| 32 - s.leading_zeros())
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
let possible = 2 << max;
|
||||
let mut seen = vec![false; possible];
|
||||
let mut todo = VecDeque::new();
|
||||
todo.push_back((0, 0));
|
||||
|
||||
while let Some((steps, state)) = todo.pop_front() {
|
||||
for &button in buttons {
|
||||
let next = state ^ button;
|
||||
|
||||
if next == target {
|
||||
return steps + 1;
|
||||
} else if !seen[next as usize] {
|
||||
seen[next as usize] = true;
|
||||
todo.push_back((steps + 1, next));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unreachable!("Did not find target");
|
||||
}
|
||||
|
||||
fn solve(input: &str) -> (i32, i32) {
|
||||
let mut total_clicks = 0;
|
||||
let mut total_presses = 0;
|
||||
for line in input.trim().lines() {
|
||||
let (target, buttons, joltage) = parse_line(line);
|
||||
total_clicks += minimum_clicks(target, &buttons);
|
||||
total_presses += min_joltage(&buttons, &joltage)
|
||||
}
|
||||
|
||||
(total_clicks, total_presses)
|
||||
}
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
if let Some(path) = env::args_os().nth(1) {
|
||||
let input = fs::read_to_string(path)?;
|
||||
|
||||
let (part1, part2) = solve(&input);
|
||||
println!("Part 1: {part1}\nPart 2: {part2}");
|
||||
Ok(())
|
||||
} else {
|
||||
eprintln!("Usage: {} INPUT_FILE", env::args().next().unwrap());
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const SAMPLE: &str = include_str!("../sample.txt");
|
||||
|
||||
#[test]
|
||||
fn test_sample() {
|
||||
let (part1, part2) = solve(SAMPLE);
|
||||
assert_eq!(7, part1);
|
||||
assert_eq!(33, part2);
|
||||
}
|
||||
}
|
||||
10
2025/day11/README.md
Normal file
10
2025/day11/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Day 11: Python
|
||||
|
||||
Straightforward. Uses `networkx` because I thought it would be very helpful but it only really saves
|
||||
me from writing a topological sort algorithm in the end.
|
||||
|
||||
```console
|
||||
$ uv run ./solve.py input.txt
|
||||
Part 1: secret
|
||||
Part 2: secret
|
||||
```
|
||||
9
2025/day11/pyproject.toml
Normal file
9
2025/day11/pyproject.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
[project]
|
||||
name = "solve"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"networkx>=3.6.1",
|
||||
]
|
||||
10
2025/day11/sample.txt
Normal file
10
2025/day11/sample.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
aaa: you hhh
|
||||
you: bbb ccc
|
||||
bbb: ddd eee
|
||||
ccc: ddd eee fff
|
||||
ddd: ggg
|
||||
eee: out
|
||||
fff: out
|
||||
ggg: out
|
||||
hhh: ccc fff iii
|
||||
iii: out
|
||||
14
2025/day11/sample2.txt
Normal file
14
2025/day11/sample2.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
svr: aaa bbb
|
||||
aaa: fft
|
||||
fft: ccc
|
||||
bbb: tty
|
||||
tty: ccc
|
||||
ccc: ddd eee
|
||||
ddd: hub
|
||||
hub: fff
|
||||
eee: dac
|
||||
dac: fff
|
||||
fff: ggg hhh
|
||||
ggg: out
|
||||
hhh: out
|
||||
you: out
|
||||
70
2025/day11/solve.py
Executable file
70
2025/day11/solve.py
Executable file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from collections import defaultdict
|
||||
import fileinput
|
||||
from typing import Iterable
|
||||
|
||||
import networkx as nx
|
||||
|
||||
def parse_graph() -> nx.Graph:
|
||||
graph = nx.DiGraph()
|
||||
|
||||
for line in fileinput.input():
|
||||
source, rem = line.split(": ")
|
||||
|
||||
for sink in rem.strip().split(" "):
|
||||
graph.add_edge(source, sink)
|
||||
|
||||
return graph
|
||||
|
||||
def count(gen: Iterable) -> int:
|
||||
return sum(1 for _ in gen)
|
||||
|
||||
def main() -> None:
|
||||
graph = parse_graph()
|
||||
|
||||
# Observation: graph is a DAG, so one needs to go in front of the other. We can do this in three
|
||||
# steps:
|
||||
# svr → closest(dac, fft) -> furthest(dac,fft)
|
||||
rank = {
|
||||
node: rank
|
||||
for rank, node in enumerate(nx.topological_sort(graph))
|
||||
}
|
||||
|
||||
rev_rank = {rank: node for node, rank in rank.items()}
|
||||
|
||||
if rank["dac"] > rank["fft"]:
|
||||
closest = "fft"
|
||||
furthest = "dac"
|
||||
else:
|
||||
closest = "dac"
|
||||
furthest = "fft"
|
||||
|
||||
|
||||
def ranked_all_paths(source: str, dest: str) -> int:
|
||||
counts = defaultdict(int)
|
||||
|
||||
counts[dest] = 1
|
||||
|
||||
for r in range(rank[dest], rank[source], -1):
|
||||
node = rev_rank[r]
|
||||
if node not in counts:
|
||||
continue
|
||||
|
||||
for u, _ in graph.in_edges(node):
|
||||
counts[u] += counts[node]
|
||||
|
||||
return counts[source]
|
||||
|
||||
assert nx.has_path(graph, closest, furthest)
|
||||
|
||||
print("Part 1", ranked_all_paths("you", "out"))
|
||||
|
||||
first = ranked_all_paths("svr", closest)
|
||||
second = ranked_all_paths(closest, furthest)
|
||||
third = ranked_all_paths(furthest, "out")
|
||||
print("Part 2:", first * second * third)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user