/ 8.py
8.py
 1  #!/usr/bin/python3
 2  
 3  # run it as
 4  # ./8.py [ --one | --two ] < inputs/8
 5  
 6  import sys
 7  import math
 8  
 9  def ingest():
10      # don't you love python sometimes?
11      return [[int(char) for char in line.strip()] for line in sys.stdin.readlines()]
12  
13  def check_visible(direction_dict, mm):
14      if direction_dict.get(mm, 0) == 9:
15          return
16      if direction_dict.get(mm) is None or direction_dict.get(mm, 0) < data[line][char]:
17          visble.add((line, char))
18      direction_dict[mm] = max(data[line][char], direction_dict.get(mm, 0))
19  
20  
21  if __name__ == '__main__':
22  
23      def display():
24          winners = [sorted(rating.items(), key=lambda x: x[1])[-1][0]]
25          for line in range(length):
26              for char in range(length):
27                  if (line, char) in winners:
28                      print('▇', end='')
29                  elif (line, char) in visble:
30                      print('X', end='')
31                  else:
32                      print(data[line][char], end='')
33              print()
34  
35      data = ingest()
36      assert len(data[0]) == len(data)
37      length = len(data)
38      visble = set()
39      rating = {}
40  
41      if '--one' in sys.argv:
42          # ok, will try to be smart here
43          # check view from all 4 sides, this way I don't need to check some trees at all
44          north, south, west, east = {}, {}, {}, {}
45          for line in range(length):
46              for char in range(length):
47                  check_visible(north, char)
48          for line in reversed(range(length)):
49              for char in range(length):
50                  check_visible(south, char)
51          for char in range(length):
52              for line in range(length):
53                  check_visible(west, line)
54          for char in reversed(range(length)):
55              for line in range(length):
56                  check_visible(east, line)
57          print('visible:', len(visble))
58  
59      if '--two' in sys.argv:
60          def calc(me, neighbors):
61              value = 0
62              if not neighbors:
63                  return value
64              for n in neighbors:
65                  if n < me:
66                      value += 1
67                  elif n == me:
68                      value += 1
69                      break
70                  else:
71                      break
72              return value
73  
74          # could be optimized by not copying every tree in each direction
75          # but that's not fun anyway. It would be fun to avoid some groups of trees somehow entirely
76          for line in range(length):
77              for char in range(length):
78                  me = data[line][char]
79                  up = [data[_][char] for _ in reversed(range(0, line))]
80                  left = [data[line][_] for _ in reversed(range(0, char))]
81                  down = [data[_][char] for _ in range(line+1, length)]
82                  right = [data[line][_] for _ in range(char+1, length)]
83                  rating[(line, char)] = math.prod([calc(me, _) for _ in (up, left, down, right)])
84          # display()
85          winner_v = sorted(rating.items(), key=lambda x: x[1])[-1][1]
86          print(winner_v)