package main

import (
	"bufio"
	"log"
	"os"
	"strconv"
)

type coord [2]int

var directions = []coord{
	{-1, 0}, //left
	{1, 0},  //right
	{0, -1}, // up
	{0, 1},  // down

	// diagonal
	{-1, -1},
	{-1, 1},
	{1, -1},
	{1, 1},
}

type matrix [][]int

type seen map[coord]bool

func main() {
	if err := myMain(); err != nil {
		log.Println(err)
	}
}

func myMain() error {
	m, err := parseInput("input.txt")
	if err != nil {
		return err
	}

	log.Println(solveFirst(m))

	log.Println(solveSecond(m))

	return nil
}

func solveFirst(m matrix) int {
	var ret int
	for step := 0; step < 100; step++ {
		for row := range m {
			for col := range m[0] {
				m[row][col]++
			}
		}
		s := seen{}
		for row := range m {
			for col := range m[0] {
				ret += s.flash(m, row, col)
			}
		}
		s = seen{} // reset flashes

		for row := range m {
			for col := range m[0] {
				if m[row][col] > 9 {
					m[row][col] = 0
				}
			}
		}
	}

	return ret
}

func solveSecond(m matrix) int {
	var step int
	for ; ; step++ {
		for row := range m {
			for col := range m[0] {
				m[row][col]++
			}
		}
		s := seen{}
		for row := range m {
			for col := range m[0] {
				s.flash(m, row, col)
			}
		}
		s = seen{} // reset flashes

		for row := range m {
			for col := range m[0] {
				if m[row][col] > 9 {
					m[row][col] = 0
				}
			}
		}

		if m.fullFlash() {
			break
		}
	}

	return step + 1
}

func (m matrix) fullFlash() bool {
	for row := range m {
		for col := range m[0] {
			if m[row][col] != 0 {
				return false
			}
		}
	}
	return true
}

func (s seen) flash(m matrix, row, col int) int {
	var flash int
	if m[row][col] <= 9 || s[coord{row, col}] {
		return flash
	}

	s[coord{row, col}] = true
	flash++

	for _, d := range directions {
		newrow := row + d[0]
		newcol := col + d[1]
		if newrow >= 0 && newrow < len(m) &&
			newcol >= 0 && newcol < len(m[0]) {
			m[newrow][newcol]++
			flash += s.flash(m, newrow, newcol)
		}
	}

	return flash
}

func parseInput(fileName string) (matrix, error) {
	var ret = matrix{}
	fd, err := os.Open(fileName)
	if err != nil {
		return ret, err
	}
	defer fd.Close()

	buf := bufio.NewScanner(fd)
	var line []int
	for buf.Scan() {
		for _, ch := range buf.Text() {
			tmp, err := strconv.Atoi(string(ch))
			if err != nil {
				return nil, err
			}
			line = append(line, tmp)
		}
		ret = append(ret, line)
		line = []int{}
	}

	return ret, nil
}