Advent of Code 2023 Day 10: Pipe Maze
Foto de Capa gerada por IA
Já no dia seguinte, ao chegar na ilha flutuante de metal você se depara com um clima frio e literalmente tudo ali é feito de metal. Flores, grama e tudo mais é feito de puro metal porém, nenhum animal é avistado. Existem também alguns avisos de Águas termais em uma direção e você resolve dar uma olhada.
Enquanto caminha, ao longe você percebe um movimento perto de algo que parece ser um tubo metálico. Rapidamente é possível fazer um esboço dos tubos ali e este é seu input para o desafio de hoje!
Contexto específico
No desafio de hoje o input é mais como um mapa e existem caracteres indicando conexões entre os tubos. Existem tubos em linha e tubos em formato de “cotovelos” ou ângulos de 90
graus.
Para resolver o desafio é preciso encontrar o ponto mais distante do início (notado pelo caractere S
no mapa). Só é possível se mover entre tubos, então uma medição em linha reta não faz sentido.
Resolução Parte 1
Caso queira resolver antes de ler a respeito de minha solução, esse é o momento!
Como o desafio fazia menção a um mapa, decidi que seria interessante criar algumas abstrações para cada parte do mesmo e separei entre arquivos diferentes.
Tile
O Tile
é justamente a coordenada [x, y]
que pode conter um tubo conectando 2 outros tiles ou apenas o chão. É necessário saber algumas informações como:
- se ele é o tile inicial
- suas conexões diretas
- coordenadas
Para isso, foi criado um Módulo chamado Tile()
usando algumas constantes que podem ser obersvadas no arquivo tile.js
como
- a constante
TILES
responsável por identificar cada caractere - a constante
TILES_CONNECTION_OFFSET
responsável por conhecer osoffsets
de cada tubo
Essas constantes foram omitidas e podem ser encontradas no arquivo tile.js
mencionado anteriormente. A implementação do Tile()
ficou então da seguinte forma
export const Tile = ({ tileType, coordinates }) => {
let tileConnections = []
const connectToTile = (tile) => {
if (tileConnections.length > 1) {
return
}
tileConnections.push(tile)
}
return {
name: () => `tile[${coordinates[0]}][${coordinates[1]}]`,
isStartTile: () => tileType === TILES.STARTING,
getTileConnections: () => tileConnections,
getTileConnectionsCoordinatesOffset: () =>
TILES_CONNECTIONS_OFFSET[tileType],
connectToTile,
coordinates,
}
}
Maze
Para isolar a lógica exclusiva ao “labirinto” foi criada uma abstração chamada Maze
. Esta é a abstração que isola a maior parte da lógica relacionada a
- Preencher os valores dos tubos
- Conectar os tubos enquanto itera pelo mapa
- Isolar o cálculo de distâncias entre os pontos
Sua implementação ficou um pouco complexa e notei que havia o código criado em um dia anterior que se encaixaria muito bem no caso de uso de um mapa 2d
envolvendo encontrar pontos adjascentes. Foi então que o Módulo Square()
foi criado e colocado dentro do diretório de utils no arquivo square.js
.
A respeito do Módulo Maze()
, notei que existia muita lógica envolvida a conexão e cálculo do ponto mais distante do início e também isolei essa lógica em outro Módulo chamado DistanceConnections()
(encontrada no arquivo distance-connections.js
). A implementação do Módulo Maze()
pode ser encontrada no arquivo maze.js
.
Assim, o estado interno do Módulo Maze()
, sua função interna de setup e sua API ficou da seguinte forma:
export const Maze = ({ data }) => {
let internalSquare = null
let getAdjascentPoints = null
let MAZE = null
let START_TILE = null
let distanceConnections = null
// ...
const init = () => {
internalSquare = Square({
data,
itemCallbackFn: buildMazeTilesCallbackFn,
})
getAdjascentPoints = internalSquare.getAdjascentPoints
MAZE = internalSquare.getSquare()
fillMazeConnections()
distanceConnections = DistanceConnections({ startTile: START_TILE })
distanceConnections.evaluateDistance()
}
init()
return {
getFarthestPointFromStart: distanceConnections.getFarthestDistance,
}
}
Com a lógica isolada dentro dos respetivos Módulos foi possível encontrar o ponto mais distante apenas chamando uma função maze.getFarthestPointFromStart()
e assim, resolvendo o desafio!
Assim que a primeira parte foi encerrada, a segunda parte fica disponível e agora é necessário contar quantos Tile
s existem na parte interna dos tubos.
Nota: Ainda estou resolvendo a segunda parte desse 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:
Map
Object- Documentação a respeito de
Closures
- Parágrafo sobre o padrão de Módulo dentro da documentação de
IIFE
Métodos Array:
Métodos String: