153 lines
2.7 KiB
Go
153 lines
2.7 KiB
Go
|
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)
|
||
|
}
|