diff --git a/2023/days/.gitignore b/2023/days/.gitignore new file mode 100755 index 0000000..afea973 --- /dev/null +++ b/2023/days/.gitignore @@ -0,0 +1,16 @@ +data + +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/2023/days/01/part2/Cargo.toml b/2023/days/01/part2/Cargo.toml new file mode 100755 index 0000000..e73cff3 --- /dev/null +++ b/2023/days/01/part2/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "part2" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/2023/days/01/part2/src/main.rs b/2023/days/01/part2/src/main.rs new file mode 100755 index 0000000..bfb3aee --- /dev/null +++ b/2023/days/01/part2/src/main.rs @@ -0,0 +1,80 @@ +use std::cmp; +use std::collections::HashMap; +use std::fs; + +// Extract all numbers, digits and letter written digits +fn extract_numbers(line: &str) -> Vec { + let written_digits: Vec<&str> = vec![ + "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", + ]; + let mut max_tail_overlaps: HashMap<&str, u32> = HashMap::new(); + // Compute the size of the suffix of number i overlaping with prefix of number j: + for suffix_number in &written_digits { + max_tail_overlaps.insert(suffix_number.clone(), 0); + for prefix_number in &written_digits { + if suffix_number != prefix_number { + let mut overlap: u32 = 0; + for i in 0..(cmp::min(prefix_number.len(), suffix_number.len())) { + if suffix_number.chars().nth_back(i) == prefix_number.chars().nth(i) { + overlap += 1; + } else { + break; + } + } + if overlap > max_tail_overlaps[suffix_number] { + max_tail_overlaps.insert(suffix_number, overlap); + } + } + } + } + let mut numbers: Vec = Vec::new(); + let mut current_digit_word: String = "".to_owned(); + for character in line.chars() { + if character.is_digit(10) { + numbers.push(character.to_digit(10).unwrap()); + current_digit_word = "".to_owned(); // Reset writing word + } else { + current_digit_word.push(character); + // Check for the presence of any of the digit words + for (index, digit_writing) in written_digits.iter().enumerate() { + let word_length = digit_writing.len(); + let positions: Vec<(usize, &str)> = + current_digit_word.match_indices(digit_writing).collect(); + if positions.len() > 0 { + let digit = index as u32 + 1; + numbers.push(digit); + let start_position = positions[0].0; + let end_position = + start_position + word_length - max_tail_overlaps[digit_writing] as usize; + let current_digit_word_slice = ¤t_digit_word[end_position..]; + current_digit_word = current_digit_word_slice.to_owned(); + } + } + } + } + numbers +} + +// Extract number including letters +fn extract_number(line: &str) -> u32 { + let numbers: Vec = extract_numbers(line); + let first: u32 = numbers[0]; + let last: u32 = numbers[numbers.len() - 1]; + let number: u32 = first * 10 + last; + number +} + +fn main() { + let input_filename: &str = "../data/input.txt"; + + let contents = + fs::read_to_string(input_filename).expect("Should have been able to read the file"); + + let mut sum: u32 = 0; + for line in contents.lines() { + let number = extract_number(line); + println!("{}\t{:?}", line, number); + sum += number; + } + println!("{:?}", sum); +} diff --git a/2023/days/01/trebuchet/Cargo.toml b/2023/days/01/trebuchet/Cargo.toml new file mode 100755 index 0000000..5d49fb2 --- /dev/null +++ b/2023/days/01/trebuchet/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "trebuchet" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/2023/days/01/trebuchet/src/main.rs b/2023/days/01/trebuchet/src/main.rs new file mode 100755 index 0000000..cf66ae9 --- /dev/null +++ b/2023/days/01/trebuchet/src/main.rs @@ -0,0 +1,33 @@ +use std::fs; + +fn extract_number(line: &str) -> u32 { + let mut has_digit: bool = false; + let mut first: u32 = 0; + let mut last: u32 = 0; + for character in line.chars() { + if character.is_digit(10) { + if !has_digit { + has_digit = true; + first = character.to_digit(10).unwrap(); + } + last = character.to_digit(10).unwrap(); + } + } + let number: u32 = first * 10 + last; + number +} + +fn main() { + let input_filename: &str = "../data/input.txt"; + + let contents = + fs::read_to_string(input_filename).expect("Should have been able to read the file"); + + let mut sum: u32 = 0; + for line in contents.lines() { + let number = extract_number(line); + // println!("{:?}", number); + sum += number; + } + println!("{:?}", sum); +} diff --git a/2023/days/02/part1.py b/2023/days/02/part1.py new file mode 100755 index 0000000..de755e0 --- /dev/null +++ b/2023/days/02/part1.py @@ -0,0 +1,32 @@ +with open("data/input.txt", "r") as f: + games = f.read() + +limits = { + "red": 12, + "green": 13, + "blue": 14 +} + +s = 0 + +for game in games.split("\n")[:-1]: + parts = game.split(":") + head = parts[0] + identifier = head.split(" ")[1] + overflow = False + for draw in parts[1].split(";"): + draw = draw.strip() + for count in draw.split(","): + count = count.strip() + count_parts = count.split(" ") + color = count_parts[1] + amount = int(count_parts[0]) + if amount > limits[color]: + overflow = True + break + if overflow: + break + if not overflow: + s += int(identifier) + +print(s) diff --git a/2023/days/02/part1/cube.pl b/2023/days/02/part1/cube.pl new file mode 100755 index 0000000..b8f0995 --- /dev/null +++ b/2023/days/02/part1/cube.pl @@ -0,0 +1,62 @@ +#!/usr/bin/env perl +use warnings; +use strict; + +my $filename = '../data/input.txt'; + +open(FH, '<', $filename) or die $!; + +sub possible_id { + my $line = $_[0]; + my $reds = $_[1]; + my $greens = $_[2]; + my $blues = $_[3]; + my @colors = qw(red green blue); + my @quantities = ($reds, $greens, $blues); + # Extract the id and game draws + my @game_parts = split /:/, $line, 2; + my @id_parts = split / /, $game_parts[0], 2; + my $id = $id_parts[1]; + my @game_plays = split /;/, $game_parts[1]; + foreach my $play (@game_plays) { + my @color_counts = (0, 0, 0); + my @play_draws = split /,/, $play; + foreach my $draw (@play_draws) { + my @draw_parts = split / /, $draw; + my $color = $draw_parts[2]; + my $amount = int($draw_parts[1]); + for ((0..2)) { + my $idx = $_; + my $limit_color = $colors[$idx]; + my $limit_amount = $quantities[$idx]; + if ($color eq $limit_color) { + $color_counts[$idx] += $amount; + } + } + } + # print join(", ", @color_counts) . "\n"; + for ((0..2)) { + if ($quantities[$_] < $color_counts[$_]) { + return 0; + + } + } + } + return int($id); +} + +my $reds_limit = 12; +my $greens_limit = 13; +my $blues_limit = 14; + +my $sum = 0; +while () { + # print $_; + my $id = possible_id($_, $reds_limit, $greens_limit, $blues_limit); + $sum += $id; + # print $id . "\n"; +} + +close(FH); + +print $sum . "\n"; diff --git a/2023/days/02/part2.py b/2023/days/02/part2.py new file mode 100755 index 0000000..18e057b --- /dev/null +++ b/2023/days/02/part2.py @@ -0,0 +1,31 @@ + +import numpy as np + +with open("data/input.txt", "r") as f: + games = f.read() + +limits = { + "red": 12, + "green": 13, + "blue": 14 +} + +s = 0 + +for game in games.split("\n")[:-1]: + parts = game.split(":") + head = parts[0] + identifier = head.split(" ")[1] + max_counts = dict(red=0, green=0, blue=0) + for draw in parts[1].split(";"): + draw = draw.strip() + for count in draw.split(","): + count = count.strip() + count_parts = count.split(" ") + color = count_parts[1] + amount = int(count_parts[0]) + if amount > max_counts[color]: + max_counts[color] = amount + s += np.prod(list(max_counts.values())) + +print(s) diff --git a/2023/days/03/part1.py b/2023/days/03/part1.py new file mode 100755 index 0000000..842a85d --- /dev/null +++ b/2023/days/03/part1.py @@ -0,0 +1,47 @@ +with open("data/input.txt", "r") as f: + data = f.read() + +table = [ + [item for item in row] + for row in data.split("\n") +] + +symbols = "&~\"#'{([-|`_\\^`])}@)]=+}$£%*!§/:;,?<>" + + +parts = [] + +positions = set() + +for i in range(len(table)): + for j in range(len(table[i])): + letter = table[i][j] + if letter in symbols: + found = False + for dx in [-1, 0, 1]: + for dy in [-1, 0, 1]: + y = i + dx + x = j + dy + if x >= 0 and x < len(table[i]) and y >= 0 and y <= len(table): + number = "" + digit = table[y][x] + if digit != "." and digit.isdigit(): + number = digit + found = True + # Extend right + shift = 1 + idx = x + shift + while idx >= 0 and idx < len(table[y]) and table[y][idx] != "." and table[y][idx].isdigit(): + number = number + table[y][idx] + idx += shift + position = (y, idx) + # Extend left + shift = -1 + idx = x + shift + while idx >= 0 and idx < len(table[y]) and table[y][idx] != "." and table[y][idx].isdigit(): + number = table[y][idx] + number + idx += shift + if position not in positions: + positions.add(position) + parts.append(int(number)) +print(sum(parts)) diff --git a/2023/days/03/part2.py b/2023/days/03/part2.py new file mode 100755 index 0000000..ffb623c --- /dev/null +++ b/2023/days/03/part2.py @@ -0,0 +1,51 @@ +import numpy as np + +with open("data/input.txt", "r") as f: + data = f.read() + +table = [ + [item for item in row] + for row in data.split("\n") +] + +symbols = "&~\"#'{([-|`_\\^`])}@)]=+}$£%*!§/:;,?<>" + + +gears = [] + + +for i in range(len(table)): + for j in range(len(table[i])): + letter = table[i][j] + if letter == "*": + gear_numbers = [] + positions = set() + for dx in [-1, 0, 1]: + for dy in [-1, 0, 1]: + y = i + dx + x = j + dy + if x >= 0 and x < len(table[i]) and y >= 0 and y <= len(table): + number = "" + digit = table[y][x] + if digit != "." and digit.isdigit(): + number = digit + found = True + # Extend right + shift = 1 + idx = x + shift + while idx >= 0 and idx < len(table[y]) and table[y][idx] != "." and table[y][idx].isdigit(): + number = number + table[y][idx] + idx += shift + position = (y, idx) + # Extend left + shift = -1 + idx = x + shift + while idx >= 0 and idx < len(table[y]) and table[y][idx] != "." and table[y][idx].isdigit(): + number = table[y][idx] + number + idx += shift + if position not in positions: + positions.add(position) + gear_numbers.append(int(number)) + if len(gear_numbers) == 2: + gears.append(np.prod(gear_numbers)) +print(sum(gears)) diff --git a/2023/days/04/part1.pl b/2023/days/04/part1.pl new file mode 100755 index 0000000..d14c638 --- /dev/null +++ b/2023/days/04/part1.pl @@ -0,0 +1,41 @@ +#!/usr/bin/env perl +use warnings; +use strict; +use List::Util; + +my $filename = "./data/input.txt"; + +open(FH, '<', $filename) or die $!; + +my $score = 0; +while () { + my $card = $_; + my $points = 0; + my @parts = split /:/, $card; + my @lists = split /\|/, $parts[1]; + my @winning = split ' ', $lists[0]; + my @numbers = split ' ', $lists[1]; + my @previous = (); + foreach my $number (@numbers) { + if ($number eq " ") { + print $_; + } + if ((List::Util::any { $_ eq $number } @winning) && (List::Util::all { $_ ne $number } @previous)) { + push(@previous, $number); + if ($points == 0) { + $points = 1; + } else { + $points *= 2; + } + # print $number . ", "; + } + } + #if ($points == 0) { + # print "no points" . "\n"; + #} else { + # print $points . " points\n"; + #} + $score += $points; +} + +print $score . "\n"; diff --git a/2023/days/04/part2.py b/2023/days/04/part2.py new file mode 100755 index 0000000..87bd6e7 --- /dev/null +++ b/2023/days/04/part2.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python3 +import queue + +with open("data/input.txt", "r") as f: + data = f.read() + +q = queue.Queue() + +def winning_copies(card): + lists = card.split(":")[1].split("|") + winning = lists[0].split() + numbers = lists[1].split() + matching = 0 + for number in numbers: + if number in winning: + matching += 1 + return matching + +cards = data.split("\n") +cards.remove("") +for i, card in enumerate(cards): + q.put((i, card)) + +counter = 0 +while not q.empty(): + i, card = q.get() + copies = winning_copies(card) + if copies > 0: + for j in range(1, copies+1): + copy = cards[i+j] + q.put((i+j, copy)) + counter += 1 + +print(counter) diff --git a/2023/days/05/Makefile b/2023/days/05/Makefile new file mode 100755 index 0000000..d2c3cb9 --- /dev/null +++ b/2023/days/05/Makefile @@ -0,0 +1,13 @@ +## +# Project Title +# +# @file +# @version 0.1 + +SOURCE=part1 + +run: + ocamlopt $(SOURCE).ml -o $(SOURCE) + ./$(SOURCE) + +# end diff --git a/2023/days/05/part1 b/2023/days/05/part1 new file mode 100755 index 0000000..8e2897a Binary files /dev/null and b/2023/days/05/part1 differ diff --git a/2023/days/05/part1.cmi b/2023/days/05/part1.cmi new file mode 100755 index 0000000..76b7e35 Binary files /dev/null and b/2023/days/05/part1.cmi differ diff --git a/2023/days/05/part1.ml b/2023/days/05/part1.ml new file mode 100755 index 0000000..c29c6fe --- /dev/null +++ b/2023/days/05/part1.ml @@ -0,0 +1,27 @@ +let file = "data/sample.txt" + +let rec next previous map = + let apply destination source range value = + let delta = value - source in + destination + delta + in match map with + | [] -> None + | (destination, source, range)::q when + previous >= previous && previous <= previous + range + -> Some(apply destination source range previous) + | h::q -> next previous q + +let res = next 98 [(50,98,2);(52,50,48)] + + +let () = + let ic = open_in file in + let line = input_line ic in + (* read line *) + print_endline line; + flush stdout; + close_in ic + with e -> close_in_noerr ic; + raise e + +let () = print_endline file diff --git a/2023/days/05/part1.py b/2023/days/05/part1.py new file mode 100755 index 0000000..297f1e4 --- /dev/null +++ b/2023/days/05/part1.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# day 5 - Advent of Code 2023 +# part 1 + +import numpy as np +import pandas as pd + +with open("data/sample.txt", "r") as f: + data = f.read() + +parts = data.split("\n\n") + +seeds = parts[0] +seeds = seeds.split(": ")[1].split() +seeds = list(map(int, seeds)) +maps = [ + [ + [int(item) for item in values.split()] + for values in themap.split("\n")[1:] + if values != "" + ] + for themap in parts[1:] +] + + +def recursive_min_descent(seed, maps): + current = seed + for submap in maps: + for indication in submap: + destination, source, size = indication + return current + + +""" +soils = list(map(lambda seed: descent(seed, maps), seeds)) + +seeds = range(0, 99) + +df = pd.DataFrame( + dict(seed=seeds, soil=list(map(lambda seed: descent(seed, maps), seeds))) +) + +""" +# Check that no map indication overlaps +for submap in maps: + for indication1 in submap: + _, start1, range1 = indication1 + for indication2 in submap: + if indication1 == indication2: + continue + _, start2, range2 = indication2 + if not (start2 > start1 + range1 or start1 > start2 + range2): + print("overlap") + +print(df) diff --git a/2023/days/05/rust/part1/Cargo.toml b/2023/days/05/rust/part1/Cargo.toml new file mode 100755 index 0000000..d53465e --- /dev/null +++ b/2023/days/05/rust/part1/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "part1" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/2023/days/05/rust/part1/src/main.rs b/2023/days/05/rust/part1/src/main.rs new file mode 100755 index 0000000..cd5100d --- /dev/null +++ b/2023/days/05/rust/part1/src/main.rs @@ -0,0 +1,93 @@ +use std::fs; + +fn parse_steps(lines: std::str::Lines) -> Vec>> { + let mut steps: Vec>> = Vec::new(); + let mut step: Vec> = Vec::new(); + for line in lines { + if line.contains("-to-") { + step = Vec::new(); + steps.push(step); + } else if line != "" { + let numbers: Vec<&str> = line.split(" ").collect(); + let numbers: Vec = numbers + .iter() + .map(|string| { + let number: u32 = string.parse().unwrap(); + number + }) + .collect(); + let n = steps.len(); + steps[n - 1].push(numbers); + } + } + steps +} + +fn position_min(vector: Vec) -> Option { + if vector.len() == 0 { + return None; + } + let mut min_index = 0; + let mut min = vector[0]; + for (i, value) in vector.iter().enumerate() { + if *value < min { + min_index = i; + min = *value; + } + } + Some(min_index) +} + +fn seed_to_location(seed: u32, steps: &Vec>>) -> u32 { + let mut current: u32 = seed; + println!("{:?}", current); + for step in steps { + let mut updated = false; + for range in step { + let destination = range[0]; + let source = range[1]; + let size = range[2]; + if current >= source && current <= source + size { + if !updated { + current = destination + current - source; + } else { + println!("Already updated?"); + } + } + } + println!("{:?}", current); + } + println!("\n"); + current +} + +fn main() { + let filepath: &str = "../../data/sample.txt"; + + let contents = fs::read_to_string(filepath).expect("Should have been hable to read the file"); + + let mut lines = contents.lines(); + let seeds: Vec<&str> = lines + .next() + .unwrap() + .split(": ") + .nth(1) + .expect("Should have a seed") + .split(" ") + .collect(); + let steps = parse_steps(lines); + let seeds: Vec = seeds + .iter() + .map(|string| { + let number: u32 = string.trim().parse().unwrap(); + number + }) + .collect(); + let locations: Vec = seeds + .iter() + .map(|seed| seed_to_location(*seed, &steps)) + .collect(); + let min_location = locations.iter().min(); + // let min_location_index = position_min(locations).unwrap(); + println!("{:?}", min_location); +} diff --git a/2023/days/06/part1.py b/2023/days/06/part1.py new file mode 100755 index 0000000..19773a3 --- /dev/null +++ b/2023/days/06/part1.py @@ -0,0 +1,28 @@ +with open("data/input.txt", "r") as f: + data = f.read() + +data = data.split("\n") +times = data[0].split(":")[1].split() +distances = data[1].split(":")[1].split() + +times = [int(i) for i in times] +distances = [int(i) for i in distances] + +# print(times) +# print(distances) + +product = 1 + + +def distance(pressed_duration, limit_duration): + return pressed_duration * (limit_duration - pressed_duration) + + +for time, dist in zip(times, distances): + count = 0 + for i in range(0, time + 1): + if distance(i, time) > dist: + count += 1 + product *= count + +print(product) diff --git a/2023/days/06/part2.py b/2023/days/06/part2.py new file mode 100755 index 0000000..43cbf77 --- /dev/null +++ b/2023/days/06/part2.py @@ -0,0 +1,28 @@ +with open("data/sample.txt", "r") as f: + data = f.read() + +data = data.split("\n") +times = data[0].split(":")[1].replace(" ", "").split() +distances = data[1].split(":")[1].replace(" ", "").split() + +times = [int(i) for i in times] +distances = [int(i) for i in distances] + +# print(times) +# print(distances) + +product = 1 + + +def distance(pressed_duration, limit_duration): + return pressed_duration * (limit_duration - pressed_duration) + + +for time, dist in zip(times, distances): + count = 0 + for i in range(0, time + 1): + if distance(i, time) > dist: + count += 1 + product *= count + +print(product) diff --git a/2023/days/07/part1.ml b/2023/days/07/part1.ml new file mode 100755 index 0000000..e69de29 diff --git a/2023/days/07/rust/part1/.gitignore b/2023/days/07/rust/part1/.gitignore new file mode 100755 index 0000000..ea8c4bf --- /dev/null +++ b/2023/days/07/rust/part1/.gitignore @@ -0,0 +1 @@ +/target diff --git a/2023/days/07/rust/part1/Cargo.toml b/2023/days/07/rust/part1/Cargo.toml new file mode 100755 index 0000000..d53465e --- /dev/null +++ b/2023/days/07/rust/part1/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "part1" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/2023/days/07/rust/part1/src/main.rs b/2023/days/07/rust/part1/src/main.rs new file mode 100755 index 0000000..cd31ab8 --- /dev/null +++ b/2023/days/07/rust/part1/src/main.rs @@ -0,0 +1,20 @@ +use std::collections::HashMap; +use std::fs; + +fn count_hashmap(card: &str) -> HashMap { + let count: HashMap = HashMap::new(); + for chr in card.chars() { + count.entry(chr).and_modify(|c| *c + 1).or_insert(0); + } + return count; +} + +fn greater_than(card1: &str, card2: &str) -> bool {} + +fn main() { + let filepath = "../../data/input.txt"; + + let contents = fs::read_to_string(filepath).expect("should have been to read the file"); + + println!("Hello, world!"); +}