Add Elm day 2

main
Bram 2023-12-28 12:05:45 +01:00
parent 2cf9264509
commit edcc3caf91
7 changed files with 1227 additions and 108 deletions

View File

@ -11,6 +11,7 @@
"elm/browser": "1.0.2", "elm/browser": "1.0.2",
"elm/core": "1.0.5", "elm/core": "1.0.5",
"elm/html": "1.0.0", "elm/html": "1.0.0",
"elm/parser": "1.1.0",
"elm/svg": "1.0.1", "elm/svg": "1.0.1",
"mdgriffith/elm-ui": "1.1.8", "mdgriffith/elm-ui": "1.1.8",
"miniBill/elm-fast-dict": "1.1.0" "miniBill/elm-fast-dict": "1.1.0"

File diff suppressed because it is too large Load Diff

View File

@ -2,16 +2,16 @@ module Main exposing (main)
import Browser import Browser
import Element import Element
import Tools.Colors as C
import Widget
import Widget.Material as Material
import Widget.Material.Typography as Typography
import Element.Background import Element.Background
import Element.Input import Element.Input
import Task
import Puzzles.Day1 as Day1 import Puzzles.Day1 as Day1
import Puzzles.Day2 as Day2
import Task
import Tools.Colors as C
import Widget
import Widget.Customize import Widget.Customize
import Widget.Material as Material
import Widget.Material.Typography as Typography
main : Program () Model Msg main : Program () Model Msg
@ -31,17 +31,22 @@ type alias Model =
, output2 : Calculating , output2 : Calculating
} }
type Calculating type Calculating
= Outcome String = Outcome String
| Calculating | Calculating
| InvalidInput String | InvalidInput String
| NoInput | NoInput
type Window type Window
= Home = Home
| Day Int | Day Int
type alias Puzzle = String -> Result String String
type alias Puzzle =
String -> Result String String
getFunctions : Window -> ( Puzzle, Puzzle ) getFunctions : Window -> ( Puzzle, Puzzle )
getFunctions window = getFunctions window =
@ -50,15 +55,19 @@ getFunctions window =
( always <| Err "There is no puzzle for this page!" ( always <| Err "There is no puzzle for this page!"
, always <| Err "There is no puzzle for this page!" , always <| Err "There is no puzzle for this page!"
) )
Day 1 -> Day 1 ->
( Day1.puzzle1, Day1.puzzle2 ) ( Day1.puzzle1, Day1.puzzle2 )
Day 2 ->
( Day2.puzzle1, Day2.puzzle2 )
_ -> _ ->
( always <| Err "This puzzle has no implementation yet!" ( always <| Err "This puzzle has no implementation yet!"
, always <| Err "This puzzle has no implementation yet!" , always <| Err "This puzzle has no implementation yet!"
) )
init : () -> ( Model, Cmd Msg ) init : () -> ( Model, Cmd Msg )
init () = init () =
( { view = Home ( { view = Home
@ -89,16 +98,17 @@ update msg model =
} }
, Cmd.none , Cmd.none
) )
OnInput input -> OnInput input ->
( { model ( { model
| input = input | input = input
, output1 = Calculating , output1 = Calculating
, output2 = Calculating , output2 = Calculating
} }
, if input == model.input then , if input == model.input then
Cmd.none Cmd.none
else
else
Cmd.batch Cmd.batch
[ Task.succeed input [ Task.succeed input
|> Task.map (getFunctions model.view |> Tuple.first) |> Task.map (getFunctions model.view |> Tuple.first)
@ -108,48 +118,47 @@ update msg model =
|> Task.perform (Calculate2 model.view) |> Task.perform (Calculate2 model.view)
] ]
) )
DoNothing -> DoNothing ->
( model, Cmd.none ) ( model, Cmd.none )
Calculate1 w (Ok s) -> Calculate1 w (Ok s) ->
if w /= model.view then if w /= model.view then
( model, Cmd.none ) ( model, Cmd.none )
else else
( { model | output1 = Outcome s } ( { model | output1 = Outcome s }
, Cmd.none , Cmd.none
) )
Calculate1 w (Err s) -> Calculate1 w (Err s) ->
if w /= model.view then if w /= model.view then
( model, Cmd.none ) ( model, Cmd.none )
else else
( { model | output1 = InvalidInput s } ( { model | output1 = InvalidInput s }
, Cmd.none , Cmd.none
) )
Calculate2 w (Ok s) -> Calculate2 w (Ok s) ->
if w /= model.view then if w /= model.view then
( model, Cmd.none ) ( model, Cmd.none )
else else
( { model | output2 = Outcome s } ( { model | output2 = Outcome s }
, Cmd.none , Cmd.none
) )
Calculate2 w (Err s) -> Calculate2 w (Err s) ->
if w /= model.view then if w /= model.view then
( model, Cmd.none ) ( model, Cmd.none )
else else
( { model | output2 = InvalidInput s } ( { model | output2 = InvalidInput s }
, Cmd.none , Cmd.none
) )
subscriptions : Model -> Sub Msg subscriptions : Model -> Sub Msg
subscriptions model = subscriptions model =
Sub.none Sub.none
@ -160,7 +169,7 @@ view model =
{ title = "Document Title" { title = "Document Title"
, body = , body =
[ Widget.menuBar [ Widget.menuBar
( Material.menuBar palette ) (Material.menuBar palette)
{ title = { title =
"aoc2023" "aoc2023"
|> Element.text |> Element.text
@ -180,10 +189,10 @@ view model =
|> Element.width |> Element.width
, Element.alignTop , Element.alignTop
] ]
( List.map (List.map
(\(window, text) -> (\( window, text ) ->
Widget.fullBleedItem Widget.fullBleedItem
( Material.fullBleedItem palette ) (Material.fullBleedItem palette)
{ text = text { text = text
, onPress = Just (ChangeWindow window) , onPress = Just (ChangeWindow window)
, icon = always Element.none , icon = always Element.none
@ -203,32 +212,34 @@ view model =
, Element.padding 20 , Element.padding 20
, Element.spacing 20 , Element.spacing 20
] ]
( case model.view of (case model.view of
Home -> Home ->
[ "Advent of Code 2023" [ "Advent of Code 2023"
|> Element.text |> Element.text
|> Element.el Typography.h3 |> Element.el Typography.h3
] ]
Day i -> Day i ->
[ [ "Using the following input for day " ++ String.fromInt i ++ ": " [ [ "Using the following input for day "
|> Element.text ++ String.fromInt i
++ ": "
|> Element.text
, Element.Input.multiline , Element.Input.multiline
[ Element.fill [ Element.fill
|> Element.maximum 500 |> Element.maximum 500
|> Element.height |> Element.height
, Element.scrollbarX , Element.scrollbarX
] ]
{ onChange = OnInput { onChange = OnInput
, text = model.input , text = model.input
, placeholder = , placeholder =
"Insert puzzle input here..." "Insert puzzle input here..."
|> Element.text |> Element.text
|> Element.Input.placeholder [] |> Element.Input.placeholder []
|> Just |> Just
, label = Element.Input.labelHidden "input" , label = Element.Input.labelHidden "input"
, spellcheck = False , spellcheck = False
} }
] ]
, case model.output1 of , case model.output1 of
Outcome s -> Outcome s ->
@ -243,12 +254,12 @@ view model =
, spellcheck = False , spellcheck = False
} }
] ]
Calculating -> Calculating ->
[ "Calculating part 1..." [ "Calculating part 1..."
|> Element.text |> Element.text
] ]
InvalidInput s -> InvalidInput s ->
[ "INVALID INPUT FOR PART 1" [ "INVALID INPUT FOR PART 1"
|> Element.text |> Element.text
@ -261,7 +272,7 @@ view model =
, spellcheck = False , spellcheck = False
} }
] ]
NoInput -> NoInput ->
List.singleton Element.none List.singleton Element.none
, case model.output2 of , case model.output2 of
@ -277,12 +288,12 @@ view model =
, spellcheck = False , spellcheck = False
} }
] ]
Calculating -> Calculating ->
[ "Calculating part 2..." [ "Calculating part 2..."
|> Element.text |> Element.text
] ]
InvalidInput s -> InvalidInput s ->
[ "INVALID INPUT FOR PART 2" [ "INVALID INPUT FOR PART 2"
|> Element.text |> Element.text
@ -295,7 +306,7 @@ view model =
, spellcheck = False , spellcheck = False
} }
] ]
NoInput -> NoInput ->
List.singleton Element.none List.singleton Element.none
] ]
@ -308,10 +319,12 @@ view model =
|> List.singleton |> List.singleton
} }
picker : C.Picker picker : C.Picker
picker = picker =
C.get C.Trichromatic C.LightMode C.get C.Trichromatic C.LightMode
palette : Material.Palette palette : Material.Palette
palette = palette =
C.defaultPalette picker C.defaultPalette picker

