Go: Advent of code 2015, dia 1: Hello Buffer!
Um pouco de história
Antes de começar, acho importante voltar um pouco no tempo para explicar por que estou a fazer este desafio.
Durante todos os meus anos na área de TI, nunca me dediquei seriamente a aprender uma linguagem de programação. Aprendi um pouco de Pascal, C++ e Visual Basic na escola, o que me deu uma compreensão básica de programação, mas nunca me despertou o interesse por aprender mais, e para ser honesto nem me lembro de nada! Talvez porque os projetos da escola fossem aborrecidos e nunca me motivassem a aprender mais, ou talvez porque estivesse mais interessado em hardware do que no desenvolvimento de software. Alguns anos depois, quando comecei a concentrar-me mais no Linux, aprendi Bash, o que tem sido bastante útil para automatizar várias tarefas, inclusive criar diversas ferramentas para a minha equipa em nossas atividades diárias em ambientes de produção.
No entanto, tenho tido cada vez mais ideias para diferentes projetos (alguns mais tolos que outros), e a necessidade de aprender uma linguagem de programação surgiu! Comecei por aprender Python e o meu interesse cresceu. Realizei alguns projetos pequenos e divertidos, mas decidi abrandar, mudar de rumo e aprender Go! Por quê? Simplesmente porque sim! Todas as ferramentas com as quais trabalho diariamente são escritas em Go, e depois de algum tempo a pensar, considero que Go é a linguagem mais adequada para os projetos que tenho em mente. Talvez esteja errado, mas… como dizia o meu avô: “O conhecimento não ocupa lugar!”
Depois de vários dias a estudar os conceitos básicos de Go, decidi começar a resolver os problemas do Advent of Code e comecei pelo ano de 2015, o que nos leva ao tópico e à descoberta de hoje!
O problema
Podem saber mais sobre o desafio aqui. Mas, de forma muito resumida, o problema consiste em calcular o piso de um elevador com base em uma série de parênteses que indicam se o elevador sobe ou desce. Por exemplo, se o elevador começar no piso 0 e a entrada for (((
ou (()(()(
, o elevador subirá até o piso 3. Se a entrada for ())
, o elevador descerá até o piso -1.
Ooh! Este é fácil, pensei eu na minha inocência!
Primeiro, uma função elevador que recebe as instruções e retorna o piso onde o elevador termina.
func elevator(instructions string) int{
var floor int
for _, instruction := range instructions {
if instruction == '(' {
floor++
} else if instruction == ')' {
floor--
}
}
return floor
}
E depois só tenho que pedir ao “Pai Natal” para inserir as instruções, imprimir o resultado e está ganho!
func main() {
var instructions string
fmt.Print("What floor you want to go?: " )
fmt.Scan(&instructions)
lastFloor := elevator(instructions)
fmt.Println("final Floor: ", lastFloor)
}
Introduzo as instruções e, epa! Sou uma máquina! Tudo funciona perfeitamente! (()))
retorna 3 e ())
retorna -1.
Pego no input do desafio e… Errado!!! Para os programadores mais veteranos, isto é capaz de ser bastante óbvio, mas para o pequeno inocente eu, foi o suficiente para passar a tarde a bater com a cabeça contra a parede.
Primeiro, foquei-me no facto de que o resultado estava errado e decidi adicionar um print extra, na esperança de tentar perceber o que se estava a passar.
func main() {
var instructions string
fmt.Print("What floor you want to go?: " )
fmt.Scan(&instructions)
fmt.Println("instructions: ", instructions)
lastFloor := elevator(instructions)
fmt.Println("final Floor: ", lastFloor)
}
Heeeey! A saída das instruções não é igual à entrada! O que está a acontecer aqui? E se eu ler de um ficheiro de texto? Será que tenho o mesmo problema? Alterei o código para ler de um ficheiro de texto:
func main() {
instructions, err := os.ReadFile("input.txt")
if err != nil {
panic(err)
}
floor := elevator(string(instructions))
fmt.Println("Final floor:", floor)
Desta vez, o resultado foi diferente. Introduzi o resultado no site e… Correto! Mas por quê? O que se passa aqui? Obtive a resposta correta para o exercício, mas, no entanto, ainda não consegui entender o que estava acontecendo. Decidi, então, comparar o resultado do input feito pelo utilizador e o input lido do ficheiro de texto.
A minha primeira ideia foi perceber se as strings tinham o mesmo tamanho e comparar o resultado de ambas.
func main() {
var instructionsFromInput string
fmt.Print("What floor you want to go?: " )
fmt.Scan(&instructionsFromInput)
fmt.Println("instructions: ", instructionsFromInput)
fmt.Println("Length from input: ", len(instructionsFromInput))
instructionsFromFile, err := os.ReadFile("../01/input.txt")
if err != nil {
panic(err)
}
fmt.Println("Lenght from file: ", len(instructionsFromFile))
lastFloorFromInput := elevator(instructionsFromInput)
lastFloorFromFile := elevator(string(instructionsFromFile))
fmt.Println("Final Floor From input: ", lastFloorFromInput)
fmt.Println("Final Floor from file: ", lastFloorFromFile)
}
EUREKA! Sou noob! ou será que não?
$go run main.go
What floor you want to go?: (((())))()((((((((())()(()))(()((((()(()(((()((()((()(()()()()()))(((()(()((((((((((())(()()((())()(((())))()(()(()((()(()))(()()()()((()((()(((()()(((((((()()())()((((()()(((((()(())()(())((())()()))()(((((((())(()())(()(((())(()))((())))(()((()())))()())((((())))(()(((((()(())(((()()((()((()((((((((((())(()())))))()))())()()((((()()()()()()((((((())())(((()())()((()()(((()()()))(((((()))(((()(()()()(()(()(((())()))(()(((()((())()(()())())))((()()()(()()(((()))(((()((((()(((((()()(()())((()())())(()((((((()(()()))((((()))))())((())()()((()(()))))((((((((()))(()()(((())())(())()((()()()()((()((()((()()(((())))(()((())()((((((((()((()(()()(((())())())))(())())))()((((()))))))())))()()))()())((()())()((()()()))(()()(((()(())((((())())((((((((()()()()())))()()()((((()()))))))()((((()(((()))(()()())))((()()(((()))()()())())(((())((()()(())()()()(((())))))()())((()))()))((())()()())()())()()(()))())))())()))(())((()(())))(()(())(()))))(()(())())(()(())(()(()))))((()())()))()((((()()))))())))()()())((())()((()()()))()(((()(()))))(())()()))(((()())))))))))(((())))()))())()))))()()(((())))))))()(()()(()))((()))))((())))((()((())))())))()()(()))())()(()((()())(()(()()())())(()()))()))))(()())()()))()()()()))(()(()(()))))))()(()))()))()()(()((())(()(())))()(((())(())())))))()(()(()))))()))(()()()(())()(()(())))()))))()()(((((())))))())()())())())()())()))))()))))))))())()()()()()()())))()))((())()))())))()((())()))))()))())))))))())()()()))()()(()((((()(((((((()(())((()())((()()))()))))(())))()()()(())((())()())))(())))(())))(((()()))()(())(((()(()))((())))())()))((((()))())()))))))))()(())())))(()))()(()()))())()()(())())))())()()(()())))()((()())(()(())(())))))))))))))(()))))()))))))()()())(()(((((()(()())))())()))(()))()))(()()))()())(()))())()(())((()()))))))())))())()(((())))(()(()))()()))()(()))))))((()())(()))))))()())))()()))))))))((((((((()()()(()))))))()())))())))()()((())()))((())(())))())())))()()()((()((()(())))())()(())))))))))()())))()()()()()()))()))((())())(()(()))))))(()()))()))(())))()))))))))))))(()))))))))()))))()))()())()))()()))))))()))))((()))))(()))())()(())))(()())((((()())))()))))(()))()(()()(())))))())))))()))))))())))())))))())))())())))())(()))))(())()(())))())()))((()()))))))())))((())))))))())))(())))))()()())))))())))))()))))))()))()()()(()(((()())())())(()))())))))((()(())(()))))))))(())))()()()())())(()))))()()()))()))())())())()(())))()(((()((((())))))))()))))))))))))))))))))((())()())(()))))()()))))))(()()(())())))())))((())))((())))))))))))))()))))()(()))))))())))))()))(()()())(()())))))))))()))))))(())))))()()))()())(((())))()))(()))))))))(())())))())))())())())()()))((())()(())()())()))()())(())(()))))()())))(()(((()))))))()(()())()()()))()))))))))()()()(())()())()(((((()))()())())(()))))()()()(())))())))()((()())))(()))())()(()())())(()))()()))((()()))((()()()()())))(())()))(()(())))((()()))))))))())))))))())()()))))))))))))))))(())()(())(())()())())()))()(()))))())())))))()())()(()))()()(())))(())())))))(()))))))))))))))())())(())(())))(((()))()))))())((())(()))())))))))())))))())))()))()))))))))))))())()))))()))))((()))(())))()(())))(())()))()))())))())))))))()(()())())))()()())))(())))))(()))))))))))))(()))()))()))())))(((()()()(())((()())))()())(((()))(())()))((()()()())))())(())(()))))()(((((())))(()))())())))))))((((()()()))())())()(()(()())))))))))()())())))(())))()())(((()(())())()()))())())))))))((()())((()()(()))(()(())))()))()))(()))(()))()()(()(((())((((()))()(()))((())()(()(()())()(()))()())))))(()))()))())()())))())))(())))((())(()())))))()))(())(()))()())()(()()((()(()))))))()(())(()())(())()))(((())()))(()()(()()()))))(()(())))()))))())))))())(()()()()()()(((())))(()()))()((())(((((()()())))(()))(()))()()))(((())())()(((()()()()))))(()))(())())))()())(()()())())))))))()))))((())))()())(()))(()(()))())))))())(())))))()()())())()))()()(())))(()))(())((((((())(()))(()))())()))(()()(())))()))(()()))()))()(())))(())))((()(()))(())()()())())))(((()()())(())()))))))()(((()(((((()()(((())(())))())()((()))))((()())()(())(((())))(((()((()(()(()))(()()))())(()))(())(())))()))))))((((()))()((((()(()))()))()()))))()(()(()))()(()((()(((()(()()(((()))))()(((()(()(()(((()(()())())()()(()(()())())(()((((())(()))()))(((((()()())(())()((()()())))()()(((()()))()((((((((()(())))())((()))))(())))(()))))((()((((()()(())(((((()))(((((((((((((()())))((((()(((()((())())()))((()))()(()()((()()()()(()()(()(()(((())()(()((((((()((()()((())()((((()((()()(()()())((()()()((()((())()(()(((()((())((((())(()))((()(()))(()())()((((((((()(((((((((((()))(()(((()(()()()((((())((())()())()))(())((())(()))(((()((()(())))(()))))((()()))))((((()(()(()())(()(())((((((((()((((()((()(((((()))())()(()))(()()((()(())(((((()(())()(((((()()))))))()(((())()(()()((((())()((())((()(((())(((()))((()()((((()(())))))((()((((()((()((()(((())((()))(((((((()(((()((((((((())()))((((())(((((()((((((((()(((()((()(((()()(((()((((((()()(()((((((((()()(()(()(())((((()())()))))(((()))((((())((((()())((()(())()((()((((((()((((((()(())))()())(((())())())()(())()(()())((()()((((())((((((())(()(((((()((((())()((((()(()(())(()())(((())()((())((((()))()((((((())(()(((()(((()((((((()(((()))(()()())())((()((()())()((((())(((()(()(((((((((())(())))()((()()()()(())((()))(((((((()(((((((((()(()))))(()((((((((()((((()((()()((((((()()(((((((()(()(())()(())((()()()((()(((((()())()(((((()())()()((()(()())(()()()(((()()(((((()((((((()()((()(()()()((((((((((((()((((((((()()(((()())))()(((()()(())())((((()((((()((((()()()(())(())((()(()(((((((((((((((()(())(())))))()()))((()(((()(())((()(((()(()()((((()()(((()(((()(((((()()((()(()(((()))((((((()((((((((()((()((())(((((()(((())(())())((()()))((((())()()((()(((()(((((()()(((()))(((()(()(((((((((((((()))((((((((()(((()))))())((((((((((((())((())((()())(((())((())(()((((((((((()(((())((()()(()((())(((((((((((()))((((((((((((()(()())((()((()((()(()(((()((((((((()()(()((()(()(((()))((()))(((((((((((((()(())((((((())(((()(())(()(()(()((()()))((((()((((()((((())))())((((()((((()))((((((()((((((()((()(((())))((())(()))(()((()((((()((()(((()()))((((()()()(((((((())(((())(()))())((((()())(((()(((((((((((()(()(()((()(((((((((((((((()()((((()((((((((()(((()()((()((((()))(((()(())((((((()((((())()((((()((()))(())()(()(((()((())())((((((()(()(())())(((())(()(()())(((((()((()((())()())(())))(((()(())))))))(((()(((()))()((()(((()()((()())()()))())))(((()))(()(((()(((((((((()(()(((((()()(((()())()()))))()(((()))(((()(()(()(()(()))()(())()))(()(((())))(()))))))))))(())((()((())((()(())()(())((()()((((()()((()()))((())(((()((()(())(())))()(()(((((()((()))())()(((((()()(((()(()((((((())(()))(())()))((()(()()))(())())()))(((())))(()((()(((())(())())))((()()((((((((((((((()((()(()()(()(((()))())()()((()()()(())(()))(()())(((())((())()(())()()(()()(())))((()(((()))))(((()()(()()))())((()((())()))((((()()()())((())))(((()(())(((((()(((((()((()(()((((()()(((()()()(((()())(((()()((((())(()))(((()))(())())((()))(((()((()))(((()()((())((()(((((()((((()()())((()))()((((()((()(()()()(
Length from input: 4095
Lenght from file: 7001
Final Floor From input: -633
Final Floor from file: 232
Hmm… interessante. Quando passo as instruções do elevador pelo input no terminal, o resultado é diferente porque faltam instruções! Aqui tudo começou a fazer mais sentido e, depois de um pouco de pesquisa, descobri que o buffer do terminal tem um limite de 4096 bytes, e tudo o que passar disso é cortado.
Bah, que “granda” noob! Normalmente, quando sei que o input é grande, uso sempre um ficheiro, até porque geralmente obtenho os dados de algum lugar, guardo num ficheiro para depois ler e processar. Mas neste caso, como o Pai Natal entra num elevador e coloca instruções para o mesmo, pensei que seria mais simples pegar o “input” do site e passá-las diretamente pelo terminal, só que não!
Parte 2
Quanto à parte 2, essa foi bastante fácil e todo o código deste exercício está disponível no meu repositório do GitHub.