浏览代码

solve day 2

Andrew Swistak 6 年之前
父节点
当前提交
0266ff4f6d
共有 5 个文件被更改,包括 256 次插入0 次删除
  1. 2 0
      src/day_2/mod.rs
  2. 131 0
      src/day_2/puzzle_1.rs
  3. 1 0
      src/day_2/puzzle_1.txt
  4. 116 0
      src/day_2/puzzle_2.rs
  5. 6 0
      src/main.rs

+ 2 - 0
src/day_2/mod.rs

@@ -0,0 +1,2 @@
+pub mod puzzle_1;
+pub mod puzzle_2;

+ 131 - 0
src/day_2/puzzle_1.rs

@@ -0,0 +1,131 @@
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+use std::path::Path;
+
+/*
+--- Day 2: 1202 Program Alarm ---
+
+On the way to your gravity assist around the Moon, your ship computer beeps angrily about a "1202
+program alarm". On the radio, an Elf is already explaining how to handle the situation: "Don't
+worry, that's perfectly norma--" The ship computer bursts into flames.
+
+You notify the Elves that the computer's magic smoke seems to have escaped. "That computer ran
+Intcode programs like the gravity assist program it was working on; surely there are enough spare
+parts up there to build a new Intcode computer!"
+
+An Intcode program is a list of integers separated by commas (like 1,0,0,3,99). To run one, start
+by looking at the first integer (called position 0). Here, you will find an opcode - either 1, 2,
+or 99. The opcode indicates what to do; for example, 99 means that the program is finished and
+should immediately halt. Encountering an unknown opcode means something went wrong.
+
+Opcode 1 adds together numbers read from two positions and stores the result in a third position.
+The three integers immediately after the opcode tell you these three positions - the first two
+indicate the positions from which you should read the input values, and the third indicates the
+position at which the output should be stored.
+
+For example, if your Intcode computer encounters 1,10,20,30, it should read the values at positions
+10 and 20, add those values, and then overwrite the value at position 30 with their sum.
+
+Opcode 2 works exactly like opcode 1, except it multiplies the two inputs instead of adding them.
+Again, the three integers after the opcode indicate where the inputs and outputs are, not their
+values.
+
+Once you're done processing an opcode, move to the next one by stepping forward 4 positions.
+
+For example, suppose you have the following program:
+
+1,9,10,3,2,3,11,0,99,30,40,50
+
+For the purposes of illustration, here is the same program split into multiple lines:
+
+1,9,10,3,
+2,3,11,0,
+99,
+30,40,50
+
+The first four integers, 1,9,10,3, are at positions 0, 1, 2, and 3. Together, they represent the
+first opcode (1, addition), the positions of the two inputs (9 and 10), and the position of the
+output (3). To handle this opcode, you first need to get the values at the input positions:
+position 9 contains 30, and position 10 contains 40. Add these numbers together to get 70. Then,
+store this value at the output position; here, the output position (3) is at position 3, so it
+overwrites itself. Afterward, the program looks like this:
+
+1,9,10,70,
+2,3,11,0,
+99,
+30,40,50
+
+Step forward 4 positions to reach the next opcode, 2. This opcode works just like the previous, but
+it multiplies instead of adding. The inputs are at positions 3 and 11; these positions contain 70
+and 50 respectively. Multiplying these produces 3500; this is stored at position 0:
+
+3500,9,10,70,
+2,3,11,0,
+99,
+30,40,50
+
+Stepping forward 4 more positions arrives at opcode 99, halting the program.
+
+Here are the initial and final states of a few more small programs:
+
+    1,0,0,0,99 becomes 2,0,0,0,99 (1 + 1 = 2).
+    2,3,0,3,99 becomes 2,3,0,6,99 (3 * 2 = 6).
+    2,4,4,5,99,0 becomes 2,4,4,5,99,9801 (99 * 99 = 9801).
+    1,1,1,4,99,5,6,0,99 becomes 30,1,1,4,2,5,6,0,99.
+
+Once you have a working computer, the first step is to restore the gravity assist program (your
+puzzle input) to the "1202 program alarm" state it had just before the last computer caught
+fire. To do this, before running the program, replace position 1 with the value 12 and replace
+position 2 with the value 2.
+
+What value is left at position 0 after the program halts?
+
+*/
+
+pub fn solve() {
+    let mut opcodes: Vec<i32> = read_opcodes("src/day_2/puzzle_1.txt");
+    opcodes[1] = 12;
+    opcodes[2] = 2;
+
+    let mut index: usize = 0;
+
+    // We are making assumptions here that input is always well formed and comes in quadruplets
+    while index < opcodes.len() {
+        let opcode = opcodes[index];
+
+        if opcode == 99 {
+            break;
+        }
+
+        let arg1 = opcodes[index + 1] as usize;
+        let arg2 = opcodes[index + 2] as usize;
+        let res_index: usize = opcodes[index + 3] as usize;
+
+        println!(
+            "opcode: {}, arg1: {}, arg2: {}, res_index: {}",
+            opcode, arg1, arg2, res_index
+        );
+
+        match opcode {
+            1 => opcodes[res_index] = opcodes[arg1] + opcodes[arg2],
+            2 => opcodes[res_index] = opcodes[arg1] * opcodes[arg2],
+            _ => panic!(),
+        }
+
+        index += 4;
+    }
+
+    println!("{}", opcodes[0]);
+}
+
+fn read_opcodes(filename: impl AsRef<Path>) -> Vec<i32> {
+    let file = File::open(filename).expect("no such file");
+    let mut opcodes = String::new();
+    let _ = BufReader::new(file).read_line(&mut opcodes);
+
+    opcodes
+        .trim()
+        .split(',')
+        .map(|opcode| opcode.parse::<i32>().expect("could not parse opcode"))
+        .collect()
+}

