{ pkgs ? import <nixpkgs> { } }:
with builtins;
let
inherit (pkgs) lib;
input = builtins.readFile ./input;
leftCipher = { "A" = "Rock"; "B" = "Paper"; "C" = "Scissors"; };
winConditions = { "Rock" = "Scissors"; "Scissors" = "Paper"; "Paper" = "Rock"; };
loseConditions = builtins.listToAttrs (map (pair: lib.nameValuePair pair.value pair.name) (lib.attrsToList winConditions));
determineScore = game:
let
shapeScore = { "Rock" = 1; "Paper" = 2; "Scissors" = 3; };
outcomeScore = { "L" = 0; "D" = 3; "W" = 6; };
gameOutcome = if winConditions.${elemAt game 0} == elemAt game 1 then "W" else if elemAt game 0 == elemAt game 1 then "D" else "L";
in
outcomeScore.${gameOutcome} + shapeScore.${elemAt game 0};
splitAndDecipher = x:
let
rightCipher = { "X" = "Rock"; "Y" = "Paper"; "Z" = "Scissors"; };
split = lib.splitString " " x;
us = rightCipher.${elemAt split 1};
them = leftCipher.${elemAt split 0};
in
[ us them ];
splitAndMapToResult = x:
let
split = lib.splitString " " x;
them = leftCipher.${elemAt split 0};
desiredOutcome = elemAt split 1;
us = if desiredOutcome == "X" then winConditions.${them} else if desiredOutcome == "Z" then loseConditions.${them} else them;
in
[ us them ];
games = lib.splitString "\n" input;
playGame = f: lib.foldl (x: y: x + y) 0 (map determineScore (map f games));
part1 = playGame splitAndDecipher;
part2 = playGame splitAndMapToResult;
out = builtins.toJSON { inherit part1; inherit part2; };
in
pkgs.writeText "out" out