Compare commits

..

10 Commits

Author SHA1 Message Date
Joe Ardent 8789bbba49 runlength encoding using the input container as the output 2024-04-25 17:49:57 -07:00
Joe Ardent 15fd997707 increasing triplet subsequence 2024-04-25 14:34:56 -07:00
Joe Ardent 06b15921fd reuse array for product 2023-11-02 22:25:39 -07:00
Joe Ardent 34db36cf0b add "product of array except self" in rust 2023-11-02 17:41:09 -07:00
Joe Ardent db142ff1df done with day13 2022-12-29 16:21:22 -08:00
Joe Ardent 24feb1c127 starting on day13, parser is halfway done 2022-12-26 17:09:04 -08:00
Joe Ardent 0423e7a8f3 clean up day12, disable tests 2022-12-13 13:43:00 -08:00
Joe Ardent a62ed3ec13 done with part2 2022-12-13 13:32:17 -08:00
Joe Ardent 2cd0dce596 done with day12, part1 2022-12-13 13:14:42 -08:00
Joe Ardent 5441906ea8 day11 part2 done 2022-12-12 20:16:39 -08:00
11 changed files with 507 additions and 130 deletions

View File

@ -9,6 +9,7 @@ edition = "2021"
aoc-runner = "0.3"
aoc-runner-derive = "0.3"
lazy_static = "1.4.0"
#itertools = "0.10.5"
regex = "1.7"
ndarray = "0.15"
petgraph = "0.6"
lyn = "0.1.0"

View File