+ 1 - 0
src/day_2/puzzle_1.txt

@@ -0,0 +1 @@
+1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,9,1,19,1,19,6,23,2,6,23,27,2,27,9,31,1,5,31,35,1,35,10,39,2,39,9,43,1,5,43,47,2,47,10,51,1,51,6,55,1,5,55,59,2,6,59,63,2,63,6,67,1,5,67,71,1,71,9,75,2,75,10,79,1,79,5,83,1,10,83,87,1,5,87,91,2,13,91,95,1,95,10,99,2,99,13,103,1,103,5,107,1,107,13,111,2,111,9,115,1,6,115,119,2,119,6,123,1,123,6,127,1,127,9,131,1,6,131,135,1,135,2,139,1,139,10,0,99,2,0,14,0

+ 116 - 0
src/day_2/puzzle_2.rs

@@ -0,0 +1,116 @@
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+use std::path::Path;
+
+/*
+"Good, the new computer seems to be working correctly! Keep it nearby during this mission - you'll
+probably use it again. Real Intcode computers support many more features than your new one, but
+we'll let you know what they are as you need them."
+
+"However, your current priority should be to complete your gravity assist around the Moon. For this
+mission to succeed, we should settle on some terminology for the parts you've already built."
+
+Intcode programs are given as a list of integers; these values are used as the initial state for
+the computer's memory. When you run an Intcode program, make sure to start by initializing memory
+to the program's values. A position in memory is called an address (for example, the first value in
+memory is at "address 0").
+
+Opcodes (like 1, 2, or 99) mark the beginning of an instruction. The values used immediately after
+an opcode, if any, are called the instruction's parameters. For example, in the instruction
+1,2,3,4, 1 is the opcode; 2, 3, and 4 are the parameters. The instruction 99 contains only an
+opcode and has no parameters.
+
+The address of the current instruction is called the instruction pointer; it starts at 0. After an
+instruction finishes, the instruction pointer increases by the number of values in the instruction;
+until you add more instructions to the computer, this is always 4 (1 opcode + 3 parameters) for the
+add and multiply instructions. (The halt instruction would increase the instruction pointer by 1,
+but it halts the program instead.)
+
+"With terminology out of the way, we're ready to proceed. To complete the gravity assist, you need
+to determine what pair of inputs produces the output 19690720."
+
+The inputs should still be provided to the program by replacing the values at addresses 1 and 2,
+just like before. In this program, the value placed in address 1 is called the noun, and the value
+placed in address 2 is called the verb. Each of the two input values will be between 0 and 99,
+inclusive.
+
+Once the program has halted, its output is available at address 0, also just like before. Each time
+you try a pair of inputs, make sure you first reset the computer's memory to the values in the
+program (your puzzle input) - in other words, don't reuse memory from a previous attempt.
+
+Find the input noun and verb that cause the program to produce the output 19690720. What is 100 *
+noun + verb? (For example, if noun=12 and verb=2, the answer would be 1202.)
+*/
+
+pub fn solve() {
+    let opcodes: Vec<i32> = read_opcodes("src/day_2/puzzle_1.txt");
+
+    let combo = find_noun_verb(opcodes);
+    let noun = combo.0;
+    let verb = combo.1;
+
+    println!("noun/verb: {:?}", combo);
+    println!("answer: {}", noun*100 + verb);
+}
+
+fn find_noun_verb(opcodes: Vec<i32>) -> (i32, i32) {
+    let mut noun: usize = 0;
+    let mut verb: usize = 0;
+
+    while noun <= 99 {
+        while verb <= 99 {
+            let mut instruction_set = opcodes.clone();
+            instruction_set[1] = noun as i32;
+            instruction_set[2] = verb as i32;
+
+            let res = run_opcodes(instruction_set);
+
+            if res == 19690720 {
+                return (noun as i32, verb as i32);
+            }
+            verb += 1;
+        }
+        verb = 0;
+        noun += 1;
+    }
+
+    panic!("could not determine noun/verb combo");
+}
+
+fn run_opcodes(mut opcodes: Vec<i32>) -> i32 {
+    let mut index: usize = 0;
+
+    while index < opcodes.len() {
+        let opcode = opcodes[index];
+
+        if opcode == 99 {
+            break;
+        }
+
+        let arg1 = opcodes[index + 1] as usize;
+        let arg2 = opcodes[index + 2] as usize;
+        let res_index: usize = opcodes[index + 3] as usize;
+
+        match opcode {
+            1 => opcodes[res_index] = opcodes[arg1] + opcodes[arg2],
+            2 => opcodes[res_index] = opcodes[arg1] * opcodes[arg2],
+            _ => panic!(),
+        }
+
+        index += 4;
+    }
+
+    opcodes[0]
+}
+
+fn read_opcodes(filename: impl AsRef<Path>) -> Vec<i32> {
+    let file = File::open(filename).expect("no such file");
+    let mut opcodes = String::new();
+    let _ = BufReader::new(file).read_line(&mut opcodes);
+
+    opcodes
+        .trim()
+        .split(',')
+        .map(|opcode| opcode.parse::<i32>().expect("could not parse opcode"))
+        .collect()
+}

+ 6 - 0
src/main.rs

@@ -2,6 +2,7 @@
 extern crate clap;
 
 mod day_1;
+mod day_2;
 
 fn main() {
     use clap::App;
@@ -18,6 +19,11 @@ fn main() {
             p if p == 2 => day_1::puzzle_2::solve(),
             _ => println!("unavailable puzzle given!"),
         },
+        d if d == 2 => match puzzle {
+            p if p == 1 => day_2::puzzle_1::solve(),
+            p if p == 2 => day_2::puzzle_2::solve(),
+            _ => println!("unavailable puzzle given!"),
+        },
         _ => println!("unavailable day given!"),
     }
 }