haro87

5933065?v=4

haro87
: haro87

About me

Nothing here yet. Update your profile at /profiles/haro87.adoc

Day 00: python

This solution is written in Python. It is the solution for becoming a team member of the aoc-2019 community.

Hello, world!

The solution is pretty simple, just one line of code.

print('Hello, world!')

Day 01: python

This solution is written in Python. It is the solution for the first day of AoC: The Tyranny of the Rocket Equation

Fuel calculation

The solution for the first part is pretty simple. The function calculate_fuel_requirement calculates the required fuel based on the given mass.

The solution for the second part is a bit more complicated. The function calculate_fuel_requirement_plus calculates the required fuel based on the given mass of the required fuel. Recursion is the hint you need.

import math

def calculate_fuel_requirement(mass):
    """Calculates the fuel requirement
    based on the given mass. (Part 1)

    Parameters:
    mass (int): mass of the module

    Returns:
    int:Fuel required

    """
    return math.floor(mass / 3) - 2

def calculate_fuel_requirement_plus(fuel):
    """Calculates the fuel requirement
    based on the given fuel mass. (Part 2)

    Parameters:
    fuel (int): mass of the fuel

    Returns:
    int:Additional fuel required

    """
    add = math.floor(fuel / 3) - 2
    if add > 0:
        return add + calculate_fuel_requirement_plus(add)
    else:
        return 0

with open("input.txt", "r") as masses:
    fuel = 0
    fueladd = 0
    for mass in masses:
        mfuel = calculate_fuel_requirement(int(mass))
        fuel = fuel + mfuel
        fueladd = fueladd + calculate_fuel_requirement_plus(mfuel)
    print('Fuel required: {0}'.format(str(fuel)))
    print('Fuel required based on fuel: {0}'.format(str(fueladd)))
    print('Fuel required total: {0}'.format(str(fuel + fueladd)))

Day 02: python

This solution is written in Python. It is the solution for the second day of AoC: 1202 Program Alarm

Fixing the board computer

The solution for the first part consists of translating the input values and executing them. Attention: you need to operate on the whole data set.

The solution for the second part is basically a brute force approach to find the right noun and verb.

import random
from enterprise import MontgomeryScott as Scotty

scotty = Scotty()

def part_one():
    with open('input.txt', "r") as commands:
        trans = scotty.translate(commands.read())
        res = scotty.execute(trans)
        print('Part one, Scotty says: {0}'.format(res[0]))


def part_two():
    with open('input.txt', "r") as commands:
        orig = scotty.translate(commands.read())
        res = 0
        while res != 19690720:
            noun = random.randint(0, 99)
            verb = random.randint(0, 99)
            program = orig.copy()
            program[1] = noun
            program[2] = verb
            res = scotty.execute(program)[0]

    print('Part two, Scotty says: {0}'.format(100 * noun + verb))

part_one()

part_two()

Day 03: python

This solution is written in Python. It is the solution for the third day of AoC: Crossed Wires

Crossed Wires