@ -24,10 +24,10 @@ impl Default for Operation {
}
impl Monkey {
pub fn inspect(&mut self) -> Vec<(usize, u128)> {
pub fn inspect(&mut self, reducer: &dyn Fn(u128) -> u128) -> Vec<(usize, u128)> {
let mut out = Vec::with_capacity(self.items.len());
while let Some(item) = self.items.pop_front() {
let item = self.op(item) / 3;
let item = reducer(self.op(item));
if item % self.tmod == 0 {
out.push((self.target.0, item));
} else {
@ -115,7 +115,7 @@ fn part1(troop: &[Monkey]) -> u128 {
for _round in 0..20 {
for i in 0..troop.len() {
let monkey = &mut troop[i];
let items = monkey.inspect();
let items = monkey.inspect(&|item| item / 3);
for (target, item) in items {
let m = &mut troop[target];
m.items.push_back(item);
@ -128,9 +128,23 @@ fn part1(troop: &[Monkey]) -> u128 {
#[aoc_run(day11, part2)]
fn part2(troop: &[Monkey]) -> u128 {
0
let max: u128 = troop.iter().map(|m| m.tmod).product();
let mut troop = troop.to_owned();
for _round in 0..10_000 {
for i in 0..troop.len() {
let monkey = &mut troop[i];
let items = monkey.inspect(&|item| item % max);
for (target, item) in items {
let m = &mut troop[target];
m.items.push_back(item);
}
}
}
troop.sort_by(|m1, m2| m2.business.cmp(&m1.business));
troop.iter().take(2).map(|m| m.business).product()
}
/*
#[cfg(test)]
mod test {
use super::*;
@ -172,129 +186,7 @@ Monkey 3:
#[test]
fn part2_test() {
let v = parse_input(INPUT);
assert_eq!(part2(&v), 1);
}
#[test]
fn leah_test() {
let troop = parse_input(
"Monkey 0:
Starting items: 54, 82, 90, 88, 86, 54
Operation: new = old * 7
Test: divisible by 11
If true: throw to monkey 2
If false: throw to monkey 6
Monkey 1:
Starting items: 91, 65
Operation: new = old * 13
Test: divisible by 5
If true: throw to monkey 7
If false: throw to monkey 4
Monkey 2:
Starting items: 62, 54, 57, 92, 83, 63, 63
Operation: new = old + 1
Test: divisible by 7
If true: throw to monkey 1
If false: throw to monkey 7
Monkey 3:
Starting items: 67, 72, 68
Operation: new = old * old
Test: divisible by 2
If true: throw to monkey 0
If false: throw to monkey 6
Monkey 4:
Starting items: 68, 89, 90, 86, 84, 57, 72, 84
Operation: new = old + 7
Test: divisible by 17
If true: throw to monkey 3
If false: throw to monkey 5
Monkey 5:
Starting items: 79, 83, 64, 58
Operation: new = old + 6
Test: divisible by 13
If true: throw to monkey 3
If false: throw to monkey 0
Monkey 6:
Starting items: 96, 72, 89, 70, 88
Operation: new = old + 4
Test: divisible by 3
If true: throw to monkey 1
If false: throw to monkey 2
Monkey 7:
Starting items: 79
Operation: new = old + 8
Test: divisible by 19
If true: throw to monkey 4
If false: throw to monkey 5",
);
assert_eq!(part1(&troop), 78960);
}
#[test]
fn rippy_part1() {
let input = "Monkey 0:
Starting items: 96, 60, 68, 91, 83, 57, 85
Operation: new = old * 2
Test: divisible by 17
If true: throw to monkey 2
If false: throw to monkey 5
Monkey 1:
Starting items: 75, 78, 68, 81, 73, 99
Operation: new = old + 3
Test: divisible by 13
If true: throw to monkey 7
If false: throw to monkey 4
Monkey 2:
Starting items: 69, 86, 67, 55, 96, 69, 94, 85
Operation: new = old + 6
Test: divisible by 19
If true: throw to monkey 6
If false: throw to monkey 5
Monkey 3:
Starting items: 88, 75, 74, 98, 80
Operation: new = old + 5
Test: divisible by 7
If true: throw to monkey 7
If false: throw to monkey 1
Monkey 4:
Starting items: 82
Operation: new = old + 8
Test: divisible by 11
If true: throw to monkey 0
If false: throw to monkey 2
Monkey 5:
Starting items: 72, 92, 92
Operation: new = old * 5
Test: divisible by 3
If true: throw to monkey 6
If false: throw to monkey 3
Monkey 6:
Starting items: 74, 61
Operation: new = old * old
Test: divisible by 2
If true: throw to monkey 3
If false: throw to monkey 1
Monkey 7:
Starting items: 76, 86, 83, 55
Operation: new = old + 4
Test: divisible by 5
If true: throw to monkey 4
If false: throw to monkey 0";
let troop = parse_input(input);
assert_eq!(part1(&troop), 56595);
assert_eq!(part2(&v), 2713310158);
}
}
*/

131
2022-aoc/src/d12.rs Normal file
View File

@ -0,0 +1,131 @@
use aoc_runner_derive::{aoc as aoc_run, aoc_generator};
use petgraph::{algo::dijkstra, prelude::NodeIndex, Graph};
type GRAPH = Graph<char, ()>;
type Pos = (usize, usize);
#[aoc_generator(day12)]
fn parse_input(input: &str) -> (NodeIndex, NodeIndex, GRAPH) {
let mut out = Graph::default();
let mut g = Vec::new();
let mut s = NodeIndex::default();
let mut e = NodeIndex::default();
for line in input.lines() {
let row = Vec::from_iter(line.chars());
g.push(row);
}
let rows = g.len();
let cols = g[0].len();
let mut g2 = vec![vec![NodeIndex::default(); cols]; rows];
for row in 0..rows {
for col in 0..cols {
let weight = g[row][col];
let node = out.add_node(weight);
g2[row][col] = node;
if weight == 'S' {
s = node;
}
if weight == 'E' {
e = node;
}
}
}
for row in 0..rows {
for col in 0..cols {
let node = g2[row][col];
for neighbor in neighbors((row, col), &g).iter() {
let &(row, col) = neighbor;
let neighbor = g2[row][col];
out.add_edge(node, neighbor, ());
}
}
}
(s, e, out)
}
fn neighbors((ridx, cidx): Pos, graph: &[Vec<char>]) -> Vec<(usize, usize)> {
let n = graph[ridx][cidx];
let mut out = Vec::new();
for (dr, dc) in [(-1, 0), (1, 0), (0, -1), (0, 1)] {
let row = (dr + ridx as i32) as usize;
let col = (dc + cidx as i32) as usize;
if let Some(r) = graph.get(row) {
if let Some(c) = r.get(col) {
if reachable(n, *c) {
out.push((row, col));
}
}
}
}
out
}
fn reachable(a: char, b: char) -> bool {
let a = match a {
'S' => 'a',
'E' => 'z',
_ => a,
};
let b = match b {
'S' => 'a',
'E' => 'z',
_ => b,
};
(a as u8 + 1) >= b as u8
}
#[aoc_run(day12, part1)]
fn part1((start, end, graph): &(NodeIndex, NodeIndex, GRAPH)) -> i32 {
let res = dijkstra(graph, *start, Some(*end), |_| 1);
res[end]
}
#[aoc_run(day12, part2)]
fn part2((start, end, graph): &(NodeIndex, NodeIndex, GRAPH)) -> i32 {
let mut roots = Vec::new();
roots.push(*start);
for (i, w) in graph.node_weights().enumerate() {
if w == &'a' {
roots.push(NodeIndex::new(i));
}
}
let mut res = i32::MAX;
for root in roots {
let p = dijkstra(graph, root, Some(*end), |_| 1);
if let Some(&v) = p.get(end) {
res = res.min(v);
}
}
res
}
/*
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi";
#[test]
fn part1_test() {
let v = parse_input(INPUT);
assert_eq!(part1(&v), 31);
}
#[test]
fn part2_test() {
let v = parse_input(INPUT);
assert_eq!(part2(&v), 29);
}
}
*/

175
2022-aoc/src/d13.rs Normal file
View File

@ -0,0 +1,175 @@
use aoc_runner_derive::{aoc as aoc_run, aoc_generator};
use lyn::Scanner;
/*
The following grammar can be used at https://bnfplayground.pauliankline.com/ to play with matching
<packet> ::= <leftbrace> <list>? <rightbrace>
<list> ::= <element> (<comma> <element>)*
<element> ::= <number> | <leftbrace> <list>* <rightbrace>
<comma> ::= "," | ", "
<leftbrace> ::= "["
<rightbrace> ::= "]"
<number> ::= [0-9]+
*/
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)]
struct Packet {
elements: Vec<Element>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
enum Element {
Plain(u32),
List(Vec<Element>),
}
impl PartialOrd for Element {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
use Element::*;
match (self, other) {
(Plain(v1), Plain(v2)) => Some(v1.cmp(v2)),
(List(v1), List(v2)) => v1.partial_cmp(v2),
(Plain(_), List(_)) => List(vec![self.clone()]).partial_cmp(other),
(List(_), Plain(_)) => self.partial_cmp(&List(vec![other.clone()])),
}
}
}
impl Ord for Element {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
#[aoc_generator(day13)]
fn parse_input(input: &str) -> Vec<Packet> {
let mut out = Vec::new();
for line in input.lines() {
if line.trim().is_empty() {
continue;
}
let mut scanner = Scanner::new(line);
let packet = parse_packet(&mut scanner);
out.push(packet);
}
out
}
fn parse_packet(scanner: &mut Scanner) -> Packet {
// we can pop the first character off, it's the opening brace
scanner.pop();
let elements = parse_list(scanner);
Packet { elements }
}
fn parse_list(scanner: &mut Scanner) -> Vec<Element> {
let mut out = Vec::new();
while let Some(c) = scanner.peek() {
match c {
'[' => {
scanner.pop();
let v = parse_list(scanner);
out.push(Element::List(v));
}
c if c.is_ascii_digit() => {
let mut s = String::new();
while let Some(c) = scanner.peek() {
if c.is_ascii_digit() {
let c = scanner.pop().unwrap();
s.push(*c);
} else {
break;
}
}
let num: u32 = s.parse().unwrap();
out.push(Element::Plain(num));
}
']' => {
scanner.pop();
break;
}
_ => {
scanner.pop();
}
};
}
out
}
#[aoc_run(day13, part1)]
fn part1(input: &[Packet]) -> u32 {
let mut out = 0;
for (i, packets) in input.chunks(2).enumerate() {
//
let (left, right) = (&packets[0], &packets[1]);
if left < right {
out += i + 1;
}
}
out as u32
}
#[aoc_run(day13, part2)]
fn part2(input: &[Packet]) -> u32 {
let d1 = &parse_packet(&mut Scanner::new("[[2]]"));
let d2 = &parse_packet(&mut Scanner::new("[[6]]"));
let mut input = input.to_vec();
input.push(d1.clone());
input.push(d2.clone());
input.sort();
let mut out = 1;
for (i, p) in input.iter().enumerate() {
if p == d1 || p == d2 {
out *= i + 1;
}
}
out as u32
}
/*
#[cfg(test)]
mod test {
use super::*;
const INPUT: &str = "[1,1,3,1,1]
[1,1,5,1,1]
[[1],[2,3,4]]
[[1],4]
[9]
[[8,7,6]]
[[4,4],4,4]
[[4,4],4,4,4]
[7,7,7,7]
[7,7,7]
[]
[3]
[[[]]]
[[]]
[1,[2,[3,[4,[5,6,7]]]],8,9]
[1,[2,[3,[4,[5,6,0]]]],8,9]";
#[test]
fn part1_test() {
let v = parse_input(INPUT);
assert_eq!(part1(&v), 13);
}
#[test]
fn part2_test() {
let v = parse_input(INPUT);
assert_eq!(part2(&v), 140);
}
}
*/

View File

@ -11,5 +11,7 @@ mod d8;
mod d9;
mod d10;
mod d11;
mod d12;
mod d13;
aoc_lib! { year = 2022 }

View File

@ -0,0 +1,6 @@
[package]
name = "increasing_triplet_subsequence"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -0,0 +1,23 @@
fn main() {
dbg!(increasing_triplet(&[1, 5, 2, 3]));
}
fn increasing_triplet(nums: &[i32]) -> bool {
let mut sub_seq = [i64::MAX; 4];
sub_seq[0] = i64::MIN;
for &v in nums {
let v = v as i64;
for j in 1..4 {
if sub_seq[j - 1] < v && v < sub_seq[j] {
sub_seq[j] = v;
}
}
}
let mut m = 0;
for &v in &sub_seq[1..] {
if v < i64::MAX {
m += 1;
}
}
m > 2
}

View File

@ -0,0 +1,8 @@
[package]
name = "product_of_array_except_self"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,63 @@
struct Solution;
enum Zeros {
None,
One(usize),
Many,
}
impl Solution {
pub fn product_except_self(nums: Vec<i32>) -> Vec<i32> {
let mut out = nums;
let nums = &mut out;
let zeros = count_zeros(nums);
match zeros {
Zeros::None => {
let prod: i32 = nums.iter().product();
for x in nums.iter_mut() {
*x = prod / *x;
}
}
Zeros::One(z) => {
let (left, right) = nums.split_at(z);
let left: i32 = left.iter().product();
let right: i32 = if right.len() < 2 {
1
} else {
right[1..].iter().product()
};
for x in nums.iter_mut() {
*x = 0;
}
nums[z] = left * right;
}
Zeros::Many => *nums = vec![0; nums.len()],
}
out
}
}
fn count_zeros(nums: &[i32]) -> Zeros {
let mut out = Zeros::None;
let mut zs = false;
for (i, n) in nums.iter().enumerate() {
if *n == 0i32 {
if !zs {
out = Zeros::One(i);
zs = true;
} else {
out = Zeros::Many;
break;
}
}
}
out
}
fn main() {
let p = Solution::product_except_self(vec![-1, 1, 0, -3, 3]);
dbg!(p);
let p = Solution::product_except_self(vec![1, 2, 0, 3]);
dbg!(p);
}

View File

@ -0,0 +1,6 @@
[package]
name = "string_compression"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -0,0 +1,70 @@
fn main() {
let mut a = ['a', 'a', 'b', 'b', 'c', 'c', 'c'];
let mut b = ['a', 'a', 'a', 'b', 'b', 'a', 'a'];
let mut c = ['a'];
let mut d = ['a', 'b', 'b', 'b'];
let mut e = ['a', 'b', 'c'];
let sz = Solution::compress(&mut a);
dbg!(sz, a);
let sz = Solution::compress(&mut b);
dbg!(sz, b);
let sz = Solution::compress(&mut c);
dbg!(sz, c);
let sz = Solution::compress(&mut d);
dbg!(sz, d);
let sz = Solution::compress(&mut e);
dbg!(sz, e);
}
struct Solution;
/*
NOTE: the key to making this work was using a separate "start" marker for the start index of the
current char; I kept trying to use the "write" variable compared with the read var.
*/
impl Solution {
pub fn compress(chars: &mut [char]) -> i32 {
let (mut read, mut write) = (1, 0);
let len = chars.len();
let mut last = chars[0];
let mut start = 0;
while read < len {
let cur = chars[read];
if cur != last {
chars[write] = last;
last = cur;
let count = read - start;
start = read;
if count > 1 {
for c in Self::tok(count) {
write += 1;
chars[write] = c;
}
}
write += 1;
}
read += 1;
}
chars[write] = last;
let count = read - start;
if count > 1 {
for c in Self::tok(count) {
write += 1;
chars[write] = c;
}
}
write as i32 + 1
}
fn tok(num: usize) -> Vec<char> {
num.to_string().chars().collect()
}
}