aboutsummaryrefslogtreecommitdiffstats
path: root/day5/solution.nim
blob: 2bf41aaa87dafd09ec7bff5387cd11a0cf291fa5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import std/strutils
import std/sequtils
import std/enumerate
import std/algorithm
import std/re

type
  Move = tuple 
    Amount: int
    From: int
    To: int

  Stack = seq[char]

  Input = tuple
    Stacks: seq[Stack]
    Moves: seq[Move]

proc parseContent(content: string): Input =
  # Parse stacks
  let tokens = content.split("\n\n")
  var strStacks = map(
      # All lines containing characters of the stacks 
      # Exclude last line since it contain's each stack's id
      tokens[0].splitLines()[0 .. ^2],
      proc(line: string): string =
        var retval = ""
        # keep only the relevant characters (spaces/letters)
        for i in countup(1, line.len(), 4):
          retval.add(line[i])
        retval
      )

  var Stacks = newSeq[Stack](10)

  for layer in strStacks:
    for i, c in enumerate(layer):
      if c != ' ':
        Stacks[i+1].add(c)

  var strMoves = map(
      # All moves described in the input
      tokens[1].strip().splitLines(),
      proc(line: string): seq[int] = 
        # Remove words and split on spaces
        let tokens = line.replace(re"[a-z]+ ").split(" ")
        # Parse them as integers
        map(tokens, proc (num: string): int = num.parseInt())
      )

  var Moves: seq[Move]
  for move in strMoves:
    Moves.add((move[0], move[1], move[2]))

  return (Stacks, Moves)

proc makeMove(stacks: var seq[Stack], move: Move, inPlace = false): void =
  # copy top of the stack
  var yoink = stacks[move.From][0 ..< move.Amount]
  # moving in place preserves the order of the moved crates (part2)
  if not inPlace:
    yoink.reverse()
  # remove it from origin
  stacks[move.From].delete(0 ..< move.Amount)
  # concat it in front of destination
  stacks[move.To] = concat(yoink, stacks[move.To])

proc getAnswer(stacks: seq[Stack]): string =
  var answer = ""
  for stack in stacks:
    if stack.len() > 0:
      answer.add(stack[0])
  answer

let content = readFile("./input.txt")
var input = parseContent(content)

let moves = input.Moves
var stacksPart1 = input.Stacks
var stacksPart2 = input.Stacks

for move in moves:
  makeMove(stacksPart1, move)
  makeMove(stacksPart2, move, true)

echo getAnswer(stacksPart1)
echo getAnswer(stacksPart2)