···11-aaa: you hhh
22-you: bbb ccc
33-bbb: ddd eee
44-ccc: ddd eee fff
55-ddd: ggg
66-eee: out
77-fff: out
88-ggg: out
99-hhh: ccc fff iii
1010-iii: out
-63
day11/src/main.rs
···11-mod server;
22-use clap::Parser;
33-use server::Server;
44-55-#[derive(Parser)]
66-struct Args {
77- #[clap(short, long)]
88- file: String,
99- #[clap(short, long)]
1010- debug: bool,
1111-}
1212-1313-fn main() {
1414- let args = Args::parse();
1515- if args.debug {
1616- println!("=== Debug mode enabled ===");
1717- }
1818-1919- let mut nodes: Vec<Server> = Vec::new();
2020- let file_contents = std::fs::read_to_string(&args.file).expect("Failed to read file");
2121-2222- nodes.push(Server::new("out", 0));
2323-2424- for line in file_contents.lines() {
2525- let tokens = line.split_whitespace().collect::<Vec<_>>();
2626- let source = tokens[0];
2727- let server = Server::new(&source[..source.len() - 1], nodes.len());
2828- nodes.push(server);
2929- }
3030-3131- println!("Nodes: {:?}", nodes);
3232-3333- for line in file_contents.lines() {
3434- let tokens = line.split_whitespace().collect::<Vec<_>>();
3535- let source = &tokens[0][..tokens[0].len() - 1];
3636- let destinations = &tokens[1..];
3737- println!("Source: {}, Destinations: {:?}", source, destinations);
3838- let server_index = nodes.iter().position(|s| s.label == source).unwrap();
3939- for next_label in destinations {
4040- let index = nodes.iter().position(|s| s.label == **next_label).unwrap();
4141- nodes[server_index].add_next(index);
4242- }
4343- }
4444-4545- let you = nodes.iter().position(|s| s.label == "you").unwrap();
4646-4747- let mut paths = 0;
4848- let mut path: Vec<usize> = Vec::new();
4949-5050- path.push(you);
5151-5252- while let Some(next) = path.pop() {
5353- if next == 0 {
5454- paths += 1;
5555- continue;
5656- }
5757- for &neighbor in &nodes[next].next {
5858- path.push(neighbor);
5959- }
6060- }
6161-6262- println!("Visited {} paths", paths);
6363-}
···11-use clap::Parser;
22-use std::{fs, ops::Sub};
33-44-#[derive(Parser, Debug)]
55-#[command(author, version, about, long_about = None)]
66-struct Args {
77- #[arg(short, long)]
88- file: String,
99-}
1010-1111-// Advent of Code Day 3
1212-// Joltage battery problem
1313-1414-fn main() {
1515- let args = Args::parse();
1616-1717- let total_joltage = sum_joltage(&args.file);
1818- println!("Maximum battery joltage is {}", total_joltage);
1919-}
2020-2121-fn sum_joltage(filename: &str) -> u64 {
2222- let contents = fs::read_to_string(filename).expect("Unable to read file");
2323- let banks = contents.lines();
2424-2525- let mut total_joltage = 0;
2626- for bank in banks {
2727- total_joltage += get_12_joltage(bank);
2828- }
2929-3030- return total_joltage;
3131-}
3232-3333-// Naive approach with 2 for loops to parse string
3434-// Go to biggest number before the end and find max
3535-// Redo starting from index of previous number + 1
3636-fn get_max_joltage(bank: &str) -> u32 {
3737- // get biggest starting digit before last one
3838- let mut digit_a = 0;
3939- let mut digit_b_start = 0;
4040- for (index, c) in bank[..bank.len() - 1].chars().enumerate() {
4141- match c.to_digit(10) {
4242- Some(digit) => {
4343- if digit > digit_a {
4444- digit_a = digit;
4545- digit_b_start = index + 1;
4646- }
4747- }
4848- _ => {
4949- println!("invalid digit")
5050- }
5151- }
5252- }
5353- println!("Digit a is {} at index {}", digit_a, digit_b_start);
5454-5555- let mut digit_b = 0;
5656- for c in bank[digit_b_start..].chars() {
5757- match c.to_digit(10) {
5858- Some(digit) => {
5959- if digit > digit_b {
6060- digit_b = digit;
6161- }
6262- }
6363- _ => {
6464- println!("invalid digit")
6565- }
6666- }
6767- }
6868- println!("Digit b is {}", digit_b);
6969- return digit_a * 10 + digit_b;
7070-}
7171-7272-// Basically a sliding window approach, where you find the max value within each window
7373-// ensuring that you still have enough characters later on to fill out the required number
7474-// of batteries, represented here as K (the problem asks for 12 but generalized solution!! yay!!)
7575-fn get_k_joltages(bank: &str, k: usize) -> u64 {
7676- // initialize vector of len k for storing voltages (i cannot be bothered to use "joltage" everywhere)
7777- let mut voltages = vec![0; k];
7878-7979- // used to store global position from the slice positions
8080- let mut index_acc = 0;
8181- // used to store the relative positions in each slice
8282- let mut start_index = 0;
8383- // stores maximum value within each slice
8484- let mut max_voltage = 0;
8585-8686- for n in (1..=k).rev() {
8787- // Get the chars from start_index to len(bank)-n, shouldn't underflow bc of assert
8888- assert!(n < bank.len());
8989- let end_index = bank.len().sub(n - 1);
9090- let arr_slice = bank[start_index..end_index].chars();
9191- // println!("arr_slice: {:?} from bank: {}", arr_slice.as_str(), bank);
9292- for (index, c) in arr_slice.enumerate() {
9393- // println!(
9494- // "n: {}, index: {}, c: {}, start_index: {}, end_index: {}, max_voltage: {}",
9595- // n, index, c, start_index, end_index, max_voltage
9696- // );
9797-9898- let cvalue = c.to_digit(10).unwrap();
9999- if cvalue > max_voltage {
100100- max_voltage = cvalue;
101101- // this shit drove me so crazy.
102102- start_index = index_acc + index + 1;
103103- }
104104- }
105105- // Update global position to the location of last found maximum + 1
106106- index_acc = start_index;
107107- // after getting max value, set the nth voltage value and reset max_voltage value
108108- voltages[k - n] = max_voltage;
109109- max_voltage = 0;
110110- }
111111- // println!("Voltages: {:?}", voltages);
112112- return voltages
113113- .into_iter()
114114- .enumerate()
115115- .fold(0u64, |acc, (index, value)| {
116116- // println!("value: {}, index: {}, pow: {}", value, index, k.sub(index));
117117- acc + (value as u64).strict_mul(10u64.pow(k.sub(index + 1) as u32))
118118- });
119119-}
120120-121121-// Part 2 requires solving for 12 batteries
122122-// Likely should use recursion --PSYCH JK DIDN'T DO THAT LMAO
123123-// Basically want to find largest digit , next largest over and over
124124-// Maybe string manipulation is bad idea, using raw numbers lets powers of ten
125125-// function as indexes? So 9_000 would be bigger than 900
126126-// I think the problem can be recontextualized as "drop the lowest digits from left to right"
127127-// ^^ this was also wrong. i was dumb last night fr.
128128-fn get_12_joltage(bank: &str) -> u64 {
129129- get_k_joltages(bank, 12)
130130-}
-7
day4/Cargo.lock
···11-# This file is automatically @generated by Cargo.
22-# It is not intended for manual editing.
33-version = 4
44-55-[[package]]
66-name = "day4"
77-version = "0.1.0"
···11-# This file is automatically @generated by Cargo.
22-# It is not intended for manual editing.
33-version = 4
44-55-[[package]]
66-name = "day5"
77-version = "0.1.0"
···11-use std::cmp::Ordering;
22-use std::fmt::Debug;
33-use std::{cmp, fs};
44-55-#[derive(Debug)]
66-struct Ingredient {
77- id: u64,
88-}
99-1010-// Describes a range of ingredient ids
1111-struct IngredientRange {
1212- start: Ingredient,
1313- end: Ingredient,
1414-}
1515-1616-// Used to store and manage IngredientRanges
1717-struct IngredientDB {
1818- ranges: Vec<IngredientRange>,
1919-}
2020-2121-// #[derive(Debug, Clone, Copy, Eq)]
2222-// don't think i need to do this deriving stuff
2323-// i find it a bit scary tbh
2424-enum RangeCap {
2525- Start(u64),
2626- End(u64),
2727-}
2828-2929-// If both elements have the same type and value, they are equal
3030-impl cmp::PartialEq for RangeCap {
3131- fn eq(&self, other: &Self) -> bool {
3232- match (self, other) {
3333- (RangeCap::Start(a), RangeCap::Start(b)) => a == b,
3434- (RangeCap::End(a), RangeCap::End(b)) => a == b,
3535- _ => false,
3636- }
3737- }
3838-}
3939-4040-// Implementing an ordering for these Range Caps (better name? terminal?)
4141-impl cmp::PartialOrd for RangeCap {
4242- fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
4343- match (self, other) {
4444- // if both values are Starts or both are Ends, compare values normally
4545- (RangeCap::Start(a), RangeCap::Start(b)) => a.partial_cmp(b),
4646- (RangeCap::End(a), RangeCap::End(b)) => a.partial_cmp(b),
4747- // If they are equal, make sure Starts always go before Ends
4848- (RangeCap::Start(a), RangeCap::End(b)) => {
4949- let result = a.partial_cmp(b);
5050- if result == Some(Ordering::Equal) {
5151- Some(Ordering::Less)
5252- } else {
5353- result
5454- }
5555- }
5656- (RangeCap::End(a), RangeCap::Start(b)) => {
5757- let result = a.partial_cmp(b);
5858- if result == Some(Ordering::Equal) {
5959- Some(Ordering::Greater)
6060- } else {
6161- result
6262- }
6363- }
6464- }
6565- }
6666-}
6767-6868-impl IngredientDB {
6969- // Initializing an IngredientDB is basically parsing an input string and initializing the ranges vector.
7070- fn new(range_list: &str) -> IngredientDB {
7171- let mut ranges = Vec::new();
7272- for l in range_list.lines() {
7373- let splitline = l.split('-').collect::<Vec<&str>>();
7474- ranges.push(IngredientRange {
7575- start: Ingredient {
7676- id: splitline[0].parse().expect("Failed to parse ingredient ID"),
7777- },
7878- end: Ingredient {
7979- id: splitline[1].parse().expect("Failed to parse ingredient ID"),
8080- },
8181- });
8282- }
8383- IngredientDB { ranges }
8484- }
8585-8686- // We can check if an ingredient is fresh by comparing it to our ranges and seeing if it falls within any of them.
8787- fn is_fresh(&self, ingredient: Ingredient) -> bool {
8888- self.ranges
8989- .iter()
9090- .any(|range| range.start.id <= ingredient.id && ingredient.id <= range.end.id)
9191- }
9292-9393- // This function is called clean_ranges_stack bc i initially tried to do something else and it was a nightmare
9494- // Basically we initialize a list of RangeCaps, then sort them by value
9595- // Then we go through and push to the stack when we find a Start, pop when we find an End
9696- // If the end we find leaves our stack empty, we push a new range to our ranges vector
9797- // Finally, we replace the internal ranges of this IngredientDB with our new, optimized ranges.
9898- fn clean_ranges_stack(&mut self) {
9999- let mut range_list = Vec::<RangeCap>::new();
100100- for range in &self.ranges {
101101- range_list.push(RangeCap::Start(range.start.id));
102102- range_list.push(RangeCap::End(range.end.id));
103103- }
104104- // Sort range list by Partial Ordering
105105- // this shouldn't fail or something's wrong
106106- range_list.sort_by(|a, b| {
107107- a.partial_cmp(b)
108108- .expect("RangeCaps should be able to be compared")
109109- });
110110-111111- // initialize our stack and output range vectors
112112- let mut range_stack = Vec::<u64>::new();
113113- let mut new_ranges = Vec::<IngredientRange>::new();
114114-115115- for range in &range_list {
116116- match *range {
117117- // always push Starts to the stack
118118- RangeCap::Start(id) => range_stack.push(id),
119119- RangeCap::End(id) => {
120120- // if stack has more than 1 element, pop the top and discard
121121- // otherwise construct an IngredientRange with the final element and push it to the new_ranges vector
122122- if range_stack.len() > 1 {
123123- range_stack.pop();
124124- } else {
125125- new_ranges.push(IngredientRange {
126126- start: Ingredient {
127127- id: range_stack.pop().unwrap(),
128128- },
129129- end: Ingredient { id },
130130- });
131131- }
132132- }
133133- }
134134- }
135135-136136- self.ranges = new_ranges;
137137- }
138138-139139- // Simple math function that subtracts ends of all the ranges from the starts and adds 1 to be **inclusive**
140140- fn count_fresh(&self) -> u64 {
141141- let mut fresh_count = 0u64;
142142- for range in &self.ranges {
143143- fresh_count += range.end.id.saturating_sub(range.start.id) + 1;
144144- }
145145- fresh_count
146146- }
147147-}
148148-149149-impl Debug for IngredientRange {
150150- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151151- write!(
152152- f,
153153- "IngredientRange {{ \n\t[{}-{}] of length {}\n }}",
154154- self.start.id,
155155- self.end.id,
156156- self.end.id.saturating_sub(self.start.id) + 1
157157- )
158158- }
159159-}
160160-161161-impl Debug for IngredientDB {
162162- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163163- write!(f, "IngredientDB {{ ranges: {:?} }}", self.ranges)
164164- }
165165-}
166166-167167-fn main() {
168168- let in_file = fs::read_to_string("input.txt").expect("Failed to read file");
169169-170170- // Split our input file into two parts based on newlines and make sure there are exactly 2 parts
171171- let file_sections = in_file.split("\n\n").collect::<Vec<&str>>();
172172- assert!(file_sections.len() == 2);
173173-174174- // Parse first part of the file and initialize an IngredientDB
175175- let mut ingredient_db = IngredientDB::new(file_sections[0]);
176176-177177- // before range cleanup
178178- // println!("Ingredient Database: {:?}", ingredient_db);
179179- // cleaning our ranges up here gives us better performance for the first part! since there are less ranges to check in.
180180- ingredient_db.clean_ranges_stack();
181181- // after range cleanup
182182- // println!("Ingredient Database: {:?}", ingredient_db);
183183-184184- // to get our first star, we check each ingredient in the second section against our initialized DB and increment fresh_count
185185- let mut fresh_count = 0u64;
186186- for test_ingredient in file_sections[1].lines() {
187187- if ingredient_db.is_fresh(Ingredient {
188188- id: test_ingredient
189189- .parse()
190190- .expect("Failed to parse ingredient ID"),
191191- }) {
192192- fresh_count += 1;
193193- }
194194- }
195195-196196- println!("Fresh Ingredients in Pantry: {}", fresh_count);
197197- println!(
198198- "Fresh Ingredients in Database: {}",
199199- ingredient_db.count_fresh()
200200- );
201201-}
···11-# This file is automatically @generated by Cargo.
22-# It is not intended for manual editing.
33-version = 4
44-55-[[package]]
66-name = "day6"
77-version = "0.1.0"
···11-use std::fmt::Debug;
22-use std::fs;
33-44-mod parser;
55-// what if signed but did, punch card then?
66-//
77-enum MathProblem {
88- Sum(Vec<u64>),
99- Mult(Vec<u64>),
1010-}
1111-1212-impl Debug for MathProblem {
1313- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1414- match self {
1515- MathProblem::Sum(nums) => write!(f, "Sum({:?})", nums),
1616- MathProblem::Mult(nums) => write!(f, "Mult({:?})", nums),
1717- }
1818- }
1919-}
2020-2121-impl MathProblem {
2222- fn new(mut nums: Vec<String>) -> MathProblem {
2323- println!("nums: {:?}", nums);
2424- //let mut mynums = nums.clone();
2525- let operator: char = nums
2626- .pop()
2727- .expect("Unable to get final char from vector.")
2828- .chars()
2929- .next()
3030- .expect("Operator could not be parsed.");
3131- let values: Vec<u64> = nums.iter().map(|num| num.parse().unwrap()).collect();
3232- match operator {
3333- '+' => MathProblem::Sum(values),
3434- '*' => MathProblem::Mult(values),
3535- _ => panic!("Invalid operator"),
3636- }
3737- }
3838-3939- fn solve(&self) -> u64 {
4040- match self {
4141- MathProblem::Sum(nums) => nums.iter().sum(),
4242- MathProblem::Mult(nums) => nums.iter().product(),
4343- }
4444- }
4545-}
4646-4747-fn main() {
4848- let input = fs::read_to_string("input.txt").expect("Unable to read input file");
4949-5050- // Go line by line through input and split each line by whitespace
5151- // create a Vector of Vectors that store each column
5252- /* let mut columns: Vec<Vec<&str>> = Vec::new();
5353-5454- for line in input.lines() {
5555- for (index, word) in line.split_whitespace().enumerate() {
5656- if index < columns.len() {
5757- columns[index].push(word);
5858- } else {
5959- columns.push(vec![word]);
6060- }
6161- }
6262- } */
6363-6464- let problems = parser::parse_columns(&input);
6565-6666- let mut solutions: Vec<u64> = Vec::new();
6767- for problem in problems {
6868- // let math_problem = MathProblem::new(&mut problem);
6969- let solution = problem.solve();
7070- solutions.push(solution);
7171- println!("{:?} = {}", problem, solution);
7272- }
7373-7474- println!("Grand total of {:?}", solutions.iter().sum::<u64>());
7575-}
-76
day6/src/parser.rs
···11-use crate::MathProblem;
22-33-// how to read cephalopod grid:
44-//
55-// let Vec<Equations>
66-// convert string -> lines, convert lines to Vec(chars)
77-// let number = Vec<char>
88-// for column in line.len -> 0 ; for row in lines.len :
99-// if grid[row][col].parse() :
1010-//
1111-1212-fn normalize_rows(char_grid: Vec<Vec<char>>) -> Vec<Vec<char>> {
1313- let max_row = char_grid.iter().map(|row| row.len()).max().unwrap_or(0);
1414- char_grid
1515- .into_iter()
1616- .map(|mut row| {
1717- row.resize(max_row, ' ');
1818- row
1919- })
2020- .collect()
2121-}
2222-2323-pub fn parse_columns(input: &str) -> Vec<MathProblem> {
2424- let mut problems = Vec::new();
2525- // parse input into 2d array of chars
2626- let char_grid: Vec<Vec<char>> = input.lines().map(|line| line.chars().collect()).collect();
2727- let char_grid = normalize_rows(char_grid);
2828-2929- println!("char_grid: {:?}", char_grid);
3030-3131- let mut cur_problem = Vec::<String>::new();
3232- // Flag for whether we should skip this col
3333- let mut skip_col = false;
3434-3535- for col in 0..char_grid[0].len() {
3636- if skip_col {
3737- skip_col = false;
3838- continue;
3939- }
4040- let rcol = char_grid[0].len() - col - 1;
4141- let mut num_chars = Vec::<char>::new();
4242- let mut found_operator = false;
4343- let p: String;
4444-4545- for row in 0..char_grid.len() {
4646- if char_grid[row][rcol] == ' ' {
4747- continue;
4848- }
4949- num_chars.push(char_grid[row][rcol]);
5050- println!("num_chars: {:?}", num_chars);
5151- if char_grid[row][rcol] == '*' || char_grid[row][rcol] == '+' {
5252- found_operator = true;
5353- }
5454- }
5555- if !found_operator {
5656- // Surely there is a better way to do this repeated bit
5757- p = num_chars.iter().collect::<String>(); // }
5858- let parsed_problem = p.trim().to_string(); //}
5959- cur_problem.push(parsed_problem); // }
6060- } else {
6161- let operator = num_chars.pop().unwrap();
6262-6363- p = num_chars.iter().collect::<String>(); // }
6464- let parsed_problem = p.trim().to_string(); //}
6565- cur_problem.push(parsed_problem); // }
6666-6767- cur_problem.push(operator.to_string());
6868- println!("cur_problem: {:?}", cur_problem);
6969- let math_problem = MathProblem::new(cur_problem);
7070- problems.push(math_problem);
7171- cur_problem = Vec::new();
7272- skip_col = true;
7373- }
7474- }
7575- problems
7676-}
-7
day7/Cargo.lock
···11-# This file is automatically @generated by Cargo.
22-# It is not intended for manual editing.
33-version = 4
44-55-[[package]]
66-name = "day7"
77-version = "0.1.0"
···11-use std::collections::VecDeque;
22-use std::fmt::Debug;
33-use std::fs;
44-55-struct TachyonManifold {
66- data: Vec<Vec<char>>,
77- height: usize,
88- width: usize,
99-}
1010-1111-impl TachyonManifold {
1212- fn new(input: String) -> Self {
1313- let data: Vec<Vec<char>> = input.lines().map(|line| line.chars().collect()).collect();
1414- let height = data.len();
1515- let width = data[0].len();
1616- Self {
1717- data,
1818- height,
1919- width,
2020- }
2121- }
2222-2323- fn propagate_beam(&mut self, row: usize) -> u32 {
2424- let mut split_count = 0u32;
2525- let row_data = self.data[row].clone();
2626-2727- // THIS ANNOYINGLY CONTAINS AN IMMUTABLE BORROW for self.data[row]
2828- // SO IT BREAKS ALL MY MUTABLE REFERENCES.
2929- // THIS IS WHY THERE IS ALL THE CLONE()ING
3030- for (index, c) in row_data.iter().enumerate() {
3131- match c {
3232- 'S' | '|' => {
3333- if self.data[row + 1][index] == '.' {
3434- self.data[row + 1][index] = '|'
3535- }
3636- }
3737- '^' => {
3838- if self.data[row.saturating_sub(1)][index] == '|' {
3939- self.data[row][index + 1] = '|';
4040- self.data[row][index.saturating_sub(1)] = '|';
4141- split_count += 1;
4242- }
4343- }
4444- _ => continue,
4545- }
4646- }
4747-4848- // ANNOYINGLY HAVE TO RE-CLONE DATA BC CANT FIGURE OUT HOW TO EDIT IN PLACE
4949- let row_data = self.data[row].clone();
5050-5151- for (index, c) in row_data.iter().enumerate() {
5252- match c {
5353- '|' => {
5454- if self.data[row + 1][index] == '.' {
5555- self.data[row + 1][index] = '|'
5656- }
5757- }
5858- _ => continue,
5959- }
6060- }
6161- split_count
6262- }
6363-}
6464-6565-// NEW PLAN OKAY SO BASICALLY WE CAN PUSH EACH ROW/COL TO A STACK AND SEE IF IT HAS A LINE OF SIGHT TO THE BOTTOM, IF IT ENCOUNTERS A ^ WE PUSH TWO MORE, IF IT REACHES THE BOTTOM, WE POP
6666-6767-impl TachyonManifold {
6868- fn ez_quantum(&mut self, row: usize) -> u64 {
6969- let mut path_stack = Vec::<QuantumSplit>::new();
7070- let mut timelines = Vec::<Vec<QuantumSplit>>::new();
7171- let mut cur_timeline = Vec::<QuantumSplit>::new();
7272- // let mut success_paths = 0;
7373- // initialize two paths from starting node
7474- let start_col = self.data[row]
7575- .iter()
7676- .position(|c| *c == '^')
7777- .expect("No starting split found");
7878- println!("Start column: {}", start_col);
7979- path_stack.push(QuantumSplit::Left(row, start_col.saturating_sub(1)));
8080- path_stack.push(QuantumSplit::Right(row, start_col.saturating_add(1)));
8181-8282- while let Some(cur_path) = path_stack.pop() {
8383- //println!("Path stack: {:?}", path_stack);
8484- // Save the path we take
8585- match cur_path {
8686- QuantumSplit::Left(cur_row, cur_col) | QuantumSplit::Right(cur_row, cur_col) => {
8787- for row_index in cur_row..self.height {
8888- cur_timeline.push(cur_path.clone());
8989- if row_index == self.height - 1 {
9090- // save the full path
9191- timelines.push(cur_timeline.clone());
9292- cur_timeline.clear();
9393- // success_paths += 1;
9494- // println!("Found {} paths", success_paths);
9595- // println!("Cur_path = {:?}", cur_path);
9696- // println!("Stack = {:?}", path_stack);
9797- // println!("Found {} paths", success_paths);
9898- } else if self.data[row_index][cur_col] == '^' {
9999- path_stack
100100- .push(QuantumSplit::Left(row_index, cur_col.saturating_sub(1)));
101101- path_stack
102102- .push(QuantumSplit::Right(row_index, cur_col.saturating_add(1)));
103103- self.data[row_index][cur_col] = 'x';
104104- break;
105105- } else if self.data[row_index][cur_col] == 'x' {
106106- break;
107107- } else {
108108- self.data[row_index][cur_col] = '|';
109109- }
110110- }
111111- println!("Data: {:?}", self);
112112- }
113113- }
114114- }
115115-116116- println!("Explored map: {:?}", self);
117117- //println!("Timelines: {:?}", timelines);
118118-119119- timelines.len() as u64
120120- }
121121-}
122122-123123-// Quantum propagation thoughts
124124-// looks like a tree structure
125125-// every time we find a split, could push a new Tachyon Manifold onto the stack
126126-// --- Wait okay its one beam
127127-// so really we just need to store a stack of L/R decisions that represent
128128-// a map of outcomes
129129-// problem is... how do we distinguish whether tachyons path was unique?
130130-// save every path taken as a a string & convert to a set?
131131-// or are they just guaranteed unique structurally
132132-133133-// Okay so quantum split will represent each time we encounter a ^ traversing the file
134134-#[derive(Debug, Clone)]
135135-enum QuantumSplit {
136136- Left(usize, usize),
137137- Right(usize, usize),
138138-}
139139-140140-impl Debug for TachyonManifold {
141141- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142142- writeln!(
143143- f,
144144- "TachyonManifold of size {}, {} {{",
145145- self.width, self.height
146146- )?;
147147- for row in &self.data {
148148- for &cell in row {
149149- write!(f, "{}", cell)?;
150150- }
151151- writeln!(f)?;
152152- }
153153- writeln!(f, "}}")?;
154154- Ok(())
155155- }
156156-}
157157-158158-fn main() {
159159- let mut manifold = TachyonManifold::new(fs::read_to_string("smallinput.txt").unwrap());
160160-161161- // let mut splits = 0u32;
162162- // for row in 0..manifold.height - 1 {
163163- // splits += manifold.propagate_beam(row);
164164- // // println!("{:?}", manifold);
165165- // }
166166-167167- // Weird observation: for the small example provided
168168- // answer for total number of paths == the number of beams
169169- let beam_count = manifold.ez_quantum(2);
170170-171171- // println!("Beam split {} times.", splits);
172172- println!("Total possible paths: {}", beam_count);
173173-}