Advent of Code 2023 Day 15: Lens Library
Foto de Capa gerada por IA
Após arrumar ter arrumado os refletores no desafio de ontem, a luz refletida está sendo apontada para outra montanha próxima: A maior montanha na Lava Island. Lá é onde a Lava é produzida e existe uma instalação completa com muita segurança envolvida.
Indo até lá, seu trabalho será ajudar as Renas Natalinas a configurar uma série de lentes com base em um manual. Porém antes de começar é necessário entender um algoritmo de HASH (Holiday ASCII String Helper) que converte qualquer string em um valor ASCII de 0
a 256
. Ele é usado para validar se você está usando as configurações corretas.
Você também possui a initialization sequence (seu input) para descobrir qual é valor correto a ser usado para inicializar o sistema.
Contexto específico
O input é uma sequência de caracteres separada por vírgulas. Cada grupo de caracteres tem no máximo 4
caracteres agrupados e seu objetivo é executar o algoritmo HASH e somar os valores de cada grupo.
O Algoritmo em si é relativamente simples. Para uma sequência de caracteres deve-se
- começar com o valor atual
0
(ou usar o valor atual da iteração anterior) - encontrar o ASCII code para o caractere e somar ao valor atual
- multiplicar por
17
- salvar o resto da divisão por
256
como valor atual
Esses passos devem ser executados para cada caractere da lista até chegar ao final da mesma.
Resolução Parte 1
Caso queira resolver antes de ler a respeito de minha solução, esse é o momento!
Para a primeira parte o desafio bastava iterar sobre a lista, executar o algoritmo e somar os valores para obter a solução.
O algoritmo HASH foi escrito em um arquivo separado de nome hash-algorightm.js
e foi implementado da seguinte forma
const MULTIPLY_FACTOR = 17
const REMAINDER_FACTOR = 256
export const hashAlgorithm = ({ character, currentValue = 0 }) => {
const asciiCode = character.charCodeAt(0) + currentValue
const multipliedValue = asciiCode * MULTIPLY_FACTOR
const remainderValue = multipliedValue % REMAINDER_FACTOR
return remainderValue
}
E a iteração sobre a lista de grupos de caracteres foram dois laços encadeados
const findSumOfHashResultsForSequence = (sequence) => {
let sumOfHashResults = 0
for (const charSequence of sequence) {
let currentValue = 0
for (const character of charSequence.split('')) {
currentValue = hashAlgorithm({ character, currentValue })
}
sumOfHashResults += currentValue
}
return sumOfHashResults
}
O parâmetro sequence
passado já está com os grupos das sequências quebradas a partir do input.
Com a primeira parte do desafio resolvida sendo o valor de sumOfHashResults
, a segunda parte fica disponível. Nela é mencionado a existência de uma sequência de caixas com aberturas para o posicionar lentes na parte interna de cada caixa. Essas lentes serão usadas para focar a luz que passa em linha reta pelo centro das caixas.
Seu trabalho agora era encontrar onde as lentes seriam colocadas, removidas e substituídas entre essas caixas para conseguir calcular o poder focal do conjunto.
Resolução Parte 2
Novamente, Caso queira resolver a segunda parte antes de ler a respeito de minha solução, interrompa sua leitura aqui mesmo!
O input na verdade era uma sequência de instruções! É necessário executar essas instruções que se caracterizam entre:
- colocar uma determinada lente em uma caixa
- remover uma determinada lente de uma caixa
- substituir uma determinada lente por outra de mesmo nome, com distância focal diferente
Para esse trabalho foi criada uma estrutura que guarda o estado das caixas (BOXES
) que internamente seria apenas um objeto Map()
do JavaScript. Essa estrutura levou o nome de LensBoxes()
e foi implementada no arquivo lens-boxes.js
.
Segue um esboço da implementação com seções omitidas mas com a API no final do trecho de código:
export const LensBoxes = () => {
const BOXES = new Map()
/* ... */
const addLensToBox = ({ lensLabel, lensValue, boxId }) => {
/* ... */
}
const removeLensFromBox = ({ lensLabel, boxId }) => {
/* ... */
}
const executeOperation = ({ operation }) => {
const [lensLabel, lensValue] = operation.match(/\w+|\d+/g)
const boxId = findBoxId(lensLabel)
if (lensValue) {
// add/update lens to box
addLensToBox({ lensLabel, lensValue, boxId })
} else {
// remove lens from box
removeLensFromBox({ lensLabel, boxId })
}
}
const findFocusPowerOfLens = ({ lensValue, boxId, slotPower }) =>
(boxId + 1) * slotPower * lensValue
const evaluateFocusPower = () => {
let focusPower = 0
for (const [boxId, boxLens] of BOXES) {
for (let i = 0; i < boxLens.length; i++) {
const [, lensValue] = boxLens[i].split(' ')
focusPower += findFocusPowerOfLens({
boxId,
lensValue: Number(lensValue),
slotPower: i + 1,
})
}
}
return focusPower
}
return {
executeOperation,
evaluateFocusPower,
}
}
Usando essa estrutura, é possível executar operações com a função executeOperation()
e calcular o poder focal com a função evaluateFocusPower()
. O código final para a solução do desafio teria apenas que iterar sobre a sequência, executar as operações que modificariam as lentes nas caixas e ao final de tudo calcular o poder focal total
const lensBoxes = LensBoxes()
for (const operation of initSequence) {
lensBoxes.executeOperation({ operation })
}
const focusPower = lensBoxes.evaluateFocusPower()
Como resultado, obtemos a solução para a parte 2 do desafio!
Referências
O código final esta disponível no repositório do GitHub. Esses são alguns links que podem te auxiliar a compreender melhor o código e cada detalhe que mencionei ou esqueci de comentar a respeito de minha solução:
Métodos Array:
Métodos String: