I'm also doing the fun little Advent of Code challenges in order to learn Rust. Until now things went quite smoothly, but while I'm proceeding with the tasks I'd love to learn where I can actually improve my Rust coding (and not only getting the correct results).
I'm specifically looking for feedback where I'm violating Rust idioms or suggestions e.g. for simplifications as my knowledge of the Rust STD library features is still quite limited. On the other hand in context of those coding challenges I don't really care too much about stuff like input validation/stability/error handling or even performance (as you would in actual production code).
As requested, a small summary of what the program does, as the linked description is admittedly a little exhaustive:
The program basically simulates very basic machine code. A set of instructions represented as a list of integers values is given by a text file (comma delimited values).
Instructions start with an "opcode", describing the operations. In our case this may either be an addition (1), multiplication (2) or program end (99). All other values are deemed invalid as an opcode. The 3 integers following the opcodes are the parameters, giving the addresses of the operands (offset 1 and 2), as well as the target address to store the result (offset 3).
The result of the program is defined to be stored at address 0. In the 2nd part of the task one is given a program result (target_value 19690720) and is supposed to figure out which values need to reside at the memory addresses at 1 and 2 before starting the program (which are in this context called "noun" and "verb") in order to get this result.
Here's my implementation part 2 of day 2:
use std::fs;
fn add_values (value_a: i32, value_b: i32, target: &mut i32) {
*target = value_a + value_b
}
fn multiply_values (value_a: i32, value_b: i32, target: &mut i32) {
*target = value_a * value_b
}
fn run_program(memory: &mut Vec<i32>) -> i32 {
let command_stride = 4;
let mut current_pos = 0;
while current_pos < memory.len() {
let current_instruction = memory[current_pos];
let address_a = memory[current_pos + 1] as usize;
let address_b = memory[current_pos + 2] as usize;
let address_target = memory[current_pos + 3] as usize;
match current_instruction {
1 => add_values(memory[address_a], memory[address_b], &mut memory[address_target]),
2 => multiply_values(memory[address_a], memory[address_b], &mut memory[address_target]),
99 => break,
_ => panic!("Invalid command value!")
}
current_pos += command_stride;
}
//return result of the program stored at address 0
memory[0]
}
fn main() {
let contents = fs::read_to_string("input.txt")
.expect("Something went wrong reading the file");
let split_codes = contents.split_terminator(',');
let codes : Vec<i32> = split_codes.filter_map(|v| v.parse::<i32>().ok()).collect();
let target_value = 19690720;
for noun in 0..100 {
for verb in 0..100 {
let mut current_memory = codes.clone();
//init noun and verb
current_memory[1] = noun;
current_memory[2] = verb;
let current_result = run_program(&mut current_memory);
if current_result == target_value {
println!("Target value reached, noun: {}, verb {}", noun, verb);
println!("Result = {}", 100*noun + verb);
break;
}
}
}
}