package main

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

func main() {
	inp := []byte(StdinToString())
	fmt.Println("= Part 1 =")
	fmt.Println(part1(inp))
	fmt.Println("\n= Part 2 =")
	fmt.Println(part2(inp))
}

func part1(inp []byte) int {
	last := inp
	curr := react(last)
	for !bytes.Equal(last, curr) {
		last = curr
		curr = react(last)
	}
	return len(curr)
}

// useShortest will skip runs where there are fewer letters in the input than the current shortest...
// It reduced _my_ runtime by about 3 minutes, but may fail depending on your input
var useShortest bool

func part2(inp []byte) int {
	// If yours fails, try setting this to false
	useShortest = true
	shortest := len(inp)
	var shortestCount int
	var count int
	for i := 65; i <= 90; i++ {
		var try []byte
		if useShortest {
			count = countByte(inp, byte(i))
			if count < shortestCount {
				continue
			}
		}
		for j := range inp {
			if int(inp[j]) == i || int(inp[j]) == i+32 {
				continue
			}
			try = append(try, inp[j])
		}
		v := part1(try)
		if v < shortest {
			shortest = v
			shortestCount = count
		}
	}
	return shortest
}

func countByte(h []byte, n byte) int {
	var ret int
	for i := range h {
		if h[i] == n {
			ret++
		}
	}
	return ret
}

func react(v []byte) []byte {
	var ret []byte
	for i := 0; i < len(v); i++ {
		if i < len(v)-1 && sameDecase(v[i], v[i+1]) {
			i++
			continue
		}
		ret = append(ret, v[i])
	}
	return ret
}

func StdinToString() string {
	var input string
	scanner := bufio.NewScanner(os.Stdin)
	for scanner.Scan() {
		input += scanner.Text()
	}
	return input
}

func Atoi(i string) int {
	var ret int
	var err error
	if ret, err = strconv.Atoi(i); err != nil {
		log.Fatal("Invalid Atoi")
	}
	return ret
}

func sameDecase(val1, val2 byte) bool {
	return val1+32 == val2 || val2+32 == val1
}
