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.