View File

@ -1,5 +1,6 @@
module Puzzles.Day1 exposing (puzzle1, puzzle2) module Puzzles.Day1 exposing (puzzle1, puzzle2)
puzzle1 : String -> Result String String puzzle1 : String -> Result String String
puzzle1 input = puzzle1 input =
input input
@ -10,25 +11,25 @@ puzzle1 input =
case items of case items of
head :: tail -> head :: tail ->
Ok (calibrationValue head tail) Ok (calibrationValue head tail)
[] -> [] ->
Err i Err i
) )
|> List.foldl |> List.foldl
(\value sum -> (\value sum ->
case (value, sum) of case ( value, sum ) of
(_, Err _) -> ( _, Err _ ) ->
sum sum
(Err i, Ok _) -> ( Err i, Ok _ ) ->
Err ("Line" ++ (String.fromInt <| i + 1) ++ "does not contain any numbers") Err ("Line" ++ (String.fromInt <| i + 1) ++ "does not contain any numbers")
(Ok a, Ok b) -> ( Ok a, Ok b ) ->
Ok (a + b) Ok (a + b)
) )
(Ok 0) (Ok 0)
|> Result.map String.fromInt |> Result.map String.fromInt
puzzle1Nums : String -> List Int puzzle1Nums : String -> List Int
puzzle1Nums s = puzzle1Nums s =
@ -37,13 +38,15 @@ puzzle1Nums s =
|> List.map String.fromChar |> List.map String.fromChar
|> List.filterMap String.toInt |> List.filterMap String.toInt
calibrationValue : Int -> List Int -> Int calibrationValue : Int -> List Int -> Int
calibrationValue head tail = calibrationValue head tail =
tail tail
|> List.reverse |> List.reverse
|> List.head |> List.head
|> Maybe.withDefault head |> Maybe.withDefault head
|> (+) ( head * 10 ) |> (+) (head * 10)
puzzle2 : String -> Result String String puzzle2 : String -> Result String String
puzzle2 input = puzzle2 input =

