Cathode-Ray Tube

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

open System.IO

type Signal =
    | AddX of int
    | NoOp

    static member parse(s: string) : Signal =
        let parts = s.Split ' '
        let operation = parts[0]

        match operation with
        | "noop" -> NoOp
        | "addx" -> AddX(parts[1] |> int)
        | x -> failwith $"Invalid option {x}"

type Device() =
    let mutable registerX = 1
    let mutable cycle = 0
    let mutable strength = 0
    let mutable screen = Array2D.create 6 40 '.'

    let checkStrength () =
        if ((cycle - 20) % 40 = 0) then
            strength <- strength + (cycle * registerX)

    let draw () =
        if cycle < 240 then
            let line = cycle / 40
            let position = cycle % 40

            if (position = registerX - 1 || position = registerX || position = registerX + 1) then
                screen[line, position] <- '#'

    let drawCycle () =
        draw ()
        cycle <- cycle + 1
        checkStrength ()

    member _.Process(signal: Signal) =
        match signal with
        | NoOp -> drawCycle ()
        | AddX x ->
            drawCycle ()
            drawCycle ()
            registerX <- registerX + x

    member _.Display() =
        for i in 0..5 do
            for j in 0..39 do
                printf "%c" screen.[i, j]

            printfn ""

    member _.Result() = strength

type Input() =

    member _.Compute() =
        use stream = new StreamReader "./input.txt"
        let mutable endOfFile = false

        let device = new Device()

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

            if (line = null) then
                endOfFile <- true
            else
                Signal.parse line |> device.Process

        device.Display()
        device.Result()

let input = Input()

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