Initial commit

This commit is contained in:
Trevor Merritt 2025-08-23 11:50:36 -04:00
commit a48f5f6d11
28 changed files with 5654 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

77
Cargo.lock generated Normal file
View File

@ -0,0 +1,77 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aoc"
version = "0.1.0"
dependencies = [
"md-5",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "cfg-if"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "md-5"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
dependencies = [
"cfg-if",
"digest",
]
[[package]]
name = "typenum"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"

7
Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name="aoc"
version = "0.1.0"
edition = "2024"
[dependencies]
md-5 = "0.10"

1
data/2015_01_data.txt Normal file

File diff suppressed because one or more lines are too long

1000
data/2015_02_data.txt Normal file

File diff suppressed because it is too large Load Diff

1
data/2015_03_data.txt Normal file

File diff suppressed because one or more lines are too long

1000
data/2015_05_data.txt Normal file

File diff suppressed because it is too large Load Diff

300
data/2015_06_data.txt Normal file
View File

@ -0,0 +1,300 @@
turn off 660,55 through 986,197
turn off 341,304 through 638,850
turn off 199,133 through 461,193
toggle 322,558 through 977,958
toggle 537,781 through 687,941
turn on 226,196 through 599,390
turn on 240,129 through 703,297
turn on 317,329 through 451,798
turn on 957,736 through 977,890
turn on 263,530 through 559,664
turn on 158,270 through 243,802
toggle 223,39 through 454,511
toggle 544,218 through 979,872
turn on 313,306 through 363,621
toggle 173,401 through 496,407
toggle 333,60 through 748,159
turn off 87,577 through 484,608
turn on 809,648 through 826,999
toggle 352,432 through 628,550
turn off 197,408 through 579,569
turn off 1,629 through 802,633
turn off 61,44 through 567,111
toggle 880,25 through 903,973
turn on 347,123 through 864,746
toggle 728,877 through 996,975
turn on 121,895 through 349,906
turn on 888,547 through 931,628
toggle 398,782 through 834,882
turn on 966,850 through 989,953
turn off 891,543 through 914,991
toggle 908,77 through 916,117
turn on 576,900 through 943,934
turn off 580,170 through 963,206
turn on 184,638 through 192,944
toggle 940,147 through 978,730
turn off 854,56 through 965,591
toggle 717,172 through 947,995
toggle 426,987 through 705,998
turn on 987,157 through 992,278
toggle 995,774 through 997,784
turn off 796,96 through 845,182
turn off 451,87 through 711,655
turn off 380,93 through 968,676
turn on 263,468 through 343,534
turn on 917,936 through 928,959
toggle 478,7 through 573,148
turn off 428,339 through 603,624
turn off 400,880 through 914,953
toggle 679,428 through 752,779
turn off 697,981 through 709,986
toggle 482,566 through 505,725
turn off 956,368 through 993,516
toggle 735,823 through 783,883
turn off 48,487 through 892,496
turn off 116,680 through 564,819
turn on 633,865 through 729,930
turn off 314,618 through 571,922
toggle 138,166 through 936,266
turn on 444,732 through 664,960
turn off 109,337 through 972,497
turn off 51,432 through 77,996
turn off 259,297 through 366,744
toggle 801,130 through 917,544
toggle 767,982 through 847,996
turn on 216,507 through 863,885
turn off 61,441 through 465,731
turn on 849,970 through 944,987
toggle 845,76 through 852,951
toggle 732,615 through 851,936
toggle 251,128 through 454,778
turn on 324,429 through 352,539
toggle 52,450 through 932,863
turn off 449,379 through 789,490
turn on 317,319 through 936,449
toggle 887,670 through 957,838
toggle 671,613 through 856,664
turn off 186,648 through 985,991
turn off 471,689 through 731,717
toggle 91,331 through 750,758
toggle 201,73 through 956,524
toggle 82,614 through 520,686
toggle 84,287 through 467,734
turn off 132,367 through 208,838
toggle 558,684 through 663,920
turn on 237,952 through 265,997
turn on 694,713 through 714,754
turn on 632,523 through 862,827
turn on 918,780 through 948,916
turn on 349,586 through 663,976
toggle 231,29 through 257,589
toggle 886,428 through 902,993
turn on 106,353 through 236,374
turn on 734,577 through 759,684
turn off 347,843 through 696,912
turn on 286,699 through 964,883
turn on 605,875 through 960,987
turn off 328,286 through 869,461
turn off 472,569 through 980,848
toggle 673,573 through 702,884
turn off 398,284 through 738,332
turn on 158,50 through 284,411
turn off 390,284 through 585,663
turn on 156,579 through 646,581
turn on 875,493 through 989,980
toggle 486,391 through 924,539
turn on 236,722 through 272,964
toggle 228,282 through 470,581
toggle 584,389 through 750,761
turn off 899,516 through 900,925
turn on 105,229 through 822,846
turn off 253,77 through 371,877
turn on 826,987 through 906,992
turn off 13,152 through 615,931
turn on 835,320 through 942,399
turn on 463,504 through 536,720
toggle 746,942 through 786,998
turn off 867,333 through 965,403
turn on 591,477 through 743,692
turn off 403,437 through 508,908
turn on 26,723 through 368,814
turn on 409,485 through 799,809
turn on 115,630 through 704,705
turn off 228,183 through 317,220
toggle 300,649 through 382,842
turn off 495,365 through 745,562
turn on 698,346 through 744,873
turn on 822,932 through 951,934
toggle 805,30 through 925,421
toggle 441,152 through 653,274
toggle 160,81 through 257,587
turn off 350,781 through 532,917
toggle 40,583 through 348,636
turn on 280,306 through 483,395
toggle 392,936 through 880,955
toggle 496,591 through 851,934
turn off 780,887 through 946,994
turn off 205,735 through 281,863
toggle 100,876 through 937,915
turn on 392,393 through 702,878
turn on 956,374 through 976,636
toggle 478,262 through 894,775
turn off 279,65 through 451,677
turn on 397,541 through 809,847
turn on 444,291 through 451,586
toggle 721,408 through 861,598
turn on 275,365 through 609,382
turn on 736,24 through 839,72
turn off 86,492 through 582,712
turn on 676,676 through 709,703
turn off 105,710 through 374,817
toggle 328,748 through 845,757
toggle 335,79 through 394,326
toggle 193,157 through 633,885
turn on 227,48 through 769,743
toggle 148,333 through 614,568
toggle 22,30 through 436,263
toggle 547,447 through 688,969
toggle 576,621 through 987,740
turn on 711,334 through 799,515
turn on 541,448 through 654,951
toggle 792,199 through 798,990
turn on 89,956 through 609,960
toggle 724,433 through 929,630
toggle 144,895 through 201,916
toggle 226,730 through 632,871
turn off 760,819 through 828,974
toggle 887,180 through 940,310
toggle 222,327 through 805,590
turn off 630,824 through 885,963
turn on 940,740 through 954,946
turn on 193,373 through 779,515
toggle 304,955 through 469,975
turn off 405,480 through 546,960
turn on 662,123 through 690,669
turn off 615,238 through 750,714
turn on 423,220 through 930,353
turn on 329,769 through 358,970
toggle 590,151 through 704,722
turn off 884,539 through 894,671
toggle 449,241 through 984,549
toggle 449,260 through 496,464
turn off 306,448 through 602,924
turn on 286,805 through 555,901
toggle 722,177 through 922,298
toggle 491,554 through 723,753
turn on 80,849 through 174,996
turn off 296,561 through 530,856
toggle 653,10 through 972,284
toggle 529,236 through 672,614
toggle 791,598 through 989,695
turn on 19,45 through 575,757
toggle 111,55 through 880,871
turn off 197,897 through 943,982
turn on 912,336 through 977,605
toggle 101,221 through 537,450
turn on 101,104 through 969,447
toggle 71,527 through 587,717
toggle 336,445 through 593,889
toggle 214,179 through 575,699
turn on 86,313 through 96,674
toggle 566,427 through 906,888
turn off 641,597 through 850,845
turn on 606,524 through 883,704
turn on 835,775 through 867,887
toggle 547,301 through 897,515
toggle 289,930 through 413,979
turn on 361,122 through 457,226
turn on 162,187 through 374,746
turn on 348,461 through 454,675
turn off 966,532 through 985,537
turn on 172,354 through 630,606
turn off 501,880 through 680,993
turn off 8,70 through 566,592
toggle 433,73 through 690,651
toggle 840,798 through 902,971
toggle 822,204 through 893,760
turn off 453,496 through 649,795
turn off 969,549 through 990,942
turn off 789,28 through 930,267
toggle 880,98 through 932,434
toggle 568,674 through 669,753
turn on 686,228 through 903,271
turn on 263,995 through 478,999
toggle 534,675 through 687,955
turn off 342,434 through 592,986
toggle 404,768 through 677,867
toggle 126,723 through 978,987
toggle 749,675 through 978,959
turn off 445,330 through 446,885
turn off 463,205 through 924,815
turn off 417,430 through 915,472
turn on 544,990 through 912,999
turn off 201,255 through 834,789
turn off 261,142 through 537,862
turn off 562,934 through 832,984
turn off 459,978 through 691,980
turn off 73,911 through 971,972
turn on 560,448 through 723,810
turn on 204,630 through 217,854
turn off 91,259 through 611,607
turn on 877,32 through 978,815
turn off 950,438 through 974,746
toggle 426,30 through 609,917
toggle 696,37 through 859,201
toggle 242,417 through 682,572
turn off 388,401 through 979,528
turn off 79,345 through 848,685
turn off 98,91 through 800,434
toggle 650,700 through 972,843
turn off 530,450 through 538,926
turn on 428,559 through 962,909
turn on 78,138 through 92,940
toggle 194,117 through 867,157
toggle 785,355 through 860,617
turn off 379,441 through 935,708
turn off 605,133 through 644,911
toggle 10,963 through 484,975
turn off 359,988 through 525,991
turn off 509,138 through 787,411
toggle 556,467 through 562,773
turn on 119,486 through 246,900
turn on 445,561 through 794,673
turn off 598,681 through 978,921
turn off 974,230 through 995,641
turn off 760,75 through 800,275
toggle 441,215 through 528,680
turn off 701,636 through 928,877
turn on 165,753 through 202,780
toggle 501,412 through 998,516
toggle 161,105 through 657,395
turn on 113,340 through 472,972
toggle 384,994 through 663,999
turn on 969,994 through 983,997
turn on 519,600 through 750,615
turn off 363,899 through 948,935
turn on 271,845 through 454,882
turn off 376,528 through 779,640
toggle 767,98 through 854,853
toggle 107,322 through 378,688
turn off 235,899 through 818,932
turn on 445,611 through 532,705
toggle 629,387 through 814,577
toggle 112,414 through 387,421
toggle 319,184 through 382,203
turn on 627,796 through 973,940
toggle 602,45 through 763,151
turn off 441,375 through 974,545
toggle 871,952 through 989,998
turn on 717,272 through 850,817
toggle 475,711 through 921,882
toggle 66,191 through 757,481
turn off 50,197 through 733,656
toggle 83,575 through 915,728
turn on 777,812 through 837,912
turn on 20,984 through 571,994
turn off 446,432 through 458,648
turn on 715,871 through 722,890
toggle 424,675 through 740,862
toggle 580,592 through 671,900
toggle 296,687 through 906,775

1
data/2016_01_data.txt Normal file
View File

@ -0,0 +1 @@
L3, R1, L4, L1, L2, R4, L3, L3, R2, R3, L5, R1, R3, L4, L1, L2, R2, R1, L4, L4, R2, L5, R3, R2, R1, L1, L2, R2, R2, L1, L1, R2, R1, L3, L5, R4, L3, R3, R3, L5, L190, L4, R4, R51, L4, R5, R5, R2, L1, L3, R1, R4, L3, R1, R3, L5, L4, R2, R5, R2, L1, L5, L1, L1, R78, L3, R2, L3, R5, L2, R2, R4, L1, L4, R1, R185, R3, L4, L1, L1, L3, R4, L4, L1, R5, L5, L1, R5, L1, R2, L5, L2, R4, R3, L2, R3, R1, L3, L5, L4, R3, L2, L4, L5, L4, R1, L1, R5, L2, R4, R2, R3, L1, L1, L4, L3, R4, L3, L5, R2, L5, L1, L1, R2, R3, L5, L3, L2, L1, L4, R4, R4, L2, R3, R1, L2, R1, L2, L2, R3, R3, L1, R4, L5, L3, R4, R4, R1, L2, L5, L3, R1, R4, L2, R5, R4, R2, L5, L3, R4, R1, L1, R5, L3, R1, R5, L2, R1, L5, L2, R2, L2, L3, R3, R3, R1

1000
data/2024_01_data.txt Normal file

File diff suppressed because it is too large Load Diff

1000
data/2024_02_data.txt Normal file

File diff suppressed because it is too large Load Diff

42
src/bin/2015_01a.rs Normal file
View File

@ -0,0 +1,42 @@
// Santa was hoping for a white Christmas, but his weather machine's "snow" function is powered by
// stars, and he's fresh out! To save Christmas, he needs you to collect fifty stars by December
// 25th.
//
// Santa is trying to deliver presents in a large apartment building, but he can't find the right
// floor - the directions he got are a little confusing. He starts on the ground floor (floor 0)
// and then follows the instructions one character at a time.
//
// An opening parenthesis, (, means he should go up one floor, and a closing parenthesis, ), means
// he should go down one floor.
//
// The apartment building is very tall, and the basement is very deep; he will never find the top
// or bottom floors.
//
// For example:
//
// (()) and ()() both result in floor 0.
// ((( and (()(()( both result in floor 3.
// ))((((( also results in floor 3.
// ()) and ))( both result in floor -1 (the first basement level).
// ))) and )())()) both result in floor -3.
// To what floor do the instructions take Santa?
//
use aoc::read_data;
fn main() {
let instructions = read_data("2015_01_data.txt");
let mut current_floor = 0;
for next_direction in instructions.chars() {
match next_direction {
')' => current_floor -= 1,
'(' => current_floor += 1,
_ => {
panic!("Invalid Direction. Santa got lost.");
}
}
}
println!("Ending on floor {}", current_floor);
}
// 232

32
src/bin/2015_01b.rs Normal file
View File

@ -0,0 +1,32 @@
// Now, given the same instructions, find the position of the first character that causes him to enter the basement (floor -1). The first character in the instructions has position 1, the second character has position 2, and so on.
//
// For example:
//
// ) causes him to enter the basement at character position 1.
// ()()) causes him to enter the basement at character position 5.
// What is the position of the character that causes Santa to first enter the basement?
//
use aoc::read_data;
fn main() {
let instructions = read_data("2015_01_data.txt");
let mut has_hit_basement = false;
let mut current_floor = 0;
for (index, next_direction) in instructions.chars().enumerate() {
match next_direction {
')' => current_floor -= 1,
'(' => current_floor += 1,
_ => {
panic!("Invalid Direction. Santa got lost.");
}
}
if !has_hit_basement && current_floor == -1 {
has_hit_basement = true;
println!("Hit the basement on step {}", index + 1);
}
}
}
// 1783

82
src/bin/2015_02a.rs Normal file
View File

@ -0,0 +1,82 @@
// The elves are running low on wrapping paper, and so they need to submit an order for more. They
// have a list of the dimensions (length l, width w, and height h) of each present, and only want
// to order exactly as much as they need.
//
// Fortunately, every present is a box (a perfect right rectangular prism), which makes calculating
// the required wrapping paper for each gift a little easier: find the surface area of the box,
// which is 2*l*w + 2*w*h + 2*h*l. The elves also need a little extra paper for each present: the
// area of the smallest side.
//
// For example:
//
// A present with dimensions 2x3x4 requires 2*6 + 2*12 + 2*8 = 52 square feet of wrapping paper
// plus 6 square feet of slack, for a total of 58 square feet.
// A present with dimensions 1x1x10 requires 2*1 + 2*10 + 2*10 = 42 square feet of wrapping paper
// plus 1 square foot of slack, for a total of 43 square feet.
// All numbers in the elves' list are in feet. How many total square feet of wrapping paper should
// they order?
//
use aoc::read_data;
fn smallest_of_vec(to_check: &Vec<u32>) -> u32 {
let mut working = to_check[0];
for current in to_check {
if current < &working {
working = *current
}
}
working
}
fn sum_of_vec(to_add: &Vec<u32>) -> u32 {
let mut working = 0;
for current in to_add {
working += current
}
working
}
fn calculate_wrapping_needed(length: u32, width: u32, height: u32) -> u32 {
let sides = vec![
2 * length * width,
2 * width * height,
2 * height * length
];
// everything is *2 for size so we need half of it for our calc
let min_side = smallest_of_vec(&sides) / 2;
sum_of_vec(&sides) + min_side
}
fn split_str(input: &str) -> Option<(u32, u32, u32)> {
let parts: Vec<&str> = input.split('x').collect();
if parts.len() == 3 {
if let (Ok(a), Ok(b), Ok(c)) = (
parts[0].parse::<u32>(),
parts[1].parse::<u32>(),
parts[2].parse::<u32>(),
) {
return Some((a, b, c));
}
}
None
}
fn main() {
println!("Need {} for 2x3x4", calculate_wrapping_needed(2,3,4));
println!("Need {} for 1x1x10", calculate_wrapping_needed(1,1,10));
let binding = read_data("2015_02_data.txt");
let sizes = binding.lines();
let mut working = 0;
for size in sizes {
let (l, w, h) = split_str(size).unwrap();
let needed = calculate_wrapping_needed(l, w, h);
// println!("Need {} for {}", needed, size);
working += needed;
}
println!("You need {}.", working);
}
// 1586300.

64
src/bin/2015_02b.rs Normal file
View File

@ -0,0 +1,64 @@
// The elves are also running low on ribbon. Ribbon is all the same width, so they only have to
// worry about the length they need to order, which they would again like to be exact.
//
// The ribbon required to wrap a present is the shortest distance around its sides, or the smallest
// perimeter of any one face. Each present also requires a bow made out of ribbon as well; the feet
// of ribbon required for the perfect bow is equal to the cubic feet of volume of the present.
// Don't ask how they tie the bow, though; they'll never tell.
//
// For example:
//
// A present with dimensions 2x3x4 requires 2+2+3+3 = 10 feet of ribbon to wrap the present
// plus 2*3*4 = 24 feet of ribbon for the bow, for a total of 34 feet.
// A present with dimensions 1x1x10 requires 1+1+1+1 = 4 feet of ribbon to wrap the present
// plus 1*1*10 = 10 feet of ribbon for the bow, for a total of 14 feet.
// How many total feet of ribbon should they order?
//
use aoc::read_data;
fn bow_ribbon_length(l: u32, w: u32, h: u32) -> u32 {
l * w * h
}
fn ribbon_for_sides(l: u32, w: u32, h: u32) -> u32 {
let to_remove = l.max(w).max(h) * 2;
let working = 2 * l + 2 * w + 2 * h;
working - to_remove
}
fn ribbon_for_package(l: u32, w: u32, h: u32) -> u32 {
ribbon_for_sides(l, w, h) + bow_ribbon_length(l, w, h)
}
fn split_str(input: &str) -> Option<(u32, u32, u32)> {
let parts: Vec<&str> = input.split('x').collect();
if parts.len() == 3 {
if let (Ok(a), Ok(b), Ok(c)) = (
parts[0].parse::<u32>(),
parts[1].parse::<u32>(),
parts[2].parse::<u32>(),
) {
return Some((a, b, c));
}
}
None
}
fn main() {
println!("Box sized {} requires {}", "2x3x4", ribbon_for_package(2,3,4));
println!("Box sized {} requires {}", "1x1x10", ribbon_for_package(1,1,10));
let sizes = read_data("2015_02_data.txt").lines();
let mut total_ribbon = 0;
for size in sizes {
let (l, w, h) = split_str(size).unwrap();
let needed = ribbon_for_package(l, w, h);
println!("Need {} for {}", needed, size);
total_ribbon += needed
}
println!("Need a total of {}", total_ribbon);
}
// 3737498

55
src/bin/2015_03a.rs Normal file
View File

@ -0,0 +1,55 @@
// Santa is delivering presents to an infinite two-dimensional grid of houses.
//
// He begins by delivering a present to the house at his starting location, and then an elf at the
// North Pole calls him via radio and tells him where to move next. Moves are always exactly one
// house to the north (^), south (v), east (>), or west (<). After each move, he delivers another
// present to the house at his new location.
//
// However, the elf back at the north pole has had a little too much eggnog, and so his directions
// are a little off, and Santa ends up visiting some houses more than once. How many houses receive
// at least one present?
//
// For example:
//
// > delivers presents to 2 houses: one at the starting location, and one to the east.
// ^>v< delivers presents to 4 houses in a square, including twice to the house at his
// starting/ending location.
// ^v^v^v^v^v delivers a bunch of presents to some very lucky children at only 2 houses.
use std::collections::HashMap;
use aoc::read_data;
fn main() {
let mut visits: HashMap<String, u32> = HashMap::from([("0x0".to_string(), 1)]);
let (mut current_x, mut current_y) = (0,0);
let instructions = read_data("2015_03_data.txt");
for current_instruction in instructions.chars() {
match current_instruction {
'^' => {
println!("Move North 1");
current_y += 1;
},
'v' => {
println!("Move South 1");
current_y -= 1;
},
'<' => {
println!("Move West 1");
current_x -= 1;
},
'>' => {
println!("Move East 1");
current_x += 1;
},
_ => { unreachable!("Invalid instruction -> {}", &current_instruction); }
}
let current_address = format!("{}x{}", current_x, current_y);
*visits.entry(current_address).and_modify(|x| *x += 1).or_insert(1);
}
println!("Found {} houses got presents.", visits.keys().count());
println!("Taxation is theft.");
}
// 2081

83
src/bin/2015_03b.rs Normal file
View File

@ -0,0 +1,83 @@
// The next year, to speed up the process, Santa creates a robot version of himself, Robo-Santa,
// to deliver presents with him.
//
// Santa and Robo-Santa start at the same location (delivering two presents to the same starting
// house), then take turns moving based on instructions from the elf, who is eggnoggedly reading
// from the same script as the previous year.
//
// This year, how many houses receive at least one present?
//
// For example:
//
// ^v delivers presents to 3 houses, because Santa goes north, and then Robo-Santa goes south.
// ^>v< now delivers presents to 3 houses, and Santa and Robo-Santa end up back where they started.
// ^v^v^v^v^v now delivers presents to 11 houses, with Santa going one direction and Robo-Santa
// going the other.
use std::collections::HashMap;
use aoc::read_data;
fn num_houses(directions: &str) -> u32 {
let (mut santa_x, mut santa_y, mut robo_x, mut robo_y) = (0,0,0,0);
let mut visits = HashMap::from([("0x0".to_string(), 1)]);
let mut santas_turn = true;
for current_instruction in directions.chars() {
match current_instruction {
'^' => {
if santas_turn {
santa_y += 1;
} else {
robo_y += 1;
}
},
'v' => {
if santas_turn {
santa_y -= 1;
} else {
robo_y -= 1;
}
},
'<' => {
if santas_turn {
santa_x -= 1;
} else {
robo_x -= 1;
}
},
'>' => {
if santas_turn {
santa_x += 1;
} else {
robo_x += 1;
}
}
_ => { unreachable!("Invalid Instruction"); }
}
let current_address = if santas_turn {
format!("{}x{}", santa_x, santa_y)
} else {
format!("{}x{}", robo_x, robo_y)
};
println!("V:{} S:{}x{} R:{}x{} V#:{}", current_address, santa_x, santa_y, robo_x, robo_y, visits.keys().count());
*visits.entry(current_address).and_modify(|x| *x += 1).or_insert(1);
santas_turn = !santas_turn;
}
visits.keys().count() as u32
}
fn main() {
let directions = read_data("2015_03_data.txt");
let params = vec![
("^v", 3),
("^>v<", 3),
("^v^v^v^v^v", 11),
(directions.as_str(), 0)
];
for (input, expected) in params {
println!("{:<20} resolves to {} houses.", input, num_houses(input));
}
}
// 2341

59
src/bin/2015_04a.rs Normal file
View File

@ -0,0 +1,59 @@
// Santa needs help mining some AdventCoins (very similar to bitcoins) to use as gifts for all the
// economically forward-thinking little girls and boys.
//
// To do this, he needs to find MD5 hashes which, in hexadecimal, start with at least five zeroes.
// The input to the MD5 hash is some secret key (your puzzle input, given below) followed by a
// number in decimal. To mine AdventCoins, you must find Santa the lowest positive number (no
// leading zeroes: 1, 2, 3, ...) that produces such a hash.
//
// For example:
//
// If your secret key is abcdef, the answer is 609043, because the MD5 hash of abcdef609043 starts
// with five zeroes (000001dbbfa...), and it is the lowest such number to do so.
// If your secret key is pqrstuv, the lowest number it combines with to make an MD5 hash starting
// with five zeroes is 1048970; that is, the MD5 hash of pqrstuv1048970 looks like 000006136ef....
use std::io::{stdout, Write};
use md5::{Digest, Md5};
const INPUT: &str = "bgvyzdsv";
fn calculate_hash(input_id: u32, seed: &str) -> String {
let to_hash = format!("{}{}", seed, input_id);
let as_hash = format!("{:x}", Md5::digest(to_hash.as_bytes()));
as_hash
}
fn main() {
println!("abcdef609043 -> {}", calculate_hash(609043, "abcdef"));
println!("pqrstuv1048970 -> {}", calculate_hash(1048970, "pqrstuv"));
let mut need5 = true;
let mut need6 = true;
for number in 0..u32::MAX {
let hashed = calculate_hash(number, INPUT);
// are the first 6 characters 0?
if need5 {
if hashed.starts_with("00000") {
println!("5 zeros -> {}{} / {}", INPUT, number, hashed);
need5 = false;
}
}
if need6 {
if hashed.starts_with("000000") {
println!("6 zeros -> {}{} / {}", INPUT, number, hashed);
need6 = false;
}
}
if hashed.starts_with("0000000") {
println!("7 zeros -> {}{} / {}", INPUT, number, hashed);
} // 318_903_846
if number % 100_000 == 0 && !need6 && !need5 {
print!(".");
stdout().flush().unwrap()
}
}
}

89
src/bin/2015_05a.rs Normal file
View File

@ -0,0 +1,89 @@
// Santa needs help figuring out which strings in his text file are naughty or nice.
//
// A nice string is one with all of the following properties:
//
// It contains at least three vowels (aeiou only), like aei, xazegov, or aeiouaeiouaeiou.
// It contains at least one letter that appears twice in a row, like xx, abcdde (dd),
// or aabbccdd (aa, bb, cc, or dd).
// It does not contain the strings ab, cd, pq, or xy, even if they are part of one of the other
// requirements.
// For example:
//
// ugknbfddgicrmopn is nice because it has at least three vowels (u...i...o...), a double letter
// (...dd...), and none of the disallowed substrings.
// aaa is nice because it has at least three vowels and a double letter, even though the letters
// used by different rules overlap.
// jchzalrnumimnmhp is naughty because it has no double letter.
// haegwjzuvuyypxyu is naughty because it contains the string xy.
// dvszwmarrgswjxmb is naughty because it contains only one vowel.
// How many strings are nice?
//
use aoc::read_data;
fn no_banned_parts(to_check: &str) -> bool {
!to_check.contains("ab") &&
!to_check.contains("cd") &&
!to_check.contains("pq") &&
!to_check.contains("xy")
}
fn has_doubled_letter(to_check: &str) -> bool {
let mut has_doubled = false;
let mut last_char = ' ';
for current in to_check.chars() {
if current == last_char {
has_doubled = true
}
last_char = current
}
has_doubled
}
fn contains_three_vowels(to_check: &str) -> bool {
let mut num_vowels = 0;
for current in to_check.chars() {
match current {
'a' | 'e' | 'i' | 'o' | 'u' => {
num_vowels += 1;
}
_ => {}
}
}
num_vowels >= 3
}
fn is_nice(to_check: &str) -> bool {
let vowels = contains_three_vowels(to_check);
let has_doubled = has_doubled_letter(to_check);
let no_banned = no_banned_parts(to_check);
// println!("{} -> V{} D{} B{}", to_check, vowels, has_doubled, no_banned);
vowels && has_doubled && no_banned
}
fn main() {
println!("ugknbfddgicrmopn is nice -> {}", is_nice("ugknbfddgicrmopn"));
println!("aaa is nice -> {}", is_nice("aaa"));
println!("jchzalrnumimnmhp is NOT nice -> {}", is_nice("jchzalrnumimnmhp"));
println!("haegwjzuvuyypxyu is NOT nice -> {}", is_nice("haegwjzuvuyypxyu"));
println!("dvszwmarrgswjxmb is NOT nice -> {}", is_nice("dvszwmarrgswjxmb"));
let binding = read_data("2015_05_data.txt");
let lines = binding.lines();
let mut nice = 0;
let num_lines = lines.clone().count();
for line in lines {
if is_nice(line) {
nice += 1;
}
}
println!("There are {} nice out of {} words.", nice, num_lines);
}
// 236

57
src/bin/2015_05b.rs Normal file
View File

@ -0,0 +1,57 @@
#![feature(substr_range)]
// Realizing the error of his ways, Santa has switched to a better model of determining whether a
// string is naughty or nice. None of the old rules apply, as they are all clearly ridiculous.
//
// Now, a nice string is one with all of the following properties:
//
// It contains a pair of any two letters that appears at least twice in the string without
// overlapping, like xyxy (xy) or aabcdefgaa (aa), but not like aaa (aa, but it overlaps).
// It contains at least one letter which repeats with exactly one letter between them, like xyx,
// abcdefeghi (efe), or even aaa.
// For example:
//
// qjhvhtzxzqqjkmpb is nice because is has a pair that appears twice (qj) and a letter that repeats
// with exactly one letter between them (zxz).
// xxyxx is nice because it has a pair that appears twice and a letter that repeats with one
// between, even though the letters used by each rule overlap.
// uurcxstgmygtbstg is naughty because it has a pair (tg) but no repeat with a single letter
// between them.
// ieodomkazucvgmuy is naughty because it has a repeating letter with one between (odo), but no
// pair that appears twice.
fn appears_twice_without_overlapping(to_check: &str) -> bool {
true
}
fn letter_repeated_seperated_by_1(to_check: &str) -> bool {
println!("Starting to check for XyX");
let mut has_criteria = false;
let mut two_back = ' ';
let mut one_back = ' ';
for (index, current) in to_check.chars().enumerate() {
if current == two_back {
has_criteria = true;
println!("Found a seperated pair. {index} / {to_check}");
break;
}
two_back = one_back;
one_back = current;
}
has_criteria
}
fn is_nice(to_check: &str) -> bool {
appears_twice_without_overlapping(to_check) &&
letter_repeated_seperated_by_1(to_check)
}
fn main() {
println!("qjhvhtzxzqqjkmpb is nice -> {}", is_nice("qjhvhtzxzqqjkmpb"));
println!("xxyxx is nice -> {}", is_nice("xxyxx"));
println!("uurcxstgmygtbstg is NOT nice -> {}", is_nice("uurcxstgmygtbstg"));
println!("ieodomkazucvgmuy is NOT nice -> {}", is_nice("ieodomkazucvgmuy"));
}

72
src/bin/2015_06a.rs Normal file
View File

@ -0,0 +1,72 @@
// Because your neighbors keep defeating you in the holiday house decorating contest year after
// year, you've decided to deploy one million lights in a 1000x1000 grid.
//
// Furthermore, because you've been especially nice this year, Santa has mailed you instructions
// on how to display the ideal lighting configuration.
//
// Lights in your grid are numbered from 0 to 999 in each direction; the lights at each corner are
// at 0,0, 0,999, 999,999, and 999,0. The instructions include whether to turn on, turn off, or
// toggle various inclusive ranges given as coordinate pairs. Each coordinate pair represents
// opposite corners of a rectangle, inclusive; a coordinate pair like 0,0 through 2,2 therefore
// refers to 9 lights in a 3x3 square. The lights all start turned off.
//
// To defeat your neighbors this year, all you have to do is set up your lights by doing the
// instructions Santa sent you in order.
//
// For example:
//
// turn on 0,0 through 999,999 would turn on (or leave on) every light.
// toggle 0,0 through 999,0 would toggle the first line of 1000 lights, turning off the ones that
// were on, and turning on the ones that were off.
// turn off 499,499 through 500,500 would turn off (or leave off) the middle four lights.
// After following the instructions, how many lights are lit?
use aoc::read_data;
fn main() {
let mut block: [bool; 1000*1000] = [false; 1000*1000];
let binding = read_data("2015_06_data.txt");
let lines: Vec<&str> = binding.lines().collect();
for instruction in lines {
let parts: Vec<&str> = instruction.split(' ').collect();
match parts.len() {
5 => {
let start_parts: Vec<u32> = parts[2].split(',').map(|x| x.parse().unwrap()).collect();
let end_parts: Vec<u32> =parts[4].split(',').map(|x| x.parse().unwrap()).collect();
// figure out if the [1] item is 'on' or 'off'
let target_state = if parts[1] == "on" { true } else { false };
for x in start_parts[0]..=end_parts[0] {
for y in start_parts[1]..=end_parts[1] {
let offset = (x * 1000) + y;
// println!("Setting {}x{}({}) to {}", x, y, offset, target_state);
block[offset as usize] = target_state;
}
}
}
4 => {
// toggle
let start_parts: Vec<u32> = parts[1].split(',').map(|x| x.parse().unwrap()).collect();
let end_parts: Vec<u32> =parts[3].split(',').map(|x| x.parse().unwrap()).collect();
// println!("[{}] Toggling from {}x{} to {}x{}", instruction, start_parts[0], start_parts[1], end_parts[0], end_parts[1]);
for x in start_parts[0]..=end_parts[0] {
for y in start_parts[1]..=end_parts[1] {
let offset = ((x * 1000) + y) as usize;
let current = block[offset];
// println!("Toggling {}x{} from {}", x, y, current);
block[offset] = !current;
}
}
},
_ => { unreachable!("Invalid number of parts") }
}
}
println!("Tallying lights...");
let mut num_lit = 0;
for current in block {
if current { num_lit += 1; }
}
println!("Counted {} lights.", num_lit);
}
// 400410

72
src/bin/2015_06b.rs Normal file
View File

@ -0,0 +1,72 @@
// You just finish implementing your winning light pattern when you realize you mistranslated
// Santa's message from Ancient Nordic Elvish.
//
// The light grid you bought actually has individual brightness controls; each light can have a
// brightness of zero or more. The lights all start at zero.
//
// The phrase turn on actually means that you should increase the brightness of those lights by 1.
//
// The phrase turn off actually means that you should decrease the brightness of those lights by 1,
// to a minimum of zero.
//
// The phrase toggle actually means that you should increase the brightness of those lights by 2.
//
// What is the total brightness of all lights combined after following Santa's instructions?
//
// For example:
//
// turn on 0,0 through 0,0 would increase the total brightness by 1.
// toggle 0,0 through 999,999 would increase the total brightness by 2000000.
use aoc::read_data;
fn main() {
let mut block: Box<[u32; 1000*1000]> = Box::new([0; 1000*1000]);
let binding = read_data("2015_06_data.txt");
let lines: Vec<&str> = binding.lines().collect();
for instruction in lines {
let parts: Vec<&str> = instruction.split(' ').collect();
match parts.len() {
5 => {
let start_parts: Vec<u32> = parts[2].split(',').map(|x| x.parse().unwrap()).collect();
let end_parts: Vec<u32> = parts[4].split(',').map(|x| x.parse().unwrap()).collect();
for x in start_parts[0]..=end_parts[0] {
for y in start_parts[1]..=end_parts[1] {
let offset = (x * 1000 + y) as usize;
if parts[1] == "on" {
block[offset] += 1;
} else {
if block[offset] > 0 {
block[offset] -= 1;
}
}
}
}
},
4 => {
let start_parts: Vec<u32> = parts[1].split(',').map(|x| x.parse().unwrap()).collect();
let end_parts: Vec<u32> = parts[3].split(',').map(|x| x.parse().unwrap()).collect();
for x in start_parts[0]..=end_parts[0] {
for y in start_parts[1]..=end_parts[1] {
let offset = ((x * 1000) + y) as usize;
block[offset] += 2;
}
}
}
_ => {
unreachable!("Invalid direction -> [{}]", instruction);
}
}
}
let mut working: u64 = 0;
for current in block.iter() {
working += *current as u64;
}
println!("Total Brightness = {}", working);
}
// 15343601

118
src/bin/2016_01a.rs Normal file
View File

@ -0,0 +1,118 @@
// Santa's sleigh uses a very high-precision clock to guide its movements, and the clock's
// oscillator is regulated by stars. Unfortunately, the stars have been stolen... by the Easter
// Bunny. To save Christmas, Santa needs you to retrieve all fifty stars by December 25th.
//
// Collect stars by solving puzzles. Two puzzles will be made available on each day in the Advent
// calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one
// star. Good luck!
//
// You're airdropped near Easter Bunny Headquarters in a city somewhere. "Near", unfortunately, is
// as close as you can get - the instructions on the Easter Bunny Recruiting Document the Elves
// intercepted start here, and nobody had time to work them out further.
//
// The Document indicates that you should start at the given coordinates (where you just landed)
// and face North. Then, follow the provided sequence: either turn left (L) or right (R) 90
// degrees, then walk forward the given number of blocks, ending at a new intersection.
//
// There's no time to follow such ridiculous instructions on foot, though, so you take a moment
// and work out the destination. Given that you can only walk on the street grid of the city,
// how far is the shortest path to the destination?
//
// For example:
//
// Following R2, L3 leaves you 2 blocks East and 3 blocks North, or 5 blocks away.
// R2, R2, R2 leaves you 2 blocks due South of your starting position, which is 2 blocks away.
// R5, L5, R5, R3 leaves you 12 blocks away.
// How many blocks away is Easter Bunny HQ?
//
use std::{env, fs};
use crate::CardinalDirection::*;
#[derive(Debug)]
enum CardinalDirection {
North,
South,
East,
West
}
fn manhattan_distance(directions: &str) -> i32 {
let (mut x_distance, mut y_distance, mut x_move, mut y_move) = (0i32,0i32, 0i32, 0i32);
let mut current_direction = North;
for next_direction in directions.split(", ") {
let (direction, vector) = next_direction.split_at(1);
let distance = vector.parse().unwrap();
// print!("[{}] At {x_distance}x{y_distance}, FACING {current_direction:?}, TURN {} MOVE {} ::::::", next_direction, direction, distance);
x_move = 0; y_move = 0;
match direction {
"R" => {
match current_direction {
North => {
current_direction = East;
x_move = distance;
}
South => {
current_direction = West;
x_move = distance * -1 ;
}
East => {
current_direction = South;
y_move = distance * -1;
}
West => {
current_direction = North;
y_move = distance;
}
}
}
"L" => {
match current_direction {
North => {
current_direction = West;
x_move = distance * -1;
}
South => {
current_direction = East;
x_move = distance;
}
East => {
current_direction = North;
y_move = distance;
}
West => {
current_direction = South;
y_move = distance * -1;
}
}
}
_ => {
println!("INVALID DIRECTION");
}
}
x_distance += x_move;
y_distance += y_move;
// println!("facing {:?} at {}x{} (moved {}x{})", current_direction, x_distance, y_distance, x_move, y_move);
}
x_distance.abs() + y_distance.abs()
}
fn main() {
let directions = fs::read_to_string(format!("{}/data/01_data.txt", env::var("CARGO_MANIFEST_DIR").unwrap())).unwrap();
let directions = directions.as_str();
let parmas: Vec<(&str, i32)> = vec![
("R2, L3", 5),
("R2, R2, R2", 2),
("R5, L5, R5, R3", 12),
(directions, 252)];
for (param, expected) in parmas {
println!("Manhattan Distance of {} Expected {}", manhattan_distance(param) , expected);
}
}
// 252

127
src/bin/2016_01b.rs Normal file
View File

@ -0,0 +1,127 @@
// Santa's sleigh uses a very high-precision clock to guide its movements, and the clock's
// oscillator is regulated by stars. Unfortunately, the stars have been stolen... by the Easter
// Bunny. To save Christmas, Santa needs you to retrieve all fifty stars by December 25th.
//
// Collect stars by solving puzzles. Two puzzles will be made available on each day in the Advent
// calendar; the second puzzle is unlocked when you complete the first. Each puzzle grants one
// star. Good luck!
//
// You're airdropped near Easter Bunny Headquarters in a city somewhere. "Near", unfortunately, is
// as close as you can get - the instructions on the Easter Bunny Recruiting Document the Elves
// intercepted start here, and nobody had time to work them out further.
//
// The Document indicates that you should start at the given coordinates (where you just landed)
// and face North. Then, follow the provided sequence: either turn left (L) or right (R) 90
// degrees, then walk forward the given number of blocks, ending at a new intersection.
//
// There's no time to follow such ridiculous instructions on foot, though, so you take a moment
// and work out the destination. Given that you can only walk on the street grid of the city,
// how far is the shortest path to the destination?
//
// For example:
//
// Following R2, L3 leaves you 2 blocks East and 3 blocks North, or 5 blocks away.
// R2, R2, R2 leaves you 2 blocks due South of your starting position, which is 2 blocks away.
// R5, L5, R5, R3 leaves you 12 blocks away.
// How many blocks away is Easter Bunny HQ?
//
use std::{env, fs};
use std::collections::HashMap;
use aoc::read_data;
use crate::CardinalDirection::*;
#[derive(Debug)]
enum CardinalDirection {
North,
South,
East,
West
}
fn manhattan_distance(directions: &str) -> i32 {
let mut visited_locations: HashMap<String, i32> = HashMap::new();
visited_locations.insert("0x0".to_string(), 0);
let (mut x_distance, mut y_distance, mut x_move, mut y_move) = (0i32,0i32, 0i32, 0i32);
let mut current_direction = North;
for next_direction in directions.split(", ") {
let (direction, vector) = next_direction.split_at(1);
let distance = vector.parse().unwrap();
// print!("[{}] At {x_distance}x{y_distance}, FACING {current_direction:?}, TURN {} MOVE {} ::::::", next_direction, direction, distance);
x_move = 0; y_move = 0;
match direction {
"R" => {
match current_direction {
North => {
current_direction = East;
x_move = distance;
}
South => {
current_direction = West;
x_move = distance * -1 ;
}
East => {
current_direction = South;
y_move = distance * -1;
}
West => {
current_direction = North;
y_move = distance;
}
}
}
"L" => {
match current_direction {
North => {
current_direction = West;
x_move = distance * -1;
}
South => {
current_direction = East;
x_move = distance;
}
East => {
current_direction = North;
y_move = distance;
}
West => {
current_direction = South;
y_move = distance * -1;
}
}
}
_ => {
println!("INVALID DIRECTION");
}
}
x_distance += x_move;
y_distance += y_move;
// have we been here before?
let new_index = format!("{}x{}", x_distance, y_distance);
for key in visited_locations.keys() {
if *key == new_index {
panic!("********************************MATCH -> {} == {}x{}", key, x_distance, y_distance);
} else {
print!("\tNOT MATCH -> {key} {x_distance}x{y_distance}\n");
}
}
println!("Adding {new_index} to visited list");
visited_locations.insert(new_index, 0);
}
x_distance.abs() + y_distance.abs()
}
fn main() {
let binding = read_data("2016_01_data.txt");
let directions = binding.as_str();
let params: Vec<&str> = vec![directions];
for param in params {
println!("Manhattan Distance of {}", manhattan_distance(param));
}
}
// NOT COMPLETED. CANT FIND THE REPEATED LOCATION

81
src/bin/2024_01a.rs Normal file
View File

@ -0,0 +1,81 @@
use std::{fs, io};
use std::fs::File;
use std::io::BufRead;
use std::path::Path;
/// Given 2 lists, sort the lists smallest to largest and then compare each pair of digits,
/// finding the difference between the two.
///
/// Ex:
///
/// 3 4 -> 1 3 = 2
/// 4 3 -> 2 3 = 1
/// 2 5 -> 3 3 = 0
/// 1 3 -> 3 4 = 1
/// 3 9 -> 3 5 = 2
/// 3 3 -> 4 9 = 5
/// SUM 11
///
///
fn bubble_sort(mut nums: Vec<i32>) -> Vec<i32> {
let n = nums.len();
let mut swapped = true;
while swapped {
swapped = false;
for i in 1..n {
if nums[i - 1] > nums[i] {
nums.swap(i - 1, i);
swapped = true;
}
}
}
nums
}
fn read_two_columns<P: AsRef<Path>>(filename: P) -> io::Result<(Vec<i32>, Vec<i32>)> {
let file = File::open(filename)?;
let reader = io::BufReader::new(file);
let mut col1 = Vec::new();
let mut col2 = Vec::new();
for line in reader.lines() {
let line = line?;
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() == 2 {
let a: i32 = parts[0].parse().unwrap_or(0);
let b: i32 = parts[1].parse().unwrap_or(0);
col1.push(a);
col2.push(b);
}
}
Ok((col1, col2))
}
fn main() {
println!("Loading Data...");
let input_file = format!("{}/{}" ,
std::env::var("CARGO_MANIFEST_DIR").unwrap(),
"data/01_data.txt"
);
let (mut list1, mut list2) = read_two_columns(input_file).unwrap();
list1 = bubble_sort(list1);
list2 = bubble_sort(list2);
let mut running_total = 0;
for index in 0..list1.len() {
let n1 = list1[index].max(list2[index]);
let n2 = list1[index].min(list2[index]);
running_total += n1 - n2;
}
println!("Total = {}", running_total);
}
// 2375403

102
src/bin/2024_01b.rs Normal file
View File

@ -0,0 +1,102 @@
use std::{fs, io};
use std::fs::File;
use std::io::BufRead;
use std::path::Path;
// Your analysis only confirmed what everyone feared: the two lists of location IDs are indeed
// very different.
//
// Or are they?
//
// The Historians can't agree on which group made the mistakes or how to read most of the Chief's
// handwriting, but in the commotion you notice an interesting detail: a lot of location IDs appear
// in both lists! Maybe the other numbers aren't location IDs at all but rather misinterpreted
// handwriting.
//
// This time, you'll need to figure out exactly how often each number from the left list appears in
// the right list. Calculate a total similarity score by adding up each number in the left list
// after multiplying it by the number of times that number appears in the right list.
//
// Here are the same example lists again:
//
// 3 4
// 4 3
// 2 5
// 1 3
// 3 9
// 3 3
// For these example lists, here is the process of finding the similarity score:
//
// The first number in the left list is 3. It appears in the right list three times, so the
// similarity score increases by 3 * 3 = 9.
// The second number in the left list is 4. It appears in the right list once, so the similarity
// score increases by 4 * 1 = 4.
// The third number in the left list is 2. It does not appear in the right list, so the similarity
// score does not increase (2 * 0 = 0).
// The fourth number, 1, also does not appear in the right list.
// The fifth number, 3, appears in the right list three times; the similarity score increases by 9.
// The last number, 3, appears in the right list three times; the similarity score again increases
// by 9.
// So, for these example lists, the similarity score at the end of this process is
// 31 (9 + 4 + 0 + 0 + 9 + 9).
//
// Once again consider your left and right lists. What is their similarity score?
fn num_in_list(needle: i32, haystack: &Vec<i32>) -> i32 {
let mut working = 0;
for straw in haystack {
if *straw == needle {
working += 1;
}
}
working
}
fn count_occurances_in_list(needles: &Vec<i32>, haystack: &Vec<i32>) -> i32 {
// looking for a needle in a haystack...lets go!
let mut working = 0;
for needle in needles {
let num_in_list = num_in_list(*needle, haystack);
println!("Found {}, {} times. / {}", needle, num_in_list, working);
working += needle * num_in_list;
}
working
}
fn read_two_columns<P: AsRef<Path>>(filename: P) -> io::Result<(Vec<i32>, Vec<i32>)> {
let file = File::open(filename)?;
let reader = io::BufReader::new(file);
let mut col1 = Vec::new();
let mut col2 = Vec::new();
for line in reader.lines() {
let line = line?;
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.len() == 2 {
let a: i32 = parts[0].parse().unwrap_or(0);
let b: i32 = parts[1].parse().unwrap_or(0);
col1.push(a);
col2.push(b);
}
}
Ok((col1, col2))
}
fn main() {
println!("Loading Data...");
let file_path = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let (list1, list2) = read_two_columns(format!("{}/data/01_data.txt", file_path)).unwrap();
println!("List 1 -> {:?}", list1);
let final_value = count_occurances_in_list(&list1, &list2);
println!("Final value = {final_value}");
}
// 23082277

103
src/bin/2024_02a.rs Normal file
View File

@ -0,0 +1,103 @@
// Fortunately, the first location The Historians want to search isn't a long walk from the Chief
// Historian's office.
//
// While the Red-Nosed Reindeer nuclear fusion/fission plant appears to contain no sign of the
// Chief Historian, the engineers there run up to you as soon as they see you. Apparently, they
// still talk about the time Rudolph was saved through molecular synthesis from a single electron.
//
// They're quick to add that - since you're already here - they'd really appreciate your help
// analyzing some unusual data from the Red-Nosed reactor. You turn to check if The Historians are
// waiting for you, but they seem to have already divided into groups that are currently searching
// every corner of the facility. You offer to help with the unusual data.
//
// The unusual data (your puzzle input) consists of many reports, one report per line. Each report
// is a list of numbers called levels that are separated by spaces. For example:
//
// 7 6 4 2 1
// 1 2 7 8 9
// 9 7 6 2 1
// 1 3 2 4 5
// 8 6 4 4 1
// 1 3 6 7 9
// This example data contains six reports each containing five levels.
//
// The engineers are trying to figure out which reports are safe. The Red-Nosed reactor safety
// systems can only tolerate levels that are either gradually increasing or gradually decreasing.
// So, a report only counts as safe if both of the following are true:
//
// The levels are either all increasing or all decreasing.
// Any two adjacent levels differ by at least one and at most three.
// In the example above, the reports can be found safe or unsafe by checking those rules:
//
// 7 6 4 2 1: Safe because the levels are all decreasing by 1 or 2.
// 1 2 7 8 9: Unsafe because 2 7 is an increase of 5.
// 9 7 6 2 1: Unsafe because 6 2 is a decrease of 4.
// 1 3 2 4 5: Unsafe because 1 3 is increasing but 3 2 is decreasing.
// 8 6 4 4 1: Unsafe because 4 4 is neither an increase or a decrease.
// 1 3 6 7 9: Safe because the levels are all increasing by 1, 2, or 3.
// So, in this example, 2 reports are safe.
use std::{env, fs};
fn min_max(num1: u32, num2: u32) -> (u32, u32) {
(num1.min(num2), num1.max(num2))
}
fn in_range(min: u32, max:u32, target: u32) -> bool {
min <= target && target <= max
}
fn parse_numbers(s: &str) -> Vec<u32> {
s.split_whitespace() // split on whitespace
.filter_map(|num| num.parse::<u32>().ok()) // try to parse each piece
.collect()
}
fn is_safe(report: &str) -> bool {
let mut is_safe = true;
let mut last_reading = 0;
let numbers = parse_numbers(report);
println!("numbers: {:?}", numbers);
let mut is_increasing = numbers[0] < numbers[1];
println!("Checking report {report}");
println!("Found is_increasing = {is_increasing} from {}/{}", numbers[0], numbers[1]);
for (index, reading) in numbers.iter().enumerate() {
println!("Checking {index}->{reading} in {report} / {is_increasing}");
}
// for (index, reading) in numbers.enumerate() {
// let reading_u32: u32 = reading.parse().unwrap();
// if index == 0 {
// // prime it for the report
// last_reading = reading_u32;
// } else if index == 1 {
// if last_reading > reading_u32 {
// is_increasing = false;
// }
// } else {
// let (min,max) = min_max(last_reading as u32, reading_u32);
//
// // changing too fast
// if (max - min) > 2 { is_safe = false; }
// }
// }
is_safe
}
fn main() {
let input_file = format!("{}/{}" ,
std::env::var("CARGO_MANIFEST_DIR").unwrap(),
"data/02_data.txt"
);
let binding = fs::read_to_string(input_file).unwrap();
let reports = binding.lines();
for report in reports {
if is_safe(report) {
println!("Handling report of {report} -> Safe: {}", is_safe(report));
}
}
}

28
src/lib.rs Normal file
View File

@ -0,0 +1,28 @@
/// AOC Lib
/// Generic methods for loading various data inputs from
/// the AOC project.
pub fn data_path(suffix: &str) -> String {
let path = std::env::var("CARGO_MANIFEST_DIR").unwrap();
format!("{}/data/{}", path, suffix)
}
pub fn read_data(suffix: &str) -> String {
std::fs::read_to_string(
data_path(suffix)
).unwrap()
}
pub fn string_to_3u32(input: &str) -> Option<(u32, u32, u32)> {
let parts: Vec<&str> = input.split('x').collect();
if parts.len() == 3 {
if let (Ok(a), Ok(b), Ok(c)) = (
parts[0].parse::<u32>(),
parts[1].parse::<u32>(),
parts[2].parse::<u32>(),
) {
return Some((a, b, c));
}
}
None
}