O sétimo dia do Advent of Code foi ontem 07/12/2024! Se você caiu aqui hoje pela primeira vez, não deixe de ler os posts sobre o Dia 1, Dia 2, Dia 3, Dia 4, Dia 5 e Dia 6.

Classifiquei o sétimo problema como fácil (parte 1) e fácil (parte 2).

Dicas#

  • A parte 1 consiste em aplicar uma lista de operações sobre uma lista de operandos.

  • Você vai ter mais operandos que operadores.

  • Você pode usar iter e next para combinar listas de tamanhos diferentes.

  • Para gerar todas as combinações entre as operações pelo número de operandos, você pode usar product do itertools.

  • A parte 2 é idêntica a parte 1, mas com uma operação adicional.

Quanto de Python você precisa saber?#

Os capítulos se referem ao meu livro Introdução à Programação com Python.

  • Listas - Capítulo 6
  • Geradores, Aplicação parcial de funções, zip, itertools - Capítulo 8

Resposta#

from operator import add, mul
from itertools import product

from auxiliares import le_arquivo_sem_linhas_em_branco

ENTRADA = """190: 10 19
3267: 81 40 27
83: 17 5
156: 15 6
7290: 6 8 6 15
161011: 16 10 13
192: 17 8 14
21037: 9 7 18 13
292: 11 6 16 20"""


def concatena_inteiros(a: int, b: int) -> int:
    return int(str(a) + str(b))


def entrada_para_matriz(entrada: list[str]) -> list[list[int]]:
    return [
        [int(n) for n in linha.replace(":", "").split()]
        for linha in entrada.splitlines()
        if linha
    ]


OPERADORES = [add, mul]

OPERADORES_PARTE2 = OPERADORES + [concatena_inteiros]


def soma_válidos(entrada, operadores=OPERADORES) -> int:
    válidos = 0
    for resultado, *operandos in entrada:
        for operações in product(operadores, repeat=len(operandos) - 1):
            p = iter(operandos)
            valor = next(p)
            for operando, operação in zip(p, operações):
                valor = operação(valor, operando)
            if valor == resultado:
                válidos += resultado
                break
    return válidos


entrada_teste = entrada_para_matriz((ENTRADA))

válidos = soma_válidos(entrada_teste)
print("Válidos (teste - parte 1):", válidos)
assert válidos == 3749

entrada_parte_1 = le_arquivo_sem_linhas_em_branco("07/input.txt")
válidos = soma_válidos(entrada_para_matriz(entrada_parte_1))
print("Válidos (parte 1):", válidos)
assert válidos == 7885693428401


válidos = soma_válidos(entrada_teste, OPERADORES_PARTE2)
print("Válidos (teste - parte 2):", válidos)
assert válidos == 11387

válidos = soma_válidos(entrada_para_matriz(entrada_parte_1), OPERADORES_PARTE2)
print("Válidos (parte 2):", válidos)
assert válidos == 348360680516005

# Saída
# Válidos (teste - parte 1): 3749
# Válidos (parte 1): 7885693428401
# Válidos (teste - parte 2): 11387
# Válidos (parte 2): 348360680516005