const ROCK = 0;
const PAPER = 1;
const SCISSORS = 2;

const LOOSE = 0;
const DRAW = 1;
const WIN = 2;

const sum = (array) => array.reduce((prev, curr) => prev + curr);

const modulo = (n, d) => ((n % d) + d) % d;

const scoreForShape = (round) => {
    return round.me + 1;
}

const scoreForResult = (round) => {
    const pointDiff = modulo(round.opponent - round.me, 3);
    return {
        0: 3, // tie
        1: 0, // loose
        2: 6 // win
    }[pointDiff]
};

const decodeShapeSymbol = (symbol) => {
    return {
        A: ROCK,
        B: PAPER,
        C: SCISSORS,
        X: ROCK,
        Y: PAPER,
        Z: SCISSORS
    }[symbol];
}

const decodeGuideSymbol = (symbol) => {
    return {
        X: LOOSE,
        Y: DRAW,
        Z: WIN
    }[symbol]
}

const getShapeForGuide = (opponent, guideHint) => {
    return modulo(guideHint - 1 + opponent, 3);
};

// parse first part into {opponent, me} shapes
const parseHandsPerRound = (inputString) => {
    const rounds = inputString.split('\n');
    return rounds.map(p => {
        const shapes = p.split(' ');
        return {
            opponent: decodeShapeSymbol(shapes[0]),
            me: decodeShapeSymbol(shapes[1])
        }
    })
};

// parse second part into {opponent, me} shapes
const parseHandGuidePerRound = (inputString) => {
    const rounds = inputString.split('\n');
    return rounds.map(p => {
        const shapes = p.split(' ');
        const opponent = decodeShapeSymbol(shapes[0]);
        const guideHint = decodeGuideSymbol(shapes[1]);
        return {
            opponent,
            me: getShapeForGuide(opponent, guideHint)
        }
    })
};

const mainDayTwoA = (inputString) => {
    const rounds = parseHandsPerRound(inputString);
    const scores = rounds.map(round => {
        return scoreForShape(round) + scoreForResult(round)
    })
    return sum(scores);
}

const mainDayTwoB = (inputString) => {
    const rounds = parseHandGuidePerRound(inputString);
    const scores = rounds.map(round => {
        return scoreForShape(round) + scoreForResult(round)
    })
    return sum(scores);
}