This was the hardest puzzle for me up until now. No tests this time due to some other priorities. :-( You can run the solution by python solution.py

from enterprise import PavelChekov as Chekov

chekov = Chekov()

with open('input.txt', "r") as commands:
    commands1, commands2 = commands.read().splitlines()
    instructions1 = chekov.wire_up(commands1)
    instructions2 = chekov.wire_up(commands2)
    plan1 = chekov.wire_points(instructions1)
    plan2 = chekov.wire_points(instructions2)

    res1 = chekov.wire_cross(plan1, plan2)
    print('Part one, Chekov says: {0}'.format(res1))

    res2 = chekov.wire_intersect(plan1, plan2)
    print('Part two, Chekov says: {0}'.format(res2))

Day 04: python

This solution is written in Python. It is the solution for the fourth day of AoC: Secure Container

Finding the code

The solution for the first part was achieved by iterating over each position in a 6 digit code and subtracting the two adjacent values. If the value is < 0 then we had an decrease which would violate the rules. Furthermore we needed to check whether there is at least one occurance of matching adjacent positions. The calculation is the same as for the first one but having a 0 as result of that calculation indicates matching positions.

The solution for the second part was achieved by counting the occurances of values in the code and checking if there was at least one count of exactly two matching values.

The solution can be run by python solution.py:

import random
from enterprise import NyotaUhura as Uhura

uhura = Uhura()

START = 240920
END = 789857

codes = uhura.valid_no_decrease(START, END)
codes = uhura.valid_same(codes)

print('Part one, Uhura says: {0}'.format(len(codes)))

codes = uhura.valid_larger_group(codes)

print('Part two, Uhura says: {0}'.format(len(codes)))

The actual methods are in a separate class:

import collections

class NyotaUhura:

    def valid_no_decrease(self, start, end):
        validcodes = []
        for code in range(start, end):
            code = str(code)
            decrease = False
            for pos in range(0, len(code)-1):
                value1 = int(code[pos])
                value2 = int(code[pos+1])
                calc = value2 - value1
                if calc < 0:
                    decrease = True
            if not decrease:
                validcodes.append(code)
        return validcodes

    def valid_same(self, codes):
        validcodes = []
        for code in codes:
            same = False
            for pos in range(0, len(code)-1):
                value1 = int(code[pos])
                value2 = int(code[pos+1])
                calc = value2 - value1
                if calc == 0:
                    same = True
            if same:
                validcodes.append(code)
        return validcodes

    def valid_larger_group(self, codes):
        validcodes = []
        for code in codes:
            c=collections.Counter(code)
            large = False
            for count in c.values():
                count = int(count)
                if count == 2:
                    large = True
            if large:
                validcodes.append(code)
        return validcodes

Test cases are derived from the puzzle description and can be run by pytest enterprise_test.py

import pytest
from unittest import TestCase
from enterprise import NyotaUhura as Uhura

class Test_Enterprise(TestCase):
    def test_no_decrease_one(self):
        uhura = Uhura()
        res = uhura.valid_no_decrease(111111, 111112)
        self.assertEqual(res, ["111111"])

    def test_no_decrease_two(self):
        uhura = Uhura()
        res = uhura.valid_no_decrease(223450, 223451)
        self.assertEqual(res, [])

    def test_same_one(self):
        uhura = Uhura()
        res = uhura.valid_same(["123789"])
        self.assertEqual(res, [])

    def test_large_one(self):
        uhura = Uhura()
        res = uhura.valid_larger_group(["112233"])
        self.assertEqual(res, ["112233"])

    def test_large_two(self):
        uhura = Uhura()
        res = uhura.valid_larger_group(["123444"])
        self.assertEqual(res, [])

    def test_large_three(self):
        uhura = Uhura()
        res = uhura.valid_larger_group(["111122"])
        self.assertEqual(res, ["111122"])

Day 05: python

This solution is written in Python. It is the solution for the fifth day of AoC: Sunny with a Chance of Asteroids

Sunny with a Chance of Asteroids

The solution for the fifth day is not that hard but it still took me some time. Structure is key and I learned some new Python features along the way.

The solution can be run by python solution.py:

import random
import os
from enterprise import MontgomeryScott as Scotty

cwd = os.getcwd()
ifile = cwd + "/input.txt"

with open(ifile, "r") as commands:
    #Part one
    scotty = Scotty(input=1)
    trans = scotty.translate(commands.read())
    res = scotty.execute(trans.copy())
    print("Scotty says the solution for part one is: {0}".format(res[-1]))

    #Part two
    scotty = Scotty(input=5)
    res = scotty.execute(trans.copy())
    print("Scotty says the solution for part two is: {0}".format(res[-1]))

The actual methods are in a separate class:

import logging
from enum import Enum

logging.basicConfig(level=logging.ERROR)

class Instruction(Enum):
    ADD = 1
    MULTIPLY = 2
    STORE = 3
    OUTPUT = 4
    JUMP_IF_TRUE = 5
    JUMP_IF_FALSE = 6
    LESS_THAN = 7
    EQUALS = 8

class Mode(Enum):
    POSITION = 0
    IMMEDIATE = 1

class Command:
    inst = 0
    modes = [].copy()
    def __init__(self, opcode):
        self.inst = opcode // 10**0 % 10
        del self.modes[:]
        self.modes.append(opcode // 10**2 % 10)
        self.modes.append(opcode // 10**3 % 10)
        self.modes.append(opcode // 10**4 % 10)


    def instruction(self):
        return self.inst

    def parameter_modes(self):
        return self.modes

class MontgomeryScott:

    def __init__(self, input):
        self.input = input

    def _add(self, one, two):
        return one + two

    def _multiply(self, one, two):
        return one * two

    def _store(self, value, add, program):
        if add < len(program):
            program[add] = value
        else:
            logging.error("ERROR -> Address: {0} out of bounds".format(add))

    def _output(self, add, program):
        if add < len(program):
            return program[add]
        else:
            logging.error("ERROR -> Address: {0} out of bounds".format(add))
            return None

    def _get_parameters(self, count, command, program):
        params = []
        pos = count + 1
        for mode in command.parameter_modes():
            if command.instruction() > 4 and command.instruction() < 7 and len(params) == 2:
                break
            if mode == Mode.IMMEDIATE.value:
                if pos < len(program):
                    params.append(program[pos])
                else:
                    logging.error("ERROR -> Address: {0} out of bounds".format(pos))
            if mode == Mode.POSITION.value:
                if pos < len(program):
                    add = program[pos]
                    if len(params) == 2:
                        if  add < len(program):
                            params.append(add)
                        else:
                            logging.error("ERROR -> Address: {0} out of bounds".format(add))
                    else:
                        if  add < len(program):
                            params.append(program[add])
                        else:
                            logging.error("ERROR -> Address: {0} out of bounds".format(add))
                else:
                    logging.error("ERROR -> Address: {0} out of bounds".format(pos))
            pos = pos + 1

        if command.instruction() > 2 and command.instruction() <= 4:
             params = [params[0]]
        logging.info("INFO -> Collected paramters: {0}".format(params))

        return params

    def translate(self, code):

        trans = str(code).split(',')
        trans = list(map(int, trans))
        return trans


    def execute(self, commands):
        output = []
        count = 0
        while count <= len(commands):
            c =  commands[count]
            if c == 99:
                break
            command = Command(c)
            if command.instruction() < 1 or command.instruction() > 8:
                count = count + 1
                continue
            logging.info("INFO -> Instruction: {0}".format(command.instruction()))
            if (command.instruction() > 0 and command.instruction() < 3) or command.instruction() > 4:
                params = self._get_parameters(count, command, commands)
                logging.info("INFO -> Parameters: {0}".format(params))
            if command.instruction() == Instruction.ADD.value:
                if len(params) < 3:
                    logging.error("ERROR -> Not enough paramters for ADD at position {0}".format(count))
                    continue
                self._store(self._add(params[0], params[1]), params[2], commands)
                count = count + 4
            elif command.instruction() == Instruction.MULTIPLY.value:
                if len(params) < 3:
                    logging.error("ERROR -> Not enough paramters for MULTIPLY at position {0}".format(count))
                    continue
                self._store(self._multiply(params[0], params[1]), params[2], commands)
                count = count + 4
            elif command.instruction() == Instruction.STORE.value:
                self._store(self.input, commands[count + 1], commands)
                count = count +2
            elif command.instruction() == Instruction.OUTPUT.value:
                out = self._output(commands[count + 1], commands)
                output.append(out)
                print("-->OUTPUT: {0}".format(out))
                count = count + 2
            elif command.instruction() == Instruction.JUMP_IF_TRUE.value:
                if params[0] != 0:
                    count = params[1]
                else:
                    count = count + 3
            elif command.instruction() == Instruction.JUMP_IF_FALSE.value:
                if params[0] == 0:
                    count = params[1]
                else:
                    count = count + 3
            elif command.instruction() == Instruction.LESS_THAN.value:
                if params[0] < params [1]:
                    self._store(1, params[2], commands)
                else:
                    self._store(0, params[2], commands)
                count = count + 4
            elif command.instruction() == Instruction.EQUALS.value:
                if params[0] == params[1]:
                    self._store(1, params[2], commands)
                else:
                    self._store(0, params[2], commands)
                count = count + 4
            else:
                count = count + 1
        return output

Test cases are derived from the puzzle description and can be run by pytest enterprise_test.py

import pytest
from unittest import TestCase
from enterprise import MontgomeryScott as Scotty

class Test_Enterprise(TestCase):
    def test_translate(self):
        scotty = Scotty(input=1)
        res = scotty.translate('3,0,4,0,99')
        self.assertEqual(res, [3, 0, 4, 0, 99])

    def test_execute_pos_equal_eight(self):
        scotty = Scotty(input=8)
        trans = scotty.translate('3,9,8,9,10,9,4,9,99,-1,8')
        res = scotty.execute(trans)
        self.assertEqual(res, [1])

    def test_execute_pos_not_equal_eight(self):
        scotty = Scotty(input=1)
        trans = scotty.translate('3,9,8,9,10,9,4,9,99,-1,8')
        res = scotty.execute(trans)
        self.assertEqual(res, [0])

    def test_execute_pos_less_than_eight(self):
        scotty = Scotty(input=1)
        trans = scotty.translate('3,9,7,9,10,9,4,9,99,-1,8')
        res = scotty.execute(trans)
        self.assertEqual(res, [1])

    def test_execute_pos_more_than_eight(self):
        scotty = Scotty(input=9)
        trans = scotty.translate('3,9,7,9,10,9,4,9,99,-1,8')
        res = scotty.execute(trans)
        self.assertEqual(res, [0])

    def test_execute_im_equal_eight(self):
        scotty = Scotty(input=8)
        trans = scotty.translate('3,3,1108,-1,8,3,4,3,99')
        res = scotty.execute(trans)
        self.assertEqual(res, [1])

    def test_execute_im_not_equal_eight(self):
        scotty = Scotty(input=1)
        trans = scotty.translate('3,3,1108,-1,8,3,4,3,99')
        res = scotty.execute(trans)
        self.assertEqual(res, [0])

    def test_execute_im_less_than_eight(self):
        scotty = Scotty(input=1)
        trans = scotty.translate('3,3,1107,-1,8,3,4,3,99')
        res = scotty.execute(trans)
        self.assertEqual(res, [1])

    def test_execute_im_more_than_eight(self):
        scotty = Scotty(input=9)
        trans = scotty.translate('3,3,1107,-1,8,3,4,3,99')
        res = scotty.execute(trans)
        self.assertEqual(res, [0])