Advent of Code 2024 | Dia 3
Prólogo:
- Hoje completei o terceiro dia do Advent of Code (2024) em Rust, e existem várias coisas nas quais eu gostaria de pontuar, questões essas relacionadas á minha curva de aprendizado em Rust e meu objetivo com essa linguagem.
Desafio 1 (dia 3):
Contexto:
Foi entregue um input de arquivo de texto (como sempre), porém dessa vez era um arquivo populado com diversos caracteres aleatórios, dentro disso haviam instruções de multiplicação escondidas dentro do arquivo; o objetivo do desafio era juntar todas essas instruções
mul(X,Y), sendoX,Ynúmeros inteiros com1-3dígitos cada.Procurando formas de resolver essa etapa eu conheci o
Regex, uma linguagem que utiliza um algoritmo de busca de strings por meio de reconhecimento de padrões, determinados por um código.
- String de exemplo:
xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))
- Os números válidos serão apenas:
mul(2,4)mul(5,5)mul(11,8)mul(8,5)
- Usando essa explicação, e com os números filtrados, eu terei de multiplicar os números
X,Ye somar o resultado da multiplicação desses pares em um resoltado total.
Código:
fn p1(f: &str) -> Result<u32, Error> {
let re = Regex::new(r"mul\((?<num1>[0-9]{1,3}),(?<num2>([0-9]{1,3}))\)").unwrap();
let mut result: u32 = 0;
for caps in re.captures_iter(&fs::read_to_string(f)?) {
if let (Some(num1), Some(num2)) = (caps.name("num1"), caps.name("num2")) {
let num1 = num1.as_str().parse::<u32>().unwrap();
let num2 = num2.as_str().parse::<u32>().unwrap();
result += num1 * num2;
}
}
Ok(result)
}
Explicação:
- O
regexusado para filtragem das strings foi:mul\((?<num1>[0-9]{1,3}),(?<num2>([0-9]{1,3}))\) - Dentro da sintaxe posso usar
(?<var>(foobar)), sendo o?<var>()um identificador de variáveis dentro do padrão da string. No meu caso o regex usado determinou uma variável com números que podem ir de0-9, com esses números podendo conter de1-3dígitos.
Desafio 2 (dia 3):
Contexto:
- Nessa segunda etapa, que completa a primeira, agora tenho que complexificar um pouco o código feito anteriormente. Dessa vez tenho que seguir instruções para “ativar” ou “desativar” as instruções de multiplicaço dentro da string.
Exemplo:
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))
- O
don't()desativa as operações; - O
do()ativa as operações; - No começo as operações são ligadas por padrão;
Código:
fn p2(f: &str) -> Result<u32, Error> {
let re = Regex::new(
r"(?<cmd_do>do\(\))|(?<cmd_dont>don't\(\))|mul\((?<num1>[0-9]{1,3}),(?<num2>[0-9]{1,3})\)",
)
.unwrap();
let content = fs::read_to_string(f)?;
let mut enabled = true;
let mut result: u32 = 0;
for cap in re.captures_iter(&content) {
if cap.name("cmd_do").is_some() {
enabled = true;
} else if cap.name("cmd_dont").is_some() {
enabled = false;
} else if let (Some(num1), Some(num2)) = (cap.name("num1"), cap.name("num2")) {
if enabled {
let num1 = num1.as_str().parse::<u32>().unwrap();
let num2 = num2.as_str().parse::<u32>().unwrap();
result += num1 * num2;
}
}
}
Ok(result)
}
Explicação:
- Para conseguir identificar tudo o que era necessário tive que complexificar um pouco o
regex, ainda usando a identificação de variáveis, porém agora usando operadores lógicos (|operador ou) para conseguir identificar os 3 tipos possíveis de operação (do, don't e mul(X,Y)). - O
regexfoi dividido em 3 partes, sendo elas:
(?<cmd_do>do\(\))- usado para ativar as operações;(?<cmd_dont>don't\(\))- usado para desativar as instruções;mul\((?<num1>[0-9]{1,3}),(?<num2>[0-9]{1,3})\)- usado para identificar as instruções de multiplicação;
Considerações finais:
- Foi um desafio que envolveu um nível de complexidade maior do que o anterior, e eu acredito que eu consegui aprender bastante com isso, ademais eu sinto que a curva de aprendizado da linguagem é bem alta e envolve muita prática, para conseguir a competência necessária para desenvolver projetos pessoais de forma efetiva.