150
elm/src/Puzzles/Day2.elm Normal file
View File

@ -0,0 +1,150 @@
module Puzzles.Day2 exposing (puzzle1, puzzle2)
import Parser as P exposing ((|.), (|=), Parser)
type alias Game =
{ number : Int, games : List RGB }
type alias RGB =
{ red : Int, green : Int, blue : Int }
maxAllowed : RGB
maxAllowed =
{ red = 12, green = 13, blue = 14 }
puzzle1 : String -> Result String String
puzzle1 input =
case P.run parser input of
Err a ->
Debug.log "Output" a
|> always (Err "Invalid input")
Ok g ->
g
|> List.map
(\{ number, games } ->
let
isLegal : Bool
isLegal =
List.all
(\rgb ->
List.all
(\f -> f rgb <= f maxAllowed)
[ .red, .green, .blue ]
)
games
in
if isLegal then
number
else
0
)
|> List.sum
|> String.fromInt
|> Ok
puzzle2 : String -> Result String String
puzzle2 input =
case P.run parser input of
Err a ->
Debug.log "Output" a
|> always (Err "Invalid input")
-- 179502 too high
Ok g ->
g
|> List.map
(\{ games } ->
let
getMaximumFor : (RGB -> Int) -> Int
getMaximumFor f =
games
|> List.map f
|> List.maximum
|> Maybe.withDefault 0
in
[ .red, .green, .blue ]
|> List.map getMaximumFor
|> List.product
)
|> List.sum
|> String.fromInt
|> Ok
parser : Parser (List Game)
parser =
andOneMore
{ separator = "\n"
, item = gameParser
}
gameParser : Parser Game
gameParser =
P.succeed Game
|. P.keyword "Game"
|. P.spaces
|= P.int
|. P.symbol ":"
|. P.spaces
|= rgbLines
rgbLines : Parser (List RGB)
rgbLines =
andOneMore
{ separator = ";"
, item = rgbParser
}
rgbParser : Parser RGB
rgbParser =
P.succeed (List.foldl (<|) (RGB 0 0 0))
|= andOneMore
{ separator = ","
, item = rgbStmt
}
rgbStmt : Parser (RGB -> RGB)
rgbStmt =
P.succeed (|>)
|= P.int
|. P.spaces
|= P.oneOf
[ P.succeed (\i rgb -> { rgb | red = i })
|. P.keyword "red"
, P.succeed (\i rgb -> { rgb | blue = i })
|. P.keyword "blue"
, P.succeed (\i rgb -> { rgb | green = i })
|. P.keyword "green"
]
andOneMore : { separator : String, item : Parser a } -> Parser (List a)
andOneMore { separator, item } =
P.loop []
(\xs ->
P.succeed (\x state -> state (x :: xs))
|= item
|. onlySpaces
|= P.oneOf
[ P.succeed P.Loop
|. P.token separator
, P.succeed P.Done
]
|. onlySpaces
)
onlySpaces : Parser ()
onlySpaces =
P.chompWhile (\c -> c == ' ')

11
elm/src/Puzzles/DayX.elm Normal file
View File

@ -0,0 +1,11 @@
module Puzzles.DayX exposing (puzzle1, puzzle2)
puzzle1 : String -> Result String String
puzzle1 _ =
Err "Not implemented yet!"
puzzle2 : String -> Result String String
puzzle2 _ =
Err "Not implemented yet!"

View File

@ -409,6 +409,7 @@ transparent =
Color.rgba 0 0 0 0 Color.rgba 0 0 0 0
-- PRIMARY COLOR -- PRIMARY COLOR