package main

import (
	"bufio"
	"fmt"
	"os"
)

const (
	MAX_INT = int(^uint(0) >> 1)
	MIN_INT = -MAX_INT - 1
)

var input []byte
var currRoom *Room
var facility *Facility
var pathStack []Room

func main() {
	input = stdinToByteSlice()
	input = input[1 : len(input)-1] // Trim ^...$
	part1()
	part2()
}

func part1() {
	facility = NewFacility()
	currRoom = &Room{0, 0, 0}
	for _, v := range input {
		switch v {
		case 'N':
			facility.move(0, -1)
		case 'E':
			facility.move(1, 0)
		case 'S':
			facility.move(0, 1)
		case 'W':
			facility.move(-1, 0)
		case '(':
			pathStack = append(pathStack, *currRoom)
		case ')':
			currRoom, pathStack = &pathStack[len(pathStack)-1], pathStack[:len(pathStack)-1]
		case '|':
			currRoom = &pathStack[len(pathStack)-1]
		}
	}
	var longest int
	for _, v := range facility.rooms {
		if v.dist > longest {
			longest = v.dist
		}
	}
	fmt.Println("= Part 1 =")
	fmt.Println(longest)
}

func part2() {
	var kilo int
	for _, v := range facility.rooms {
		if v.dist >= 1000 {
			kilo++
		}
	}
	fmt.Println("= Part 2 =")
	fmt.Println(kilo)
}

type Facility struct {
	minX, maxX int
	minY, maxY int
	rooms      map[string]*Room
}

func NewFacility() *Facility {
	f := Facility{
		minX:  MAX_INT,
		maxX:  MIN_INT,
		minY:  MAX_INT,
		maxY:  MIN_INT,
		rooms: make(map[string]*Room),
	}
	return &f
}

func (f *Facility) key(x, y int) string {
	return fmt.Sprintf("%d,%d", x, y)
}

func (f *Facility) move(xd, yd int) {
	n := f.getRoom(currRoom.x+xd, currRoom.y+yd)
	n.dist = min(n.dist, currRoom.dist+1)
	currRoom = n
	f.setRoom(n)
}

func (f *Facility) getRoom(x, y int) *Room {
	if v, ok := f.rooms[f.key(x, y)]; ok {
		return v
	}
	return &Room{x, y, MAX_INT}
}

func (f *Facility) setRoom(r *Room) {
	f.minX = min(f.minX, r.x)
	f.maxX = max(f.maxX, r.x)
	f.minY = min(f.minY, r.y)
	f.maxY = max(f.maxY, r.y)
	f.rooms[r.key()] = r
}

type Room struct {
	x, y int
	dist int
}

func (r *Room) key() string {
	return fmt.Sprintf("%d,%d", r.x, r.y)
}

func min(i, j int) int {
	if j < i {
		return j
	}
	return i
}

func max(i, j int) int {
	if j > i {
		return j
	}
	return i
}

func stdinToByteSlice() []byte {
	var ret []byte
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		data := scanner.Bytes()
		ret = append(input, data...)
	}
	return ret
}
