import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

class Euler67 {

    private static class Options {
        String file = "resources/documents/0067_triangle.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, "--file=", value)) {
                options.file = value.toString();
                continue;
            }
            System.err.println("Unknown argument: " + arg);
            return false;
        }
        return true;
    }

    private static List<List<Integer>> parseTriangle(String text) {
        List<List<Integer>> triangle = new ArrayList<>();
        String[] lines = text.split("\n");

        for (String line : lines) {
            line = line.trim();
            if (line.isEmpty()) {
                continue;
            }
            String[] tokens = line.split("\\s+");
            List<Integer> row = new ArrayList<>();
            for (String token : tokens) {
                row.add(Integer.parseInt(token));
            }
            if (!row.isEmpty()) {
                triangle.add(row);
            }
        }
        return triangle;
    }

    private static int maxPathSum(List<List<Integer>> triangle) {
        if (triangle.isEmpty()) {
            return 0;
        }

        for (int row = triangle.size() - 2; row >= 0; row--) {
            for (int col = 0; col <= row; col++) {
                int currentValue = triangle.get(row).get(col);
                int leftChild = triangle.get(row + 1).get(col);
                int rightChild = triangle.get(row + 1).get(col + 1);
                triangle.get(row).set(col, currentValue + Math.max(leftChild, rightChild));
            }
        }

        return triangle.get(0).get(0);
    }

    private static int solve(String filePath) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(filePath));
        StringBuilder buffer = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            buffer.append(line).append("\n");
        }
        reader.close();
        return maxPathSum(parseTriangle(buffer.toString()));
    }

    private static boolean runCheckpoints() {
        String sample = "3\n7 4\n2 4 6\n8 5 9 3\n";
        if (maxPathSum(parseTriangle(sample)) != 23) {
            System.err.println("Checkpoint failed for sample triangle");
            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.file));
        } catch (Exception ex) {
            System.err.println(ex.getMessage());
            System.exit(3);
        }
    }
}
