#!/bin/env python3

import dataclasses

@dataclasses.dataclass(frozen=True)
class MountainRange:
  N: int
  R: int
  mountains: list[list[int]]

def get_mountain_range(filename: str) -> MountainRange:
  with open(filename, 'r') as fin:
    N, R = list(map(int, next(fin).split(' ')[:2]))
    mountains = [list(map(int, next(fin).split(' '))) for _ in range(N)]
  return MountainRange(N=N, R=R, mountains=mountains)

def visualize(mr: MountainRange):
  N = mr.N
  R = mr.R
  mountains = sorted(mr.mountains, reverse=True, key=lambda tup: tup[1])
  canvas: list[str] = []
  unit_width = 1  # How many characters each unit on the graph is.

  def print_canvas(canvas: list[str]):
    fstring = f'{{:>{unit_width}s}}'

    print('-' * (unit_width * R + R - 1))
    for row in canvas[::-1]:
      for col in row[1:]:
        print(fstring.format(col), end=' ')
      print()
    print('-' * (unit_width * R + R - 1))


  for mountain in mountains:  # Reverse order.
    H, X, D = mountain[:3]
    B = mountain[3] if len(mountain) > 3 else 2 * H + 1
    half = B // 2 + 1
    for dx in range(half):
      height = int(H - H * dx / half)  # H / half is the slope.

      for h in range(height):
        while len(canvas) <= h:
          canvas.append([''] * (R + 1))

        for idx in (X - dx, X + dx):
          canvas[h][idx] = str(D)

    unit_width = max(unit_width, len(str(D)))

    print_canvas(canvas)

  print_canvas(canvas)

def part1(mr: MountainRange):
  N = mr.N
  R = mr.R
  mountains = [mountain[:3] for mountain in mr.mountains]

  heights = [0] * (R + 1)  # Ignore index 0.
  num_visible = 0
  for mountain in sorted(mountains, key=lambda tup: tup[2]):  # Sort by distance, ascending.
    visible = False
    H, X, D = mountain
    for dx in range(H):
      height = H - dx

      # Check the left and right sides.
      for idx in (X - dx, X + dx):
        if heights[idx] < height:
          heights[idx] = height
          visible = True

    if visible:
      num_visible += 1

  print(num_visible)

def part2(mr: MountainRange):
  N = mr.N
  R = mr.R
  mountains = [mountain[:4] for mountain in mr.mountains]

  heights = [0] * (R + 1)  # Ignore index 0.
  num_visible = 0
  for mountain in sorted(mountains, key=lambda tup: tup[2]):  # Sort by distance, ascending.
    visible = False
    H, X, D, B = mountain
    half = B // 2 + 1
    for dx in range(half):
      height = int(H - H * dx / half)

      # Check the left and right sides.
      for idx in (X - dx, X + dx):
        if heights[idx] < height:
          heights[idx] = height
          visible = True

    if visible:
      num_visible += 1

  print(num_visible)

mr = get_mountain_range('input1.txt')
visualize(mr)
part1(mr)

mr = get_mountain_range('input2.txt')
visualize(mr)
part1(mr)
part2(mr)
