Segundo dia do Advent of Code foi ontem 02/12/2024! Se você caiu aqui hoje pela primeira vez, não deixe de ler o post sobre o Dia 1!

Classifiquei o segundo problema como fácil (parte 1) e médio (parte 2).

Dicas#

  • Você precisa transformar cada linha de entrada em uma lista de inteiros.
  • Para saber se a lista é crescente ou decrescente, calcule a diferença entre o segundo e o primeiro elemento. O sinal do resultado da subtração indicará se a lista é deve ser crescente ou decrescente. Para saber se a lista inteira é crescente ou decrescente, continue subtraindo os elementos, dois a dois, até o final da lista. Quando a valor da subtração for positivo, a lista é crescente. Se negativo, a lista é decrescente. Mas somente se o mesmo sinal for mantido até o final da lista.
  • Lembre-se que como usamos L[i+1] - L[i], i deve ser menor que o índice do último elemento, caso contrário você terá um erro.

Exemplo de lista crescente:

L = [1, 2, 3, 4, 6]

Veja que ao subtrairmos o segundo pelo primeiro elemento, temos um valor positivo.

 2 - 1 = 1  # L[1] - L[0]
 3 - 2 = 1  # L[2] - L[1]
 4 - 3 = 1  # L[3] - L[2]
 6 - 4 = 2  # L[4] - L[3]

Decrescente:

L = [6, 4, 3, 2, 1]

Veja que ao subtrairmos o segundo pelo primeiro elemento, temos um valor negativo.

 4 - 6 = -2 # L[1] - L[0]
 3 - 4 = -1 # L[2] - L[1]
 2 - 3 = -1 # L[3] - L[2]
 1 - 2 = -1 # L[4] - L[3]

No problema do dia 2, você tem que verificar se o sinal da subtração entre os elementos da lista é sempre o mesmo, desta forma garantindo que a lista é crescente ou decrescente. Lembre que o problema estipula que a diferença entre dois elementos deve ter o mesmo sinal, mas que o valor absoluto entre dois elementos não pode ser maior que 3.

A função abs() retorna o valor absoluto de um número, ou seja, o valor sem o sinal, você pode utilizá-la quando precisar comparar um número sem considerar o sinal.

Para a segunda parte, uma das soluções é usar combinações (ver módulo itertools, função combinations). Lembre-se que permutações e combinação são diferentes. Você pode utilizar combinações para remover as entradas inválidas na parte 2.

Quanto de Python você precisa saber?#

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

  • Listas - Capítulo 6
  • Strings - Capítulo 7
  • Funções, list comprehensions e geradores - Capítulo 8
  • Módulo itertools do python

Resposta#

A listagem do módulo auxiliares.arquivos você encontra no Dia 1.

from itertools import combinations
from auxiliares import signal
from auxiliares.arquivos import uma_lista_por_linha

DIFERENÇA_MÁXIMA = 3


def valida_crescente(lista: list[int]) -> bool:
    return all(
        signal(d := lista[i + 1] - lista[i]) == 1 and 0 < abs(d) <= DIFERENÇA_MÁXIMA
        for i in range(len(lista) - 1)
    )


def valida_decrescente(lista: list[int]) -> bool:
    return all(
        signal(d := lista[i + 1] - lista[i]) == -1 and 0 < abs(d) <= DIFERENÇA_MÁXIMA
        for i in range(len(lista) - 1)
    )


def valida_lista(lista: list[int]) -> bool:
    s = signal(lista[1] - lista[0])
    return (
        valida_crescente(lista)
        if s == 1
        else valida_decrescente(lista) if s == -1 else False
    )


def valida_relatório(listas) -> list[bool]:
    return [valida_lista(lista) for lista in listas]


def valida_com_erro(lista):
    t = len(lista)
    for posições in combinations(range(t), t - 1):
        if valida_lista([lista[p] for p in posições]):
            return True
    return False


def valida_relatório_com_erro(listas):
    return [valida_com_erro(lista) for lista in listas]


resultado_teste = valida_relatório(uma_lista_por_linha("02/input_test.txt"))
assert resultado_teste.count(True) == 2
print(resultado_teste)

resultado = valida_relatório(uma_lista_por_linha("02/input.txt"))
print(resultado.count(True))
assert resultado.count(True) == 591

resultado_testes_2 = valida_relatório_com_erro(uma_lista_por_linha("02/input_test.txt"))
print(resultado_testes_2)
assert resultado_testes_2.count(True) == 4

resultado_2 = valida_relatório_com_erro(uma_lista_por_linha("02/input.txt"))
print(resultado_2.count(True))
assert resultado_2.count(True) == 621

auxiliares.signal#

def signal(x: int) -> int:
    return 1 if x > 0 else -1 if x < 0 else 0