advent-of-code/2022/go/05/answer.go

153 lines
2.7 KiB
Go
Raw Permalink Normal View History

2023-08-03 17:45:59 +02:00
package main
import (
"bufio"
"errors"
"fmt"
"log"
"os"
"strconv"
"strings"
)
type Stack []byte
func (s *Stack) String() string {
var res strings.Builder
for _, crate := range *s {
res.WriteByte(crate)
res.WriteString(" ")
}
return res.String()
}
func (s *Stack) isEmpty() bool {
return len(*s) == 0
}
func (s *Stack) push(t ...byte) {
*s = append(*s, t...)
}
func (s *Stack) pop(n int) ([]byte, error) {
if s.isEmpty() {
return nil, errors.New("Couldn't pop from empty stack")
}
index := len(*s) - n
ret := (*s)[index:]
*s = (*s)[:index]
return ret, nil
}
type Move struct {
n, from, to int
}
type Input struct {
stacks []Stack
moves []Move
}
func input(filename string) *Input {
file, err := os.Open(filename)
check(err, "Couldn't open %q", filename)
defer file.Close()
input := &Input{}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var n_stacks int = 0
// Parse the stacks
for scanner.Scan() {
line := scanner.Text()
if line[1] == '1' {
break
}
if len(input.stacks) == 0 {
n_stacks = (len(line) + 1) / 4
input.stacks = make([]Stack, n_stacks)
}
for i := 0; i < n_stacks; i++ {
crate := line[4*i+1]
if crate != ' ' {
input.stacks[i].push(crate)
}
}
}
// Reverse the stacks since they were added top-down and not bottom-up
for _, stack := range input.stacks {
for i, j := 0, len(stack)-1; i < j; i, j = i+1, j-1 {
stack[i], stack[j] = stack[j], stack[i]
}
}
scanner.Scan() // get rid of the empty line after the labeling of the stacks
// Parse the moves
for scanner.Scan() {
line := scanner.Text()
tokens := strings.Split(line, " ")
n, err := strconv.Atoi(tokens[1])
check(err, "Couldn't convert %q to int", tokens[1])
from, err := strconv.Atoi(tokens[3])
check(err, "Couldn't convert %q to int", tokens[3])
to, err := strconv.Atoi(tokens[5])
check(err, "Couldn't convert %q to int", tokens[5])
input.moves = append(input.moves, Move{
n: n,
from: from,
to: to,
})
}
return input
}
func result(inp *Input, part int8) string {
var res strings.Builder
for _, move := range inp.moves {
moving, err := inp.stacks[move.from-1].pop(int(move.n))
check(err, "ntm")
if part == 1 {
for i, j := 0, len(moving)-1; i < j; i, j = i+1, j-1 {
moving[i], moving[j] = moving[j], moving[i]
}
}
inp.stacks[move.to-1].push(moving...)
}
for _, stack := range inp.stacks {
log.Print(stack.String())
res.WriteByte(stack[len(stack)-1])
}
return res.String()
}
func check(e error, msg string, vals ...any) {
if e != nil {
log.Printf("ERROR: "+msg, vals)
panic(e)
}
}
func main() {
result := result(input("sample1"), 1)
log.Println(result)
fmt.Println(result)
}