import gleam/int import gleam/result import gleam/string pub type RollVariant { Advantage Disadvantage Normal } pub type Dice { Dice(amount: Int, value: Int, variant: RollVariant) } pub type DiceError { InvalidAmount InvalidString InvalidValue } pub fn dice_from_string(string string: String) -> Result(Dice, DiceError) { use #(amount_string, value_string) <- result.try(split_dice(string)) use amount <- result.try(parse_amount(amount_string)) use #(value, variant) <- result.try(parse_value(value_string)) Ok(Dice(amount:, value:, variant:)) } fn parse_amount(amount: String) -> Result(Int, DiceError) { case amount { "" -> Ok(1) _ -> amount |> int.parse |> result.replace_error(InvalidAmount) } } fn parse_value(value: String) -> Result(#(Int, RollVariant), DiceError) { let variant = Normal let #(value, variant) = case value |> string.ends_with("kh") { True -> #(value |> string.drop_end(2), Advantage) False -> #(value, variant) } let #(value, variant) = case value |> string.ends_with("kl") { True -> #(value |> string.drop_end(2), Disadvantage) False -> #(value, variant) } case value |> int.parse { Ok(num) -> Ok(#(num, variant)) _ -> Error(InvalidValue) } } fn split_dice(string: String) -> Result(#(String, String), DiceError) { case string |> int.parse { Ok(_) -> Ok(#(string, string)) _ -> string |> string.split_once("d") |> result.replace_error(InvalidString) } }