import java.io.*;
import java.util.*;

public class Euler42 {

    private static class Options {
        String wordsFile = "resources/documents/0042_words.txt";
        boolean runCheckpoints = true;
    }

    private static boolean parseStringAfterPrefix(String arg, String prefix, StringBuilder value) {
        if (!arg.startsWith(prefix)) {
            return false;
        }
        String tail = arg.substring(prefix.length());
        if (tail.isEmpty()) {
            return false;
        }
        value.setLength(0);
        value.append(tail);
        return true;
    }

    private static boolean parseArguments(String[] args, Options options) {
        for (String arg : args) {
            if ("--skip-checkpoints".equals(arg)) {
                options.runCheckpoints = false;
                continue;
            }
            StringBuilder value = new StringBuilder();
            if (parseStringAfterPrefix(arg, "--words-file=", value)) {
                options.wordsFile = value.toString();
                continue;
            }
            System.err.println("Unknown argument: " + arg);
            return false;
        }
        return true;
    }

    private static List<String> parseCsvWords(String payload) {
        List<String> words = new ArrayList<>();
        StringBuilder current = new StringBuilder();
        boolean insideQuotes = false;

        for (char c : payload.toCharArray()) {
            if (c == '"') {
                insideQuotes = !insideQuotes;
                if (!insideQuotes) {
                    words.add(current.toString());
                    current.setLength(0);
                }
                continue;
            }
            if (insideQuotes) {
                current.append(c);
            }
        }

        return words;
    }

    private static int wordValue(String word) {
        int value = 0;
        for (char c : word.toCharArray()) {
            if (c >= 'A' && c <= 'Z') {
                value += c - 'A' + 1;
            }
        }
        return value;
    }

    private static Set<Integer> triangleSetUpTo(int limit) {
        Set<Integer> triangles = new HashSet<>();
        for (int n = 1; ; ++n) {
            int t = n * (n + 1) / 2;
            if (t > limit) {
                break;
            }
            triangles.add(t);
        }
        return triangles;
    }

    private static int solve(String wordsFile) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(wordsFile));
        StringBuilder buf = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            buf.append(line);
        }
        reader.close();

        List<String> words = parseCsvWords(buf.toString());

        int maxWordValue = 0;
        for (String w : words) {
            maxWordValue = Math.max(maxWordValue, wordValue(w));
        }

        Set<Integer> triangles = triangleSetUpTo(maxWordValue);

        int count = 0;
        for (String w : words) {
            if (triangles.contains(wordValue(w))) {
                ++count;
            }
        }

        return count;
    }

    private static boolean runCheckpoints() {
        if (wordValue("SKY") != 55) {
            System.err.println("Checkpoint failed for SKY value");
            return false;
        }
        Set<Integer> triangles = triangleSetUpTo(100);
        if (!triangles.contains(55) || triangles.contains(54)) {
            System.err.println("Checkpoint failed for triangle-number set");
            return false;
        }
        return true;
    }

    public static void main(String[] args) {
        Options options = new Options();
        if (!parseArguments(args, options)) {
            System.exit(1);
        }
        if (options.runCheckpoints && !runCheckpoints()) {
            System.exit(2);
        }

        try {
            System.out.println(solve(options.wordsFile));
        } catch (Exception ex) {
            System.err.println(ex.getMessage());
            System.exit(3);
        }
    }
}
