#!/usr/bin/env node

const fs = require('fs');
const path = require('path');

let contents = fs.readFileSync(
    path.basename(__filename, ".js") + ".txt", 'utf8')
    .trim();

function Forest(mapString) {
    this.map = mapString.split("\n").map(l => l.split(""));
    this.height = this.map.length;
    this.width = this.map[0].length;
}

Forest.prototype.getSurrounding = function (oy, ox) {
    let surrounding = {};
    for (let y = oy - 1; y <= oy + 1; y++) {
        for (let x = ox - 1; x <= ox + 1; x++) {
            if (y == oy && x == ox)
                continue;

            if (this.map[y] != null) {
                const symbol = this.map[y][x];
                if (symbol != null)
                    surrounding[symbol] = (surrounding[symbol] || 0) + 1;
            }
        }
    }
    return surrounding;
}

Forest.prototype.spendMinute = function() {
    let newMap = new Array(this.height).fill(0).map(() => new Array(this.width));

    for (let y = 0; y < this.height; y++) {
        for (let x = 0; x < this.width; x++) {
            let acreContent = this.map[y][x];
            let surrounding = this.getSurrounding(y, x);

            switch (acreContent) {
                case '.':
                    if (surrounding['|'] >= 3)
                        acreContent = '|';
                    break;
                case '|':
                    if (surrounding['#'] >= 3)
                        acreContent = '#';
                    break;
                case '#':
                    if (!(surrounding['#'] >= 1 && surrounding['|'] >= 1))
                        acreContent = '.';
                    break;
            }
            newMap[y][x] = acreContent;
        }
    }
    this.map = newMap;
}

Forest.prototype.toString = function() {
    return this.map.map(a => a.join("")).join("\n");
}

Forest.prototype.value = function() {
    let wooded = 0, lumberyards = 0;

    for (let y = 0; y < this.height; y++)
        for (let x = 0; x < this.width; x++) {
            const s = this.map[y][x];
            if (s === '|')
                wooded++;
            else if (s === '#')
                lumberyards++;
        }

    return wooded * lumberyards;
}

let forest = new Forest(contents);
//console.log(forest.toString(), "\n");

let i;
for (i = 0; i < 10; i++)
    forest.spendMinute();
// console.log(forest.toString(), "\n");
console.log("Part One:", forest.value());

let states = []
let cycle;
let partTwoTarget = 1000000000;
for (; i < partTwoTarget; i++) {
    forest.spendMinute();
    let fs = forest.toString();
    let sameState = states.indexOf(fs);

    if (cycle === undefined && sameState != -1) {
        delete states;
        cycle = i - sameState;
        i = (i + cycle * Math.floor((partTwoTarget - 1 - i) / cycle))
    } else 
        states[i] = fs;
}

console.log("Part Two:", forest.value());