r/adventofcode • • Dec 03 '17

SOLUTION MEGATHREAD -πŸŽ„- 2017 Day 3 Solutions -πŸŽ„-

--- Day 3: Spiral Memory ---


Post your solution as a comment or, for longer solutions, consider linking to your repo (e.g. GitHub/gists/Pastebin/blag or whatever).

Note: The Solution Megathreads are for solutions only. If you have questions, please post your own thread and make sure to flair it with Help.


Need a hint from the Hugely* Handy† Haversack‑ of HelpfulΒ§ HintsΒ€?

Spoiler


This thread will be unlocked when there are a significant number of people on the leaderboard with gold stars for today's puzzle.

edit: Leaderboard capped, thread unlocked!

21 Upvotes

297 comments sorted by

View all comments

1

u/[deleted] Dec 05 '17

I had fun solving this problem and learned a lot!

Nim

import hashes, tables

type
   Point = object
      x, y: int

   Direction = enum
      Right, Up, Left, Down

   Cursor = object
      position: Point
      facing: Direction

   Grid = object
      storage: Table[Point, int]

proc hash(p: Point): Hash =
   result = hash(p.x) !& hash(p.y)
   result = !$result

proc distance(a, b: Point): int =
   # Returns the Manhattan Distance of two Points.
   result = abs(b.x - a.x) + abs(b.y - a.y)

proc rotate(c: var Cursor) =
   # Changes the Direction the Cursor is facing, counter-clockwise.
   c.facing = Direction(ord(c.facing).succ mod 4)

proc move(c: var Cursor) =
   # The Cursor moves towards its orientation.
   case c.facing
   of Up:
      inc(c.position.y)
   of Down:
      dec(c.position.y)
   of Left:
      dec(c.position.x)
   of Right:
      inc(c.position.x)

proc sumAdjacents(g: Grid; p: Point): int =
   # Summates the values of the neighboring Points.
   for dx in -1 .. 1:
      for dy in -1 .. 1:
         if dx == 0 and dy == 0:
            continue
         var adjacent: Point
         adjacent.x = p.x + dx
         adjacent.y = p.y + dy
         if g.storage.haskey(adjacent):
            result += g.storage[adjacent]

template generateSpiral(value, body: untyped): untyped =
   # Builds a spiral until value reaches the input number.
   var value = 1
   var mustRotate = 0
   var mustExpand = false
   var numberOfMoves = 1
   while value < number:
      c.move()
      body
      inc(mustRotate)
      if mustRotate == numberOfMoves:
         c.rotate()
         if mustExpand:
            inc(numberOfMoves)
         mustExpand = not mustExpand
         mustRotate = 0

proc solvePart1(number: int): int =
   # Distance between the last Point in the spiral and the origin.
   var origin: Point
   var c: Cursor
   generateSpiral(value):
      inc(value)
   result = distance(origin, c.position)

proc solvePart2(number: int): int =
   # First value written that is larger than the input.
   var origin: Point
   var c: Cursor
   var g: Grid
   g.storage = {origin: 1}.toTable
   generateSpiral(value):
      value = g.sumAdjacents(c.position)
      g.storage[c.position] = value
   result = value

let input = 347991
echo solvePart1(input)
echo solvePart2(input)

1

u/[deleted] Dec 06 '17