Solution to problem 2 in Python

This commit is contained in:
David Doblas Jiménez 2022-02-07 19:52:33 +01:00
parent 782db1b1ab
commit fd38b9516b

193
src/Year_2019/P2.py Normal file
View File

@ -0,0 +1,193 @@
# --- 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?
with open("files/P2.txt") as f:
data = [int(number) for number in f.read().strip().split(",")]
def part_1() -> None:
# before starting
_data = data.copy()
_data[1] = 12
_data[2] = 2
for i in range(len(_data) // 4):
opcode = _data[4 * i]
i1 = _data[4 * i + 1]
i2 = _data[4 * i + 2]
o3 = _data[4 * i + 3]
if opcode == 1:
res = _data[i1] + _data[i2]
_data[o3] = res
elif opcode == 2:
res = _data[i1] * _data[i2]
_data[o3] = res
elif opcode == 99:
break
print(f"First value of the instructions is {_data[0]}")
# --- Part Two ---
# "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.)
# from copy import copy
def part_2() -> None:
for noun in range(100):
for verb in range(100):
# before starting
_data = data.copy()
_data[1] = noun
_data[2] = verb
for i in range(len(_data) // 4):
opcode = _data[4 * i]
i1 = _data[4 * i + 1]
i2 = _data[4 * i + 2]
o3 = _data[4 * i + 3]
if opcode == 1:
res = _data[i1] + _data[i2]
_data[o3] = res
elif opcode == 2:
res = _data[i1] * _data[i2]
_data[o3] = res
elif opcode == 99:
break
if _data[0] == 19690720:
print(f"The final result is {100*noun+verb}")
if __name__ == "__main__":
part_1()
part_2()