diff options
Diffstat (limited to 'aoc2023/build/packages/adglent/src/priv')
9 files changed, 315 insertions, 0 deletions
diff --git a/aoc2023/build/packages/adglent/src/priv/aoc_client.gleam b/aoc2023/build/packages/adglent/src/priv/aoc_client.gleam new file mode 100644 index 0000000..e18bafa --- /dev/null +++ b/aoc2023/build/packages/adglent/src/priv/aoc_client.gleam @@ -0,0 +1,37 @@ +import gleam/result.{try} +import gleam/httpc +import gleam/http/request +import gleam/int +import gleam/string + +pub fn get_input( + year: String, + day: String, + session: String, +) -> Result(String, String) { + let url = "https://adventofcode.com/" <> year <> "/day/" <> day <> "/input" + use request <- try( + request.to(url) + |> result.map_error(fn(error) { + "Could not create request for \"" <> url <> "\": " <> string.inspect( + error, + ) + }), + ) + + // Send the HTTP request to the server + use response <- try( + request + |> request.prepend_header("Accept", "application/json") + |> request.prepend_header("Cookie", "session=" <> session <> ";") + |> httpc.send + |> result.map_error(fn(error) { + "Error when requesting \"" <> url <> "\": " <> string.inspect(error) + }), + ) + + case response.status { + status if status >= 200 && status < 300 -> Ok(response.body) + status -> Error(int.to_string(status) <> " - " <> response.body) + } +} diff --git a/aoc2023/build/packages/adglent/src/priv/errors.gleam b/aoc2023/build/packages/adglent/src/priv/errors.gleam new file mode 100644 index 0000000..14c35ca --- /dev/null +++ b/aoc2023/build/packages/adglent/src/priv/errors.gleam @@ -0,0 +1,54 @@ +import gleam/result +import gleam/string +import gleam/io + +pub fn map_messages( + result: Result(a, b), + success_message: String, + error_message: String, +) -> Result(String, String) { + result + |> result.map_error(fn(error) { + "Error - " <> error_message <> ": " <> string.inspect(error) + }) + |> result.replace(success_message) +} + +pub fn map_error( + result: Result(a, b), + error_message: String, +) -> Result(a, String) { + result + |> result.map_error(fn(error) { + error_message <> ": " <> string.inspect(error) + }) +} + +pub fn print_result(result: Result(String, String)) { + result + |> result.unwrap_both + |> io.println + result +} + +pub fn print_error(result: Result(a, String)) { + result + |> result.map_error(fn(err) { + io.println(err) + err + }) +} + +pub fn assert_ok(result: Result(a, String)) { + let assert Ok(value) = + result + |> result.map_error(fn(err) { + halt(1) + err + }) + value +} + +@target(erlang) +@external(erlang, "erlang", "halt") +fn halt(a: Int) -> Nil diff --git a/aoc2023/build/packages/adglent/src/priv/prompt.gleam b/aoc2023/build/packages/adglent/src/priv/prompt.gleam new file mode 100644 index 0000000..6cee35a --- /dev/null +++ b/aoc2023/build/packages/adglent/src/priv/prompt.gleam @@ -0,0 +1,38 @@ +import gleam/result +import gleam/string + +pub fn confirm(message: String, auto_accept: Bool) -> Bool { + auto_accept || case + get_line(message <> "? (Y/N): ") + |> result.unwrap("n") + |> string.trim() + { + "Y" | "y" -> True + _ -> False + } +} + +pub fn value(message: String, default: String, auto_accept: Bool) -> String { + case get_value_of_default(message, default, auto_accept) { + "" -> default + value -> value + } +} + +fn get_value_of_default(message: String, default: String, auto_accept: Bool) { + case auto_accept { + True -> default + False -> + get_line(message <> "? (" <> default <> "): ") + |> result.unwrap("") + |> string.trim() + } +} + +pub type GetLineError { + Eof + NoData +} + +@external(erlang, "adglent_ffi", "get_line") +pub fn get_line(prompt prompt: String) -> Result(String, GetLineError) diff --git a/aoc2023/build/packages/adglent/src/priv/template.gleam b/aoc2023/build/packages/adglent/src/priv/template.gleam new file mode 100644 index 0000000..e946888 --- /dev/null +++ b/aoc2023/build/packages/adglent/src/priv/template.gleam @@ -0,0 +1,18 @@ +import gleam/list +import gleam/string + +pub fn render( + template: String, + substitutions: List(#(String, String)), +) -> String { + substitutions + |> list.fold( + template, + fn(template, substitution) { + let #(name, value) = substitution + template + |> string.replace("{{ " <> name <> " }}", value) + }, + ) + |> string.trim <> "\n" +} diff --git a/aoc2023/build/packages/adglent/src/priv/templates/solution.gleam b/aoc2023/build/packages/adglent/src/priv/templates/solution.gleam new file mode 100644 index 0000000..96085c3 --- /dev/null +++ b/aoc2023/build/packages/adglent/src/priv/templates/solution.gleam @@ -0,0 +1,27 @@ +pub const template = " +import adglent.{First, Second} +import gleam/io + +pub fn part1(input: String) { + todo as \"Implement solution to part 1\" +} + +pub fn part2(input: String) { + todo as \"Implement solution to part 2\" +} + +pub fn main() { + let assert Ok(part) = adglent.get_part() + let assert Ok(input) = adglent.get_input(\"{{ day }}\") + case part { + First -> + part1(input) + |> adglent.inspect + |> io.println + Second -> + part2(input) + |> adglent.inspect + |> io.println + } +} +" diff --git a/aoc2023/build/packages/adglent/src/priv/templates/test_main.gleam b/aoc2023/build/packages/adglent/src/priv/templates/test_main.gleam new file mode 100644 index 0000000..27548d3 --- /dev/null +++ b/aoc2023/build/packages/adglent/src/priv/templates/test_main.gleam @@ -0,0 +1,7 @@ +pub const template = " +import showtime + +pub fn main() { + showtime.main() +} +" diff --git a/aoc2023/build/packages/adglent/src/priv/templates/testfile_gleeunit.gleam b/aoc2023/build/packages/adglent/src/priv/templates/testfile_gleeunit.gleam new file mode 100644 index 0000000..a1d56f6 --- /dev/null +++ b/aoc2023/build/packages/adglent/src/priv/templates/testfile_gleeunit.gleam @@ -0,0 +1,41 @@ +pub const template = " +import gleam/list +import gleeunit/should +import adglent.{type Example, Example} +import day{{ day }}/solve + +type Problem1AnswerType = + String + +type Problem2AnswerType = + String + +/// Add examples for part 1 here: +/// ```gleam +///const part1_examples: List(Example(Problem1AnswerType)) = [Example(\"some input\", \"\")] +/// ``` +const part1_examples: List(Example(Problem1AnswerType)) = [] + +/// Add examples for part 2 here: +/// ```gleam +///const part2_examples: List(Example(Problem2AnswerType)) = [Example(\"some input\", \"\")] +/// ``` +const part2_examples: List(Example(Problem2AnswerType)) = [] + +pub fn part1_test() { + part1_examples + |> should.not_equal([]) + use example <- list.map(part1_examples) + solve.part1(example.input) + |> should.equal(example.answer) +} + +pub fn part2_test() { + part2_examples + |> should.not_equal([]) + use example <- list.map(part2_examples) + solve.part2(example.input) + |> should.equal(example.answer) +} + +" diff --git a/aoc2023/build/packages/adglent/src/priv/templates/testfile_showtime.gleam b/aoc2023/build/packages/adglent/src/priv/templates/testfile_showtime.gleam new file mode 100644 index 0000000..699feb2 --- /dev/null +++ b/aoc2023/build/packages/adglent/src/priv/templates/testfile_showtime.gleam @@ -0,0 +1,41 @@ +pub const template = " +import gleam/list +import showtime/tests/should +import adglent.{type Example, Example} +import day{{ day }}/solve + +type Problem1AnswerType = + String + +type Problem2AnswerType = + String + +/// Add examples for part 1 here: +/// ```gleam +///const part1_examples: List(Example(Problem1AnswerType)) = [Example(\"some input\", \"\")] +/// ``` +const part1_examples: List(Example(Problem1AnswerType)) = [] + +/// Add examples for part 2 here: +/// ```gleam +///const part2_examples: List(Example(Problem2AnswerType)) = [Example(\"some input\", \"\")] +/// ``` +const part2_examples: List(Example(Problem2AnswerType)) = [] + +pub fn part1_test() { + part1_examples + |> should.not_equal([]) + use example <- list.map(part1_examples) + solve.part1(example.input) + |> should.equal(example.answer) +} + +pub fn part2_test() { + part2_examples + |> should.not_equal([]) + use example <- list.map(part2_examples) + solve.part2(example.input) + |> should.equal(example.answer) +} + +" diff --git a/aoc2023/build/packages/adglent/src/priv/toml.gleam b/aoc2023/build/packages/adglent/src/priv/toml.gleam new file mode 100644 index 0000000..7042833 --- /dev/null +++ b/aoc2023/build/packages/adglent/src/priv/toml.gleam @@ -0,0 +1,52 @@ +import tom +import gleam/result + +pub type TomError { + TomParseError(error: tom.ParseError) + TomGetError(error: tom.GetError) +} + +pub fn get_string( + toml_content: String, + key_path: List(String), +) -> Result(String, TomError) { + use toml <- result.try( + tom.parse(toml_content <> "\n") + |> result.map_error(TomParseError), + ) + use value <- result.try( + tom.get_string(toml, key_path) + |> result.map_error(TomGetError), + ) + Ok(value) +} + +pub fn get_bool( + toml_content: String, + key_path: List(String), +) -> Result(Bool, TomError) { + use toml <- result.try( + tom.parse(toml_content <> "\n") + |> result.map_error(TomParseError), + ) + use value <- result.try( + tom.get_bool(toml, key_path) + |> result.map_error(TomGetError), + ) + Ok(value) +} + +pub fn get_int( + toml_content: String, + key_path: List(String), +) -> Result(Int, TomError) { + use toml <- result.try( + tom.parse(toml_content <> "\n") + |> result.map_error(TomParseError), + ) + use value <- result.try( + tom.get_int(toml, key_path) + |> result.map_error(TomGetError), + ) + Ok(value) +} |