aboutsummaryrefslogtreecommitdiff
path: root/2020/seventeen.nim
blob: 8e4ab4979d076b980a03a9c7f1c0ade97ae94817 (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
# Day Seventeen: Conway Cubes
import std/os, std/sets, std/enumerate

let input: string = paramStr(1)
type Coord = tuple[x,y,z,w: int]

# Coordinate system: 0,0 is at the top left
var dimension: HashSet[Coord]
for y, line in enumerate(lines(input)):
  for x, cube in line:
    if cube == '#':
      dimension.incl((x,y,0,0))
      # stdout.write(x, ",", y, " ")
    # stdout.write(cube)
  # stdout.write('\n')
# echo(dimension)

## Return a tuple describing a dimension's largest axes
func maximum(dim: HashSet[Coord]): tuple[x,y,z,w: int] =
  result = (0,0,0,0)
  for cube in dim:
    if abs(cube.x) > result.x: result.x = abs(cube.x)
    if abs(cube.y) > result.y: result.y = abs(cube.y)
    if abs(cube.z) > result.z: result.z = abs(cube.z)
    if abs(cube.w) > result.w: result.w = abs(cube.w)

## Return the number of cubes neighboring an arbitary point in space
func neighbors(cube: Coord, dim: HashSet[Coord]): int =
  result = 0
  for x in -1 .. 1:
    for y in -1 .. 1:
      for z in -1 .. 1:
        for w in -1 .. 1:
          if ((cube.x+x, cube.y+y, cube.z+z, cube.w+w) in dim) and ((x,y,z,w) != (0,0,0,0)):
            inc(result)

## Run one cycle of a pocket dimension
func cycle(dim: HashSet[Coord]): HashSet[Coord] =
  let max = maximum(dim)
  for x in -max.x-1 .. max.x+1:
    for y in -max.y-1 .. max.y+1:
      for z in -max.z-1 .. max.z+1:
        for w in -max.w-1 .. max.w+1:
          let coord = (x,y,z,w)
          if coord in dim:
            if coord.neighbors(dim) == 2 or coord.neighbors(dim) == 3:
              result.incl(coord)
          if coord notin dim:
            if coord.neighbors(dim) == 3:
              result.incl(coord)

func cycle(dim: HashSet[Coord], reps: int): HashSet[Coord] =
  result = dim
  for i in 1 .. reps:
    result = cycle(result)

## Visualize output
proc echo(dim: HashSet[Coord]) =
  let max = maximum(dim)
  for w in -max.w .. max.w:
    for z in -max.z .. max.z:
      stdout.write("z=", z, ", ", "w=", w, '\n')
      for y in -max.y .. max.y:
        for x in -max.x .. max.x:
          if (x,y,z,w) == (0,0,0,0):
            stdout.write('0')
          elif (x,y,z,w) in dim:
            stdout.write('#')
          else:
            stdout.write('.')
        stdout.write('\n')
      stdout.write('\n')

echo len(dimension.cycle(6))