Rock Paper Scissors

Description: https://adventofcode.com/2022/day/2

open System.IO
open System

exception Error of string

type Shape =
    | Rock
    | Paper
    | Scissors

    member x.points: int =
        match x with
        | Rock -> 1
        | Paper -> 2
        | Scissors -> 3

    static member parse(s: string) : Shape =
        match s with
        | "A"
        | "X" -> Rock
        | "B"
        | "Y" -> Paper
        | "C"
        | "Z" -> Scissors
        | x -> raise (Error($"Invalid option {x}"))

type Result =
    | Lose
    | Draw
    | Win

    member x.points: int =
        match x with
        | Lose -> 0
        | Draw -> 3
        | Win -> 6

    static member parse(s: string) : Result =
        match s with
        | "X" -> Lose
        | "Y" -> Draw
        | "Z" -> Win
        | x -> raise (Error($"Invalid option {x}"))

type Input() =
    let getResult (oponent: Shape, me: Shape) : Result =
        match oponent, me with
        | Rock, Paper
        | Paper, Scissors
        | Scissors, Rock -> Win
        | Rock, Rock
        | Paper, Paper
        | Scissors, Scissors -> Draw
        | Rock, Scissors
        | Paper, Rock
        | Scissors, Paper -> Lose

    let getShape (oponent: Shape, result: Result) : Shape =
        match oponent, result with
        | Rock, Draw
        | Paper, Lose
        | Scissors, Win -> Rock
        | Rock, Lose
        | Paper, Win
        | Scissors, Draw -> Scissors
        | Rock, Win
        | Paper, Draw
        | Scissors, Lose -> Paper

    let computePart1 (oponent: Shape, me: string) : int =
        let shape = Shape.parse me

        (getResult (oponent, shape)).points + shape.points

    let computePart2 (oponent: Shape, result: string) : int =
        let result = Result.parse result

        (getShape (oponent, result)).points + result.points

    member _.Compute(part: int) =
        use stream = new StreamReader "./input.txt"

        let compute = if part = 1 then computePart1 else computePart2
        let mutable sum = 0
        let mutable endOfFile = false

        while (not endOfFile) do
            let line = stream.ReadLine()

            if (line = null) then
                endOfFile <- true
            else
                let (fst :: snd :: _) = line.Split() |> List.ofArray
                let oponent = Shape.parse (fst)

                sum <- sum + compute (oponent, snd)

        sum

let input = Input()
let part = (Environment.GetCommandLineArgs()[1]) |> int

printfn "%d" (input.Compute(part))