From 2876b3b0f8be1afef31b70132dd9c666fb59e24c Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 25 Jan 2023 17:12:07 -0600 Subject: [PATCH 01/64] finish start here reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index c298c1f19..533202968 100644 --- a/progress.json +++ b/progress.json @@ -145,7 +145,7 @@ "task_drills_exercise": false, "monster_spawner_exercise": false, "metaprogramming_reading": false, - "start_here_reading": false, + "start_here_reading": true, "games_supervisor_setup_exercise": false, "pic_chat_pub_sub_reading": false, "lists_reading": false, From 6ba188603683f74cbd9486feb22db2f776c20e3e Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 25 Jan 2023 17:24:48 -0600 Subject: [PATCH 02/64] added code cell --- reading/start_here.livemd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reading/start_here.livemd b/reading/start_here.livemd index 6e4bfd8ae..91ef12af0 100644 --- a/reading/start_here.livemd +++ b/reading/start_here.livemd @@ -99,6 +99,10 @@ There is a **Commit Your Progress** and a **Mark as Completed** section at the e However, self-led students can complete these sections if they want to track their progress and get more practice using GitHub. We ask that you don't create pull requests to the DockYard Academy repo, as this spams our PR tracker. If you are not an academy student, we also ask that you refrain from @mentioning the instructor as this spams our notifications, and 1-1 feedback is only available to academy students. +```elixir +2 + 2 +``` + ## Mark As Completed From 0a2e73c32d0df5e0ea186a29ca1daadb7c44a06f Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 11:14:52 -0600 Subject: [PATCH 03/64] finish github engineering journal exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 533202968..3f4340c8a 100644 --- a/progress.json +++ b/progress.json @@ -61,7 +61,7 @@ "animal_generator_exercise": false, "group_project_blog_exercise": false, "treasure_matching_exercise": false, - "github_engineering_journal_exercise": false, + "github_engineering_journal_exercise": true, "mailbox_server_exercise": false, "blog_posts_exercise": false, "git_reading": false, From 8a8ff711085c55107dfc960607d9ccef5c2e1603 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 11:16:57 -0600 Subject: [PATCH 04/64] finish github collab exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 3f4340c8a..50d0a7115 100644 --- a/progress.json +++ b/progress.json @@ -83,7 +83,7 @@ "phoenix_1.7_reading": false, "pic_chat_messages_reading": false, "math_game_exercise": false, - "github_collab_exercise": false, + "github_collab_exercise": true, "web_servers_reading": false, "book_search_deployment_reading": false, "tic-tac-toe_exercise": false, From 75427677965af1969dd4d2c904481f43eb0e4957 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 12:41:30 -0600 Subject: [PATCH 05/64] finish rock paper scissors exercise --- exercises/rock_paper_scissors.livemd | 24 +++++++++++++++++++++++- progress.json | 6 +++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/exercises/rock_paper_scissors.livemd b/exercises/rock_paper_scissors.livemd index 0cfd2820c..7b8073b0d 100644 --- a/exercises/rock_paper_scissors.livemd +++ b/exercises/rock_paper_scissors.livemd @@ -54,7 +54,15 @@ Then, return the winning choice of either `:rock`, `:paper`, or `:scissors` that Enter your solution below. ```elixir +player_choice = Enum.random([:rock, :paper, :scissors]) + +IO.puts(player_choice) +case player_choice do + :rock -> :paper + :paper -> :scissors + :scissors -> :rock +end ``` ## Create Two Player Rock Paper Scissors @@ -107,7 +115,21 @@ Bind a `player1_choice` and `player2_choice` variable to `:rock`, `:paper`, or ` Enter your solution below. ```elixir - +player1 = Enum.random([:rock, :paper, :scissors]) +IO.inspect(player1: player1) + +player2 = Enum.random([:rock, :paper, :scissors]) +IO.inspect(player2: player2) + +case {player1, player2} do + {:rock, :scissors} -> "Player 1 Wins!" + {:paper, :rock} -> "Player 1 Wins!" + {:scissors, :paper} -> "Player 1 Wins!" + {:rock, :paper} -> "Player 2 Wins!" + {:paper, :scissors} -> "Player 2 Wins!" + {:scissors, :rock} -> "Player 2 Wins!" + {same, same} -> "Draw" +end ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 50d0a7115..7eb0218a4 100644 --- a/progress.json +++ b/progress.json @@ -61,7 +61,7 @@ "animal_generator_exercise": false, "group_project_blog_exercise": false, "treasure_matching_exercise": false, - "github_engineering_journal_exercise": true, + "github_engineering_journal_exercise": false, "mailbox_server_exercise": false, "blog_posts_exercise": false, "git_reading": false, @@ -83,7 +83,7 @@ "phoenix_1.7_reading": false, "pic_chat_messages_reading": false, "math_game_exercise": false, - "github_collab_exercise": true, + "github_collab_exercise": false, "web_servers_reading": false, "book_search_deployment_reading": false, "tic-tac-toe_exercise": false, @@ -105,7 +105,7 @@ "palindrome_exercise": false, "comprehensions_reading": false, "comments_reading": false, - "rock_paper_scissors_exercise": false, + "rock_paper_scissors_exercise": true, "book_search_seeding_reading": false, "concurrent_word_count_exercise": false, "regex_reading": false, From 34a0a160d796163145900dd42be31775fc45dabb Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 13:23:12 -0600 Subject: [PATCH 06/64] finish naming numbers exercise --- exercises/naming_numbers.livemd | 30 ++++++++++++++++++++++++++++++ progress.json | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/exercises/naming_numbers.livemd b/exercises/naming_numbers.livemd index df121b16f..24319112b 100644 --- a/exercises/naming_numbers.livemd +++ b/exercises/naming_numbers.livemd @@ -72,7 +72,22 @@ naming_numbers.(1) Enter your solution below. ```elixir +naming_numbers = fn integer -> + case integer do + 0 -> "zero" + 1 -> "one" + 2 -> "two" + 3 -> "three" + 4 -> "four" + 5 -> "five" + 6 -> "six" + 7 -> "seven" + 8 -> "eight" + 9 -> "nine" + end +end +naming_numbers.(1) ``` ## Numbering Names @@ -169,7 +184,22 @@ flowchart ```elixir +numbering_names = fn int_str -> + case String.downcase(int_str) do + "zero" -> 0 + "one" -> 1 + "two" -> 2 + "three" -> 3 + "four" -> 4 + "five" -> 5 + "six" -> 6 + "seven" -> 7 + "eight" -> 8 + "nine" -> 9 + end +end +numbering_names.("Nine") ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 7eb0218a4..b7d5bc682 100644 --- a/progress.json +++ b/progress.json @@ -126,7 +126,7 @@ "supervisor_and_genserver_drills_exercise": false, "computer_hardware_reading": false, "supervised_stack_exercise": false, - "naming_numbers_exercise": false, + "naming_numbers_exercise": true, "deployment_exercise": false, "typespecs_reading": false, "card_counting_exercise": false, From c9811638377aa23d7efb5a8a0427f8ba67911036 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 17:38:42 -0600 Subject: [PATCH 07/64] finish keyword lists reading --- progress.json | 22 +++++++++++----------- reading/keyword_lists.livemd | 10 ++++++---- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/progress.json b/progress.json index b7d5bc682..ec8e821cc 100644 --- a/progress.json +++ b/progress.json @@ -13,7 +13,7 @@ "agents_and_ets_reading": false, "protocols_reading": false, "games_score_tracker_exercise": false, - "habit_tracker_exercise": false, + "habit_tracker_exercise": true, "reduce_reading": false, "code_editors_reading": false, "exdoc_reading": false, @@ -64,14 +64,14 @@ "github_engineering_journal_exercise": false, "mailbox_server_exercise": false, "blog_posts_exercise": false, - "git_reading": false, + "git_reading": true, "named_number_lists_exercise": false, "big_o_notation_reading": false, "battle_map_exercise": false, "group_project_blog_presentation_exercise": false, "timer_exercise": false, "games_benchmarking_exercise": false, - "guessing_games_exercise": false, + "guessing_games_exercise": true, "sign_up_form_exercise": false, "enum_reading": false, "caesar_cypher_exercise": false, @@ -95,7 +95,7 @@ "liveview_reading": false, "process_mailbox_exercise": false, "io_reading": false, - "tuples_reading": false, + "tuples_reading": true, "ranges_reading": false, "task_reading": false, "executables_reading": false, @@ -105,7 +105,7 @@ "palindrome_exercise": false, "comprehensions_reading": false, "comments_reading": false, - "rock_paper_scissors_exercise": true, + "rock_paper_scissors_exercise": false, "book_search_seeding_reading": false, "concurrent_word_count_exercise": false, "regex_reading": false, @@ -119,17 +119,17 @@ "phone_number_parsing_exercise": false, "maps_reading": false, "exunit_reading": false, - "keyword_lists_reading": false, + "keyword_lists_reading": true, "command_line_reading": false, "stack_exercise": false, "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, "computer_hardware_reading": false, "supervised_stack_exercise": false, - "naming_numbers_exercise": true, + "naming_numbers_exercise": false, "deployment_exercise": false, "typespecs_reading": false, - "card_counting_exercise": false, + "card_counting_exercise": true, "math_with_protocols_exercise": false, "stack_server_exercise": false, "pokemon_battle_exercise": false, @@ -148,7 +148,7 @@ "start_here_reading": true, "games_supervisor_setup_exercise": false, "pic_chat_pub_sub_reading": false, - "lists_reading": false, + "lists_reading": true, "message_validation_exercise": false, "functions_reading": false, "spoonacular_recipe_api_exercise": false, @@ -158,7 +158,7 @@ "save_game_exercise": false, "document_tools_exercise": false, "factorial_exercise": false, - "livebook_reading": false, + "livebook_reading": true, "filter_values_by_type_exercise": false, "book_search_exercise": false, "guards_reading": false, @@ -205,5 +205,5 @@ "fibonacci_exercise": false, "typespec_drills_exercise": false, "custom_assertions_exercise": false, - "atoms_reading": false + "atoms_reading": true } \ No newline at end of file diff --git a/reading/keyword_lists.livemd b/reading/keyword_lists.livemd index b0d06161b..b8a3d435a 100644 --- a/reading/keyword_lists.livemd +++ b/reading/keyword_lists.livemd @@ -165,7 +165,7 @@ In the Elixir cell below, create a keyword list of your favourite super hero. In Enter your solution below. ```elixir - +[hero1: "superman", hero2: "batman", hero3: "robin"] ``` ## Accessing A Key @@ -184,6 +184,7 @@ Access the `:hello` key in the following keyword list. ```elixir keyword_list = [hello: "world"] +keyword_list[:hello] ``` ## Keyword List Operators @@ -206,13 +207,13 @@ evaluate as a tuple again. Remember that keyword lists are simply lists of tuple In the Elixir cell below, use `++` to add `[one: 1]` to `[two: 2]` to make `[one: 1, two: 2]`. ```elixir - +[one: 1] ++ [two: 2] ``` Remove `[two: 2]` from `[one: 1, two: 2]` to make `[one: 1]`. ```elixir - +[one: 1, two: 2] -- [two: 2] ``` ## Pattern Matching @@ -274,7 +275,8 @@ Bind `1` in the following keyword list to a variable `one`. Enter your solution below. ```elixir -[one: 1, two: 2, three: 3, four: 4] +[{key, one} | tail] = [one: 1, two: 2, three: 3, four: 4] +one ``` ## Further Reading From a55afc61846d8ee7c425079f0c3f8fc4ded7298a Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 17:52:42 -0600 Subject: [PATCH 08/64] finish maps reading --- reading/maps.livemd | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/reading/maps.livemd b/reading/maps.livemd index 3fc6d2a1c..f75b8f24a 100644 --- a/reading/maps.livemd +++ b/reading/maps.livemd @@ -193,6 +193,8 @@ map[:hello] ```elixir map = %{hello: "world"} +map.hello +map[:hello] ``` ### Updating Maps @@ -253,7 +255,9 @@ todo = %{title: "finish maps exercise", completed: false} ```elixir - +todo = %{title: "finish maps exercises", completed: false} +updated = %{todo | completed: true} +updated.completed ``` ## Pattern Matching @@ -332,7 +336,8 @@ Bind `2` and `4` in the following map to variables `two` and `four`. Enter your solution below. ```elixir -%{one: 1, two: 2, three: 3, four: 4} +%{two: two, four: four} = %{one: 1, two: 2, three: 3, four: 4} +four ``` ## Further Reading From f0a47b994b304010e13eeb54290cdeac9a680d47 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 18:20:34 -0600 Subject: [PATCH 09/64] finish modules reading --- progress.json | 12 +++---- reading/modules.livemd | 71 ++++++++++++++++++++++++++++++++---------- 2 files changed, 60 insertions(+), 23 deletions(-) diff --git a/progress.json b/progress.json index ec8e821cc..c9e0da738 100644 --- a/progress.json +++ b/progress.json @@ -8,7 +8,7 @@ "credo_reading": false, "mazes_exercise": false, "rollable_expressions_exercise": false, - "modules_reading": false, + "modules_reading": true, "file_reading": false, "agents_and_ets_reading": false, "protocols_reading": false, @@ -71,7 +71,7 @@ "group_project_blog_presentation_exercise": false, "timer_exercise": false, "games_benchmarking_exercise": false, - "guessing_games_exercise": true, + "guessing_games_exercise": false, "sign_up_form_exercise": false, "enum_reading": false, "caesar_cypher_exercise": false, @@ -95,7 +95,7 @@ "liveview_reading": false, "process_mailbox_exercise": false, "io_reading": false, - "tuples_reading": true, + "tuples_reading": false, "ranges_reading": false, "task_reading": false, "executables_reading": false, @@ -119,7 +119,7 @@ "phone_number_parsing_exercise": false, "maps_reading": false, "exunit_reading": false, - "keyword_lists_reading": true, + "keyword_lists_reading": false, "command_line_reading": false, "stack_exercise": false, "traffic_light_server_exercise": false, @@ -148,7 +148,7 @@ "start_here_reading": true, "games_supervisor_setup_exercise": false, "pic_chat_pub_sub_reading": false, - "lists_reading": true, + "lists_reading": false, "message_validation_exercise": false, "functions_reading": false, "spoonacular_recipe_api_exercise": false, @@ -205,5 +205,5 @@ "fibonacci_exercise": false, "typespec_drills_exercise": false, "custom_assertions_exercise": false, - "atoms_reading": true + "atoms_reading": false } \ No newline at end of file diff --git a/reading/modules.livemd b/reading/modules.livemd index 13b965088..1bf6dbdc6 100644 --- a/reading/modules.livemd +++ b/reading/modules.livemd @@ -308,7 +308,13 @@ end Enter your solution below. ```elixir +defmodule Languages.German do + def greeting do + "Guten Tag" + end +end +Languages.German.greeting() ``` ### Nested Modules @@ -347,8 +353,8 @@ We use the `@` symbol to define a compile-time module attribute. ```elixir defmodule Hero do - @name "Spider-Man" - @nemesis "Green Goblin" + @name "Batman" + @nemesis "Penguin" def introduce do "Hello, my name is #{@name}!" @@ -506,7 +512,29 @@ end ```elixir +defmodule Math do + @moduledoc """ + Math Module + Module demonstrates 2 functions with same name and different arity + """ + + @doc """ + add/2 + """ + def add(a, b) do + a + b + end + + @doc """ + add/3 + """ + def add(a, b, c) do + a + b + c + end +end +Math.add(2, 3) +Math.add(2, 3, 4) ``` ## Default Arguments @@ -573,7 +601,14 @@ Greeting.hello("Andrew") ``` ```elixir +defmodule Greeting do + def hello(name \\ "fubar") do + "Hello #{name}" + end +end +Greeting.hello("extra fubar") +Greeting.hello() ``` ## Documentation @@ -658,7 +693,7 @@ defmodule DoctestFailure do "expected return value" """ def test do - "actual return value" + "expected return value" end end ``` @@ -686,25 +721,27 @@ If this is the case, you either have to fix your code, or remove/comment the cra Uncomment the following code and evaluate the cell to see an example. Re-comment your code to avoid crashing the livebook as you continue with the lesson. ```elixir -# defmodule DoctestCrash do -# @moduledoc """ -# DoctestCrash +defmodule DoctestCrash do + @moduledoc """ + DoctestCrash -# Explains doctest crashes with examples -# """ + Explains doctest crashes with examples + """ -# @doc """ -# Purposely crashes doctest using invalid pattern matching + @doc """ + Purposely crashes doctest using invalid pattern matching -# ## Examples + ## Examples -# iex> {} = DoctestCrash.crash() -# "2" -# """ -# def crash do + iex> DoctestCrash.crash() + "2" + """ + def crash do + "2" + end +end -# end -# end +DoctestCrash.crash() ``` ### Your Turn From 8b3ab22f3d6f52eac660ddc690ea8508bad66897 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Feb 2023 18:22:33 -0600 Subject: [PATCH 10/64] finish command line reading --- progress.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/progress.json b/progress.json index c9e0da738..ce5ef525a 100644 --- a/progress.json +++ b/progress.json @@ -8,12 +8,12 @@ "credo_reading": false, "mazes_exercise": false, "rollable_expressions_exercise": false, - "modules_reading": true, + "modules_reading": false, "file_reading": false, "agents_and_ets_reading": false, "protocols_reading": false, "games_score_tracker_exercise": false, - "habit_tracker_exercise": true, + "habit_tracker_exercise": false, "reduce_reading": false, "code_editors_reading": false, "exdoc_reading": false, @@ -64,7 +64,7 @@ "github_engineering_journal_exercise": false, "mailbox_server_exercise": false, "blog_posts_exercise": false, - "git_reading": true, + "git_reading": false, "named_number_lists_exercise": false, "big_o_notation_reading": false, "battle_map_exercise": false, @@ -120,7 +120,7 @@ "maps_reading": false, "exunit_reading": false, "keyword_lists_reading": false, - "command_line_reading": false, + "command_line_reading": true, "stack_exercise": false, "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, @@ -129,7 +129,7 @@ "naming_numbers_exercise": false, "deployment_exercise": false, "typespecs_reading": false, - "card_counting_exercise": true, + "card_counting_exercise": false, "math_with_protocols_exercise": false, "stack_server_exercise": false, "pokemon_battle_exercise": false, @@ -158,7 +158,7 @@ "save_game_exercise": false, "document_tools_exercise": false, "factorial_exercise": false, - "livebook_reading": true, + "livebook_reading": false, "filter_values_by_type_exercise": false, "book_search_exercise": false, "guards_reading": false, From dbd8667733f90d0dc58bfa25ef4c3ac0472b2a86 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 2 Feb 2023 16:39:49 -0600 Subject: [PATCH 11/64] finish rpg dialogue exercise --- .../rock_paper_scissors_lizard_spock.livemd | 19 ++++++++++ exercises/rpg_dialogue.livemd | 36 +++++++++++++++++-- progress.json | 10 +++--- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/exercises/rock_paper_scissors_lizard_spock.livemd b/exercises/rock_paper_scissors_lizard_spock.livemd index 400a7af02..0c4d4ec89 100644 --- a/exercises/rock_paper_scissors_lizard_spock.livemd +++ b/exercises/rock_paper_scissors_lizard_spock.livemd @@ -99,9 +99,28 @@ defmodule RockPaperScissorsLizardSpock do iex> RockPaperScissorsLizardSpock.play(:lizard, :lizard) "Player 2 Wins!" """ + def play(player1, player2) do + case {player1, player2} do + {:rock, :paper} -> "Player 2 Wins!" + end end end + +RockPaperScissorsLizardSpock.play(:rock, :paper) +``` + +```elixir +# input/output +# input -> :rock, :paper, etc... +# output -> winner "Player 2 Wins!" + +player1 = :rock +player2 = :paper + +case {player1, player2} do + {:rock, :paper} -> "Player 2 Wins!" +end ``` ## Mark As Completed diff --git a/exercises/rpg_dialogue.livemd b/exercises/rpg_dialogue.livemd index dd17f3caf..890a7a579 100644 --- a/exercises/rpg_dialogue.livemd +++ b/exercises/rpg_dialogue.livemd @@ -82,7 +82,9 @@ defmodule Character do iex> %Character{name: "Frodo"} ** (ArgumentError) the following keys must also be given when building struct Character: [:name] """ - defstruct [] + @enforced_key [:name] + + defstruct @enforced_key ++ [:class, :weapon] @doc """ Introduce the character by name. @@ -96,6 +98,7 @@ defmodule Character do "My name is Aragorn." """ def introduce(character) do + "My name is #{character.name}." end @doc """ @@ -110,6 +113,7 @@ defmodule Character do "I attack with my sword!" """ def attack(character) do + "I attack with my #{character.weapon}!" end @doc """ @@ -124,6 +128,7 @@ defmodule Character do "I am a ranger." """ def class(character) do + "I am a #{character.class}." end @doc """ @@ -138,8 +143,13 @@ defmodule Character do "My name is Aragorn and I am a ranger!" """ def war_cry(character) do + "My name is #{character.name} and I am a #{character.class}!" end + # def war_cry2(name, class) do + # "My name is #{name} and I am a #{class}" + # end + @doc """ Declare that one character has defeated another. @@ -151,9 +161,31 @@ defmodule Character do iex> Character.defeat(%Character{name: "Aragorn"}, %Character{name: "Gimli", class: "warrior"}) "My name is Aragorn and I have defeated the warrior Gimli!" """ - def defeat(character1, character2) do + def defeat(char1 = %Character{}, char2 = %Character{}) do + "My name is #{char1.name} and I have defeated the #{char2.class} #{char2.name}!" end end + +# defmodule Test do +# import Character + +# def test do +# aragorn = %Character{name: "Aragorn", class: "ranger", weapon: "sword"} +# gandalf = %Character{name: "Gandalf", class: "wizard", weapon: "staff"} +# Character.introduce(aragorn) +# Character.attack(aragorn) +# Character.class(aragorn) +# Character.war_cry(aragorn) +# Character.war_cry2(aragorn.name, aragorn.class) +# Character.defeat(aragorn, gandalf) +# end +# end + +# Test.test +``` + +```elixir + ``` ### Bonus: Character Instances diff --git a/progress.json b/progress.json index ce5ef525a..be490de2a 100644 --- a/progress.json +++ b/progress.json @@ -15,7 +15,7 @@ "games_score_tracker_exercise": false, "habit_tracker_exercise": false, "reduce_reading": false, - "code_editors_reading": false, + "code_editors_reading": true, "exdoc_reading": false, "process_drills_exercise": false, "saferange_exercise": false, @@ -64,7 +64,7 @@ "github_engineering_journal_exercise": false, "mailbox_server_exercise": false, "blog_posts_exercise": false, - "git_reading": false, + "git_reading": true, "named_number_lists_exercise": false, "big_o_notation_reading": false, "battle_map_exercise": false, @@ -101,7 +101,7 @@ "executables_reading": false, "rdbms_reading": false, "fun_formulas_exercise": false, - "rpg_dialogue_exercise": false, + "rpg_dialogue_exercise": true, "palindrome_exercise": false, "comprehensions_reading": false, "comments_reading": false, @@ -120,7 +120,7 @@ "maps_reading": false, "exunit_reading": false, "keyword_lists_reading": false, - "command_line_reading": true, + "command_line_reading": false, "stack_exercise": false, "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, @@ -158,7 +158,7 @@ "save_game_exercise": false, "document_tools_exercise": false, "factorial_exercise": false, - "livebook_reading": false, + "livebook_reading": true, "filter_values_by_type_exercise": false, "book_search_exercise": false, "guards_reading": false, From 73b6e43bb93a9144c4e1d6798c9147a0a5aeabb2 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 2 Feb 2023 17:47:25 -0600 Subject: [PATCH 12/64] finish rock paper scissors lizard spock exercise --- .../rock_paper_scissors_lizard_spock.livemd | 25 +++++++++++-------- progress.json | 2 +- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/exercises/rock_paper_scissors_lizard_spock.livemd b/exercises/rock_paper_scissors_lizard_spock.livemd index 0c4d4ec89..e924cdd3f 100644 --- a/exercises/rock_paper_scissors_lizard_spock.livemd +++ b/exercises/rock_paper_scissors_lizard_spock.livemd @@ -83,6 +83,17 @@ defmodule RockPaperScissorsLizardSpock do false """ def beats?(guess1, guess2) do + {guess1, guess2} in [ + {:rock, :scissors}, + {:rock, :lizard}, + {:paper, :rock}, + {:paper, :spock}, + {:scissors, :paper}, + {:scissors, :lizards}, + {:lizard, :paper}, + {:lizard, :spock}, + {:spock, :scissors} + ] end @doc """ @@ -101,8 +112,9 @@ defmodule RockPaperScissorsLizardSpock do """ def play(player1, player2) do - case {player1, player2} do - {:rock, :paper} -> "Player 2 Wins!" + cond do + beats?(player1, player2) -> "Player 1 Wins!" + not beats?(player1, player2) -> "Player 2 Wins!" end end end @@ -111,16 +123,7 @@ RockPaperScissorsLizardSpock.play(:rock, :paper) ``` ```elixir -# input/output -# input -> :rock, :paper, etc... -# output -> winner "Player 2 Wins!" -player1 = :rock -player2 = :paper - -case {player1, player2} do - {:rock, :paper} -> "Player 2 Wins!" -end ``` ## Mark As Completed diff --git a/progress.json b/progress.json index be490de2a..7d99e11d1 100644 --- a/progress.json +++ b/progress.json @@ -175,7 +175,7 @@ "blog_tags_exercise": false, "structs_reading": false, "games_wordle_exercise": false, - "rock_paper_scissors_lizard_spock_exercise": false, + "rock_paper_scissors_lizard_spock_exercise": true, "datetime_reading": false, "with_points_exercise": false, "itinerary_exercise": false, From 5b672c135e74e187ad04eed868ae642e632063de Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 3 Feb 2023 10:45:16 -0600 Subject: [PATCH 13/64] finish ranges reading --- exercises/rpg_dialogue.livemd | 18 +++++++++--------- progress.json | 6 +++--- reading/ranges.livemd | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/exercises/rpg_dialogue.livemd b/exercises/rpg_dialogue.livemd index 890a7a579..7006b4ffd 100644 --- a/exercises/rpg_dialogue.livemd +++ b/exercises/rpg_dialogue.livemd @@ -97,8 +97,8 @@ defmodule Character do iex> Character.introduce(%Character{name: "Aragorn"}) "My name is Aragorn." """ - def introduce(character) do - "My name is #{character.name}." + def introduce(char) do + "My name is #{char.name}." end @doc """ @@ -112,8 +112,8 @@ defmodule Character do iex> Character.attack(%Character{name: "Aragorn", weapon: "sword"}) "I attack with my sword!" """ - def attack(character) do - "I attack with my #{character.weapon}!" + def attack(char) do + "I attack with my #{char.weapon}!" end @doc """ @@ -127,8 +127,8 @@ defmodule Character do iex> Character.class(%Character{name: "Aragorn", class: "ranger"}) "I am a ranger." """ - def class(character) do - "I am a #{character.class}." + def class(char) do + "I am a #{char.class}." end @doc """ @@ -142,8 +142,8 @@ defmodule Character do iex> Character.war_cry(%Character{name: "Aragorn", class: "ranger"}) "My name is Aragorn and I am a ranger!" """ - def war_cry(character) do - "My name is #{character.name} and I am a #{character.class}!" + def war_cry(char) do + "My name is #{char.name} and I am a #{char.class}!" end # def war_cry2(name, class) do @@ -161,7 +161,7 @@ defmodule Character do iex> Character.defeat(%Character{name: "Aragorn"}, %Character{name: "Gimli", class: "warrior"}) "My name is Aragorn and I have defeated the warrior Gimli!" """ - def defeat(char1 = %Character{}, char2 = %Character{}) do + def defeat(char1, char2) do "My name is #{char1.name} and I have defeated the #{char2.class} #{char2.name}!" end end diff --git a/progress.json b/progress.json index 7d99e11d1..53ea874be 100644 --- a/progress.json +++ b/progress.json @@ -96,12 +96,12 @@ "process_mailbox_exercise": false, "io_reading": false, "tuples_reading": false, - "ranges_reading": false, + "ranges_reading": true, "task_reading": false, "executables_reading": false, "rdbms_reading": false, "fun_formulas_exercise": false, - "rpg_dialogue_exercise": true, + "rpg_dialogue_exercise": false, "palindrome_exercise": false, "comprehensions_reading": false, "comments_reading": false, @@ -175,7 +175,7 @@ "blog_tags_exercise": false, "structs_reading": false, "games_wordle_exercise": false, - "rock_paper_scissors_lizard_spock_exercise": true, + "rock_paper_scissors_lizard_spock_exercise": false, "datetime_reading": false, "with_points_exercise": false, "itinerary_exercise": false, diff --git a/reading/ranges.livemd b/reading/ranges.livemd index 342c427b9..e089b5708 100644 --- a/reading/ranges.livemd +++ b/reading/ranges.livemd @@ -121,7 +121,7 @@ In the Elixir cell below, use [Enum.to_list/1](https://hexdocs.pm/elixir/Enum.ht ```elixir - +Enum.to_list(3..9//3) ``` ### Pattern Matching With Ranges From 74dbfe714e7d56fc84bf93153ae38dbc62b9a528 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 3 Feb 2023 14:08:57 -0600 Subject: [PATCH 14/64] finish fizzbuzz exercise --- exercises/fizzbuzz.livemd | 10 ++++++++++ progress.json | 2 +- reading/enum.livemd | 25 +++++++++++++++++++------ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/exercises/fizzbuzz.livemd b/exercises/fizzbuzz.livemd index 179fe2c17..a1393a308 100644 --- a/exercises/fizzbuzz.livemd +++ b/exercises/fizzbuzz.livemd @@ -77,8 +77,18 @@ defmodule FizzBuzz do ["buzz", 11, "fizz", 13, 14, "fizzbuzz"] """ def run(range) do + Enum.map(range, fn int -> + cond do + rem(int, 15) == 0 -> "fizzbuzz" + rem(int, 3) == 0 -> "fizz" + rem(int, 5) == 0 -> "buzz" + true -> int + end + end) end end + +FizzBuzz.run(1..15) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 53ea874be..8dad7d1e4 100644 --- a/progress.json +++ b/progress.json @@ -191,7 +191,7 @@ "doctests_reading": false, "pic_chat_infinite_scroll_reading": false, "exunit_with_mix_reading": false, - "fizzbuzz_exercise": false, + "fizzbuzz_exercise": true, "strings_and_binaries_reading": false, "phoenix_drills_exercise": false, "html_css_reading": false, diff --git a/reading/enum.livemd b/reading/enum.livemd index 64a5398d2..f8859418c 100644 --- a/reading/enum.livemd +++ b/reading/enum.livemd @@ -371,7 +371,7 @@ Use [Enum.map/2](https://hexdocs.pm/elixir/1.12/Enum.html#map/2) to convert a li Enter your solution below. ```elixir - +Enum.map(1..10, fn int -> to_string(int) end) ``` ## Enum.reduce/2 and Enum.reduce/3 @@ -492,7 +492,13 @@ Use [Enum.reduce/3](https://hexdocs.pm/elixir/Enum.html#reduce/3) or [Enum.reduc Enter your solution below. ```elixir - +Enum.reduce(1..10, 0, fn int, acc -> + if rem(int, 2) == 0 do + acc + int + else + acc + end +end) ``` ## Enum.filter @@ -530,7 +536,8 @@ odd_numbers = Enum.filter(1..10, fn integer -> rem(integer, 2) != 0 end) Enter your solution below. ```elixir - +even = Enum.filter(1..10, fn int -> rem(int, 2) == 0 end) +odd = Enum.filter(1..10, fn int -> rem(int, 2) != 0 end) ``` ## Enum.all?/2 @@ -585,6 +592,7 @@ Use [Enum.all/2](https://hexdocs.pm/elixir/Enum.html#all/2) to determine if all ```elixir colors = [:green, :green, :red] +Enum.all?(colors, fn color -> color == :green end) ``` ## Enum.any/2 @@ -628,7 +636,8 @@ Enum.any?(1..10_000_000, fn integer -> is_bitstring(integer) end) Use [Enum.any/2](https://hexdocs.pm/elixir/Enum.html#any/2) to determine if any of the animals in the `animals` list are `:dogs`. You may change the `animals` list to experiment with [Enum.any/2](https://hexdocs.pm/elixir/Enum.html#any/2). ```elixir -[:cats, :dogs, :bears, :lions, :penguins] +animals = [:cats, :dogs, :bears, :lions, :penguins] +Enum.any?(animals, fn animal -> animal == :dogs end) ``` ## Enum.count/1 @@ -656,6 +665,8 @@ In the Elixir cell below, count the number of elements in the `collection`. It s ```elixir collection = [1, 2, 3, 4, 5] + +Enum.count(collection) ``` ## Enum.find/3 @@ -683,7 +694,9 @@ Enum.find(["h", "e", "l", "l", "o"], 10, fn each -> is_integer(each) end) Use [Enum.find/2](https://hexdocs.pm/elixir/Enum.html#find/2) to find the first even integer in this list. ```elixir -[1, "2", "three", 4, "five", 6] +mylist = [1, "2", "three", 4, "five", 6] + +Enum.find(mylist, fn item -> is_integer(item) && rem(item, 2) == 0 end) ``` ## Enum.random/1 @@ -710,7 +723,7 @@ Enum.map(1..10, fn _ -> Enum.random(0..9) end) Enter your solution below. ```elixir - +Enum.random(0..9) ``` ## Capture Operator and Module Functions From a89e9360c2be0a005304609b7c04f779d24edcf4 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 3 Feb 2023 14:15:34 -0600 Subject: [PATCH 15/64] finish enum reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 8dad7d1e4..e179254cf 100644 --- a/progress.json +++ b/progress.json @@ -73,7 +73,7 @@ "games_benchmarking_exercise": false, "guessing_games_exercise": false, "sign_up_form_exercise": false, - "enum_reading": false, + "enum_reading": true, "caesar_cypher_exercise": false, "booleans_reading": false, "blog_comments_exercise": false, From fa6599b3675cd48434cd85e17627f4fbbc262ba8 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 3 Feb 2023 16:43:05 -0600 Subject: [PATCH 16/64] finish named number lists exercise --- exercises/named_number_lists.livemd | 17 ++++++++++++++++- progress.json | 6 +++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/exercises/named_number_lists.livemd b/exercises/named_number_lists.livemd index 7b1f06cba..ac6e70d07 100644 --- a/exercises/named_number_lists.livemd +++ b/exercises/named_number_lists.livemd @@ -75,7 +75,22 @@ flowchart Enter your solution below. ```elixir - +rando = Enum.map(1..10, fn _ -> Enum.random(0..9) end) + +Enum.map(rando, fn int -> + case int do + 0 -> "zero" + 1 -> "one" + 2 -> "two" + 3 -> "three" + 4 -> "four" + 5 -> "five" + 6 -> "six" + 7 -> "seven" + 8 -> "eight" + 9 -> "nine" + end +end) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index e179254cf..3d4eb82d7 100644 --- a/progress.json +++ b/progress.json @@ -65,7 +65,7 @@ "mailbox_server_exercise": false, "blog_posts_exercise": false, "git_reading": true, - "named_number_lists_exercise": false, + "named_number_lists_exercise": true, "big_o_notation_reading": false, "battle_map_exercise": false, "group_project_blog_presentation_exercise": false, @@ -73,7 +73,7 @@ "games_benchmarking_exercise": false, "guessing_games_exercise": false, "sign_up_form_exercise": false, - "enum_reading": true, + "enum_reading": false, "caesar_cypher_exercise": false, "booleans_reading": false, "blog_comments_exercise": false, @@ -191,7 +191,7 @@ "doctests_reading": false, "pic_chat_infinite_scroll_reading": false, "exunit_with_mix_reading": false, - "fizzbuzz_exercise": true, + "fizzbuzz_exercise": false, "strings_and_binaries_reading": false, "phoenix_drills_exercise": false, "html_css_reading": false, From 11daeb169041dfa5efc838c157fd2f334ad42ca8 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 6 Feb 2023 17:01:48 -0600 Subject: [PATCH 17/64] finish counting votes exercise --- exercises/anagram.livemd | 2 ++ exercises/animal_generator.livemd | 6 ++++++ exercises/book_search.livemd | 3 +++ exercises/counting_votes.livemd | 9 +++++++++ exercises/palindrome.livemd | 1 + progress.json | 10 +++++----- reading/built-in_modules.livemd | 28 ++++++++++++++++------------ reading/comprehensions.livemd | 8 ++++++-- reading/non_enumerables.livemd | 6 ++++-- 9 files changed, 52 insertions(+), 21 deletions(-) diff --git a/exercises/anagram.livemd b/exercises/anagram.livemd index 99d40a44d..af3db1a5c 100644 --- a/exercises/anagram.livemd +++ b/exercises/anagram.livemd @@ -67,6 +67,7 @@ defmodule Anagram do true """ def anagram?(string1, string2) do + String.to_charlist(string1) |> Enum.sort() == String.to_charlist(string2) |> Enum.sort() end @doc """ @@ -84,6 +85,7 @@ defmodule Anagram do [] """ def filter_anagrams(word_list, anagram) do + Enum.filter(word_list, fn word -> anagram?(word, anagram) end) end end ``` diff --git a/exercises/animal_generator.livemd b/exercises/animal_generator.livemd index 81d96f88c..12d9cc543 100644 --- a/exercises/animal_generator.livemd +++ b/exercises/animal_generator.livemd @@ -57,7 +57,13 @@ end Enter your solution below. ```elixir +names = ["Clifford", "Zoboomafoo", "Leonardo"] +animal_types = ["dog", "lemur", "turtle"] +ages = 1..14 +for name <- names, animal_type <- animal_types, age <- ages do + %{name: name, animal_type: animal_type, age: age} +end ``` ## Mark As Completed diff --git a/exercises/book_search.livemd b/exercises/book_search.livemd index a63beca18..dadb02a1a 100644 --- a/exercises/book_search.livemd +++ b/exercises/book_search.livemd @@ -30,6 +30,8 @@ defmodule Book do iex> %Book{title: "My Book Title"} %Book{title: "My Book Title"} """ + @enforce_keys [:title] + defstruct @enforce_keys @doc """ Search a list of Book structs. Search should match any book that includes the @@ -59,6 +61,7 @@ defmodule Book do [%Book{title: "ABC"}] """ def search(books, query) do + Enum.filter(books, fn book -> Book[:title] == query end) end end ``` diff --git a/exercises/counting_votes.livemd b/exercises/counting_votes.livemd index b7ca899b0..366b25eae 100644 --- a/exercises/counting_votes.livemd +++ b/exercises/counting_votes.livemd @@ -80,6 +80,7 @@ defmodule Votes do 0 """ def count(votes, vote) do + Enum.count(Enum.filter(votes, fn item -> item == vote end)) end end ``` @@ -120,6 +121,14 @@ defmodule VoterTally do %{dog: 2, cat: 3, bird: 1} """ def tally(votes) do + for {:dog, dogs}, {:cat, cats}, {:bird, birds} <- [votes] do + %{dog: dogs, cat: cats, bird: birds} + end + + # dogs = Enum.count(Enum.filter(votes, fn item -> item == :dog end)) + # cats = Enum.count(Enum.filter(votes, fn item -> item == :cat end)) + # birds = Enum.count(Enum.filter(votes, fn item -> item == :bird end)) + # %{dog: dogs, cat: cats, bird: birds} end end ``` diff --git a/exercises/palindrome.livemd b/exercises/palindrome.livemd index a6137c0ba..7a3b1c845 100644 --- a/exercises/palindrome.livemd +++ b/exercises/palindrome.livemd @@ -70,6 +70,7 @@ defmodule Palindrome do false """ def palindrome?(string) do + string == String.reverse(string) end end ``` diff --git a/progress.json b/progress.json index 3d4eb82d7..3dec5fc09 100644 --- a/progress.json +++ b/progress.json @@ -13,9 +13,9 @@ "agents_and_ets_reading": false, "protocols_reading": false, "games_score_tracker_exercise": false, - "habit_tracker_exercise": false, + "habit_tracker_exercise": true, "reduce_reading": false, - "code_editors_reading": true, + "code_editors_reading": false, "exdoc_reading": false, "process_drills_exercise": false, "saferange_exercise": false, @@ -65,7 +65,7 @@ "mailbox_server_exercise": false, "blog_posts_exercise": false, "git_reading": true, - "named_number_lists_exercise": true, + "named_number_lists_exercise": false, "big_o_notation_reading": false, "battle_map_exercise": false, "group_project_blog_presentation_exercise": false, @@ -96,7 +96,7 @@ "process_mailbox_exercise": false, "io_reading": false, "tuples_reading": false, - "ranges_reading": true, + "ranges_reading": false, "task_reading": false, "executables_reading": false, "rdbms_reading": false, @@ -129,7 +129,7 @@ "naming_numbers_exercise": false, "deployment_exercise": false, "typespecs_reading": false, - "card_counting_exercise": false, + "card_counting_exercise": true, "math_with_protocols_exercise": false, "stack_server_exercise": false, "pokemon_battle_exercise": false, diff --git a/reading/built-in_modules.livemd b/reading/built-in_modules.livemd index 55aeaa455..bc6b52d53 100644 --- a/reading/built-in_modules.livemd +++ b/reading/built-in_modules.livemd @@ -108,6 +108,7 @@ Use [Kernel.elem/2](https://hexdocs.pm/elixir/Kernel.html#elem/2) to retrieve `1 ```elixir tuple = {0, 4, 1, 100, 5, 7} +elem(tuple, 3) ``` ## Checking Types @@ -149,31 +150,31 @@ is_atom(:example) ``` ```elixir -%{} +is_map(%{}) ``` ```elixir -{} +is_map({}) ``` ```elixir -[] +is_list([]) ``` ```elixir -true +is_boolean(true) ``` ```elixir -1.0 +is_float(1.0) ``` ```elixir -1 +is_integer(1) ``` ```elixir -"" +is_binary("") ``` The [Kernel](https://hexdocs.pm/elixir/Kernel.html) is reasonably large. Remember, our goal is not to memorize every function but to develop familiarity with repeated practice. @@ -213,8 +214,10 @@ Created a `capped_seconds` variable that uses the value of `seconds` and cannot Enter your solution below. if `seconds` is less than `0` `capped_seconds` should be `0`. If `seconds` is greater than `59`, then `capped_seconds` should be `59`. ```elixir -seconds = 60 -capped_seconds = nil +seconds = 20 +# min(seconds, 59) +# max(seconds, 0) +capped_seconds = max(min(seconds, 59), 0) ``` ## Safe Inspection @@ -264,7 +267,8 @@ map = %{} list = [1, 2, 3] tuple = {1, 2, 3} -"" +# "" +inspect(tuple) ``` ## The Integer Module @@ -345,7 +349,7 @@ Use the [Integer.gcd/2](https://hexdocs.pm/elixir/Integer.html#gcd/2) function t positive integer that divides both 10 and 15 evenly, so the result should be `5`. ```elixir - +Integer.gcd(10, 15) ``` ## The String Module @@ -427,7 +431,7 @@ Use the [String.at/2](https://hexdocs.pm/elixir/String.html#at/2) function to ge ```elixir -"hello" +String.at("hello", 2) ``` Use the [String.at/2](https://hexdocs.pm/elixir/String.html#at/2) function to retrieve the letter `"o"` in `"hello"` diff --git a/reading/comprehensions.livemd b/reading/comprehensions.livemd index 9d2eae025..a573a6148 100644 --- a/reading/comprehensions.livemd +++ b/reading/comprehensions.livemd @@ -222,7 +222,9 @@ each generator creates another nested loop and therefore has a significant perfo In the Elixir cell below, use a comprehension with a generator of `1..50` to create a list of even integers from `2` to `100`. ```elixir - +for n <- 1..50, rem(n, 2) == 0 do + n +end ``` ## Filters @@ -315,7 +317,9 @@ end ```elixir - +for a <- 1..7, b <- 1..7, c <- 1..7, a + b + c == 7 do + {a, b, c} +end ``` ## Collectables diff --git a/reading/non_enumerables.livemd b/reading/non_enumerables.livemd index 724734dd2..77501acd6 100644 --- a/reading/non_enumerables.livemd +++ b/reading/non_enumerables.livemd @@ -57,7 +57,7 @@ Integer.digits(123) In the Elixir cell below, convert the integer `4389` into a list of digits. ```elixir - +Integer.digits(4389) ``` ### Undigits @@ -138,7 +138,7 @@ Now your string is an enumerable list of characters. In the Elixir cell below, convert the string `"Hello, world!"` into a list of single characters. ```elixir - +String.split("Hello, world!", "") ``` ### Joining Strings @@ -216,6 +216,8 @@ defmodule CharacterCount do 4 """ def count(string) do + String.split(String.trim(string), "") + # Enum.count(String.split(string, "")) end end ``` From f4d0d1299401a1bc047c69b931bbd6e6914fcb18 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 6 Feb 2023 17:03:49 -0600 Subject: [PATCH 18/64] finish animal generator exercise --- exercises/counting_votes.livemd | 12 ++++-------- progress.json | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/exercises/counting_votes.livemd b/exercises/counting_votes.livemd index 366b25eae..cb1e0c25e 100644 --- a/exercises/counting_votes.livemd +++ b/exercises/counting_votes.livemd @@ -121,14 +121,10 @@ defmodule VoterTally do %{dog: 2, cat: 3, bird: 1} """ def tally(votes) do - for {:dog, dogs}, {:cat, cats}, {:bird, birds} <- [votes] do - %{dog: dogs, cat: cats, bird: birds} - end - - # dogs = Enum.count(Enum.filter(votes, fn item -> item == :dog end)) - # cats = Enum.count(Enum.filter(votes, fn item -> item == :cat end)) - # birds = Enum.count(Enum.filter(votes, fn item -> item == :bird end)) - # %{dog: dogs, cat: cats, bird: birds} + dogs = Enum.count(Enum.filter(votes, fn item -> item == :dog end)) + cats = Enum.count(Enum.filter(votes, fn item -> item == :cat end)) + birds = Enum.count(Enum.filter(votes, fn item -> item == :bird end)) + %{dog: dogs, cat: cats, bird: birds} end end ``` diff --git a/progress.json b/progress.json index 3dec5fc09..47f0c438c 100644 --- a/progress.json +++ b/progress.json @@ -58,7 +58,7 @@ "math_with_guards_exercise": false, "pokemon_api_exercise": false, "file_search_exercise": false, - "animal_generator_exercise": false, + "animal_generator_exercise": true, "group_project_blog_exercise": false, "treasure_matching_exercise": false, "github_engineering_journal_exercise": false, From fa1f08ac22661c6e24524cacd4617fbdc4cdb721 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 6 Feb 2023 17:05:45 -0600 Subject: [PATCH 19/64] finish palindrome exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 47f0c438c..03aa34b19 100644 --- a/progress.json +++ b/progress.json @@ -102,7 +102,7 @@ "rdbms_reading": false, "fun_formulas_exercise": false, "rpg_dialogue_exercise": false, - "palindrome_exercise": false, + "palindrome_exercise": true, "comprehensions_reading": false, "comments_reading": false, "rock_paper_scissors_exercise": false, From 5feaba5a46ea75a48cb82b9edada7dd55524fa8b Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Feb 2023 10:28:35 -0600 Subject: [PATCH 20/64] finish built-in modules reading --- progress.json | 2 +- reading/built-in_modules.livemd | 37 +++++++++++++++++---------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/progress.json b/progress.json index 03aa34b19..2bb025094 100644 --- a/progress.json +++ b/progress.json @@ -180,7 +180,7 @@ "with_points_exercise": false, "itinerary_exercise": false, "apis_reading": false, - "built-in_modules_reading": false, + "built-in_modules_reading": true, "rps_pattern_matching_exercise": false, "arithmetic_reading": false, "rps_guards_exercise": false, diff --git a/reading/built-in_modules.livemd b/reading/built-in_modules.livemd index bc6b52d53..d574b8f19 100644 --- a/reading/built-in_modules.livemd +++ b/reading/built-in_modules.livemd @@ -614,7 +614,7 @@ Use [List.delete_at/2](https://hexdocs.pm/elixir/List.html#delete_at/2) to remov ```elixir -[2, 1, 3] +List.delete_at([2, 1, 3], 0) ``` Use [List.flatten/1](https://hexdocs.pm/elixir/List.html#flatten/1) to flatten the following list into `[1, 2, 3, 4, 5, 6, 7, 8, 9]` @@ -630,7 +630,7 @@ Use [List.flatten/1](https://hexdocs.pm/elixir/List.html#flatten/1) to flatten t ```elixir -[1, 2, [3, 4, 5], 6, [7, [8, [9]]]] +List.flatten([1, 2, [3, 4, 5], 6, [7, [8, [9]]]]) ``` Use [List.insert_at/3](https://hexdocs.pm/elixir/List.html#insert_at/3) to insert `2` into the following list to make `[1, 2, 3]`. @@ -646,7 +646,7 @@ Use [List.insert_at/3](https://hexdocs.pm/elixir/List.html#insert_at/3) to inser ```elixir -[1, 3] +List.insert_at([1, 3], 1, 2) ``` Use [List.last/2](https://hexdocs.pm/elixir/List.html#last/2) to retrieve the last element `10000` in a list from `1` to `10000`. @@ -668,7 +668,7 @@ Use [List.last/2](https://hexdocs.pm/elixir/List.html#last/2) to retrieve the la ```elixir -Enum.to_list(1..10000) +List.last(Enum.to_list(1..10000)) ``` Use [List.update_at/3](https://hexdocs.pm/elixir/List.html#update_at/3) to subtract `2` from `4` in the following list to make `[1, 2, 3]`. @@ -684,7 +684,7 @@ Use [List.update_at/3](https://hexdocs.pm/elixir/List.html#update_at/3) to subtr ```elixir -[1, 4, 3] +List.update_at([1, 4, 3], 1, &(&1 - 2)) ``` Use [List.zip/1](https://hexdocs.pm/elixir/List.html#zip/1) to combine these two lists to make `[{"a", 1}, {"b", 2}, {"c", 3}]`. @@ -705,6 +705,7 @@ Use [List.zip/1](https://hexdocs.pm/elixir/List.html#zip/1) to combine these two ```elixir letters = ["a", "b", "c"] numbers = [1, 2, 3] +List.zip([letters, numbers]) ``` ## The Map Module @@ -760,7 +761,7 @@ Use [Map.get/3](https://hexdocs.pm/elixir/Map.html#get/3) to retrieve the `"worl ```elixir -%{hello: "world"} +Map.get(%{hello: "world"}, :hello) ``` Use [Map.put/3](https://hexdocs.pm/elixir/Map.html#put/3) to add the key `:two` with the value `2` to the following map. @@ -776,7 +777,7 @@ Use [Map.put/3](https://hexdocs.pm/elixir/Map.html#put/3) to add the key `:two` ```elixir -%{one: 1} +Map.put(%{one: 1}, :two, 2) ``` Use [Map.keys/1](https://hexdocs.pm/elixir/Map.html#keys/1) to retrieve the keys for the following map. @@ -792,7 +793,7 @@ Use [Map.keys/1](https://hexdocs.pm/elixir/Map.html#keys/1) to retrieve the keys ```elixir -%{key1: 1, key2: 2, key3: 3} +Map.keys(%{key1: 1, key2: 2, key3: 3}) ``` Use [Map.delete/2](https://hexdocs.pm/elixir/Map.html#delete/2) to remove `:key1` from the following map. @@ -808,7 +809,7 @@ Use [Map.delete/2](https://hexdocs.pm/elixir/Map.html#delete/2) to remove `:key1 ```elixir -%{key1: 1, key2: 2, key3: 3} +Map.delete(%{key1: 1, key2: 2, key3: 3}, :key1) ``` Use [Map.merge/2](https://hexdocs.pm/elixir/Map.html#merge/2) to combine `%{one: 1}` and `%{two: 2}`. @@ -824,7 +825,7 @@ Use [Map.merge/2](https://hexdocs.pm/elixir/Map.html#merge/2) to combine `%{one: ```elixir - +Map.merge(%{one: 1}, %{two: 2}) ``` Use [Map.update/4](https://hexdocs.pm/elixir/Map.html#update/4) or [Map.update!/3](https://hexdocs.pm/elixir/Map.html#update!/3) to update the `:count` key in this map to be `5` plus the existing value. @@ -840,7 +841,7 @@ Use [Map.update/4](https://hexdocs.pm/elixir/Map.html#update/4) or [Map.update!/ ```elixir -%{count: 10} +Map.update(%{count: 10}, :count, 10, &(&1 + 5)) ``` Use [Map.values/1](https://hexdocs.pm/elixir/Map.html#values/1) to retrieve the values `[1, 2, 3]` in the following map. @@ -856,7 +857,7 @@ Use [Map.values/1](https://hexdocs.pm/elixir/Map.html#values/1) to retrieve the ```elixir -%{key1: 1, key2: 2, key3: 3} +Map.values(%{key1: 1, key2: 2, key3: 3}) ``` ## The Keyword Module @@ -919,7 +920,7 @@ Use [Keyword.get/3](https://hexdocs.pm/elixir/Keyword.html#get/3) to access the ```elixir -[color: "red"] +Keyword.get([color: "red"], :color) ``` Use [Keyword.get/3](https://hexdocs.pm/elixir/Keyword.html#get/3) to access the value for the `:color` key in the following empty list. If the `:color` key does not exist, provide a default value of `"blue"`. @@ -935,7 +936,7 @@ Use [Keyword.get/3](https://hexdocs.pm/elixir/Keyword.html#get/3) to access the ```elixir -[] +Keyword.get([], :color, "blue") ``` Use the [Keyword.keys/1](https://hexdocs.pm/elixir/Keyword.html#keys/1) function to list all of the keys in the following keyword list. @@ -951,7 +952,7 @@ Use the [Keyword.keys/1](https://hexdocs.pm/elixir/Keyword.html#keys/1) function ```elixir -[one: 1, two: 2, three: 3] +Keyword.keys(one: 1, two: 2, three: 3) ``` Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) function to determine if the following is a keyword list. @@ -967,7 +968,7 @@ Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) ```elixir -[key: "value"] +Keyword.keyword?(key: "value") ``` Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) function to determine if an empty list is a keyword list. @@ -985,7 +986,7 @@ Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) ```elixir -[] +Keyword.keyword?([]) ``` Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) function to determine if the following list is a keyword list. @@ -1001,7 +1002,7 @@ Use the [Keyword.keyword?/1](https://hexdocs.pm/elixir/Keyword.html#keyword?/1) ```elixir -[1, 2, 3] +Keyword.keyword?([1, 2, 3]) ``` ## Further Reading From 0123821b482e58c2a5b7ad13194aba81c22ae42a Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Feb 2023 10:30:37 -0600 Subject: [PATCH 21/64] finish anagram exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 2bb025094..eb97d7631 100644 --- a/progress.json +++ b/progress.json @@ -77,7 +77,7 @@ "caesar_cypher_exercise": false, "booleans_reading": false, "blog_comments_exercise": false, - "anagram_exercise": false, + "anagram_exercise": true, "lazy_product_filters_exercise": false, "file_system_todo_app_exercise": false, "phoenix_1.7_reading": false, From f78fede5b167ae104b719150d44b1a771846d2c2 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Feb 2023 10:35:37 -0600 Subject: [PATCH 22/64] finish non enumerables reading --- progress.json | 2 +- reading/non_enumerables.livemd | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/progress.json b/progress.json index eb97d7631..1ec567cff 100644 --- a/progress.json +++ b/progress.json @@ -43,7 +43,7 @@ "pascals_triangle_exercise": false, "book_search_book_content_reading": false, "portfolio_exercise": false, - "non_enumerables_reading": false, + "non_enumerables_reading": true, "control_flow_reading": false, "lists_vs_tuples_reading": false, "dominoes_exercise": false, diff --git a/reading/non_enumerables.livemd b/reading/non_enumerables.livemd index 77501acd6..cabb378ca 100644 --- a/reading/non_enumerables.livemd +++ b/reading/non_enumerables.livemd @@ -216,8 +216,7 @@ defmodule CharacterCount do 4 """ def count(string) do - String.split(String.trim(string), "") - # Enum.count(String.split(string, "")) + Enum.count(String.split(string, "", trim: true)) end end ``` From 32173e4e0d212d6744609a41eca09ae49b1e0a03 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Feb 2023 12:28:57 -0600 Subject: [PATCH 23/64] finish filter values by type exercise --- exercises/book_search.livemd | 28 +++++++++++++++++++++++--- exercises/filter_values_by_type.livemd | 9 +++++++++ progress.json | 2 +- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/exercises/book_search.livemd b/exercises/book_search.livemd index dadb02a1a..c8e19e62d 100644 --- a/exercises/book_search.livemd +++ b/exercises/book_search.livemd @@ -30,8 +30,7 @@ defmodule Book do iex> %Book{title: "My Book Title"} %Book{title: "My Book Title"} """ - @enforce_keys [:title] - defstruct @enforce_keys + defstruct [:title] @doc """ Search a list of Book structs. Search should match any book that includes the @@ -40,6 +39,7 @@ defmodule Book do ## Examples Include books that exactly match the search query. + # Map.get(map, :title) == query iex> book1 = %Book{title: "A"} iex> book2 = %Book{title: "B"} @@ -48,6 +48,8 @@ defmodule Book do [%Book{title: "A"}] Include books that partially match the search query. + # does the query match any letter of the title? + # split the title string and enum.filter over query iex> Book.search([%Book{title: "ABC"}], "A") [%Book{title: "ABC"}] @@ -56,16 +58,36 @@ defmodule Book do [%Book{title: "BAC"}] Search should be case insensitive. + # lowercase the input and title iex> Book.search([%Book{title: "ABC"}], "a") [%Book{title: "ABC"}] """ + def fuzzy_match(string, char) do + mysplit = String.split(string, "", trim: true) + Enum.filter(mysplit, fn element -> element == char end) && string + end + def search(books, query) do - Enum.filter(books, fn book -> Book[:title] == query end) + # books that exactly match + # Enum.filter(books, fn book -> Map.get(book, :title) == query end) + book = Enum.filter(books, fn book -> Map.get(book, :title) end) + fuzzy_match(book, query) end end ``` +```elixir +mytitle = "ABC" +myquery = "A" + +mysplit = String.split(mytitle, "", trim: true) +# split string +# filter split string to see if any char == query +# if filter returns a match then return title +Enum.filter(mysplit, fn char -> myquery == char end) && mytitle +``` + ## Mark As Completed diff --git a/exercises/filter_values_by_type.livemd b/exercises/filter_values_by_type.livemd index 2b9025019..1092bfeb9 100644 --- a/exercises/filter_values_by_type.livemd +++ b/exercises/filter_values_by_type.livemd @@ -82,7 +82,10 @@ defmodule Filter do iex> Filter.integers([1, 2, %{}, {}, []]) [1, 2] """ + + # filter list using is_integer def integers(list) do + Enum.filter(list, fn element -> is_integer(element) end) end @doc """ @@ -94,6 +97,7 @@ defmodule Filter do [1.2, 3.2] """ def floats(list) do + Enum.filter(list, fn element -> is_float(element) end) end @doc """ @@ -105,6 +109,7 @@ defmodule Filter do [1, 2, 1.2, 3.2] """ def numbers(list) do + Enum.filter(list, fn element -> is_integer(element) or is_float(element) end) end @doc """ @@ -116,6 +121,7 @@ defmodule Filter do [:first_atom, :second_atom] """ def atoms(list) do + Enum.filter(list, fn element -> is_atom(element) end) end @doc """ @@ -127,6 +133,7 @@ defmodule Filter do [[1, 2], [4, 5, 6]] """ def lists(list) do + Enum.filter(list, fn element -> is_list(element) && element != [] end) end @doc """ @@ -138,6 +145,7 @@ defmodule Filter do [%{}, %{key: "value"}] """ def maps(list) do + Enum.filter(list, fn element -> is_map(element) end) end @doc """ @@ -149,6 +157,7 @@ defmodule Filter do [[], [key: "value"]] """ def keyword_lists(list) do + Enum.filter(list, fn element -> Keyword.keyword?(element) end) end end ``` diff --git a/progress.json b/progress.json index 1ec567cff..4902118f9 100644 --- a/progress.json +++ b/progress.json @@ -159,7 +159,7 @@ "document_tools_exercise": false, "factorial_exercise": false, "livebook_reading": true, - "filter_values_by_type_exercise": false, + "filter_values_by_type_exercise": true, "book_search_exercise": false, "guards_reading": false, "sql_drills_exercise": false, From 12b63c5e575b4fc284539cf4b577f36104aeed8e Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Feb 2023 17:07:27 -0600 Subject: [PATCH 24/64] finish tic-tac-toe exercise --- exercises/book_search.livemd | 2 +- exercises/tic-tac-toe.livemd | 15 +++++++++++++++ progress.json | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/exercises/book_search.livemd b/exercises/book_search.livemd index c8e19e62d..d3c739b02 100644 --- a/exercises/book_search.livemd +++ b/exercises/book_search.livemd @@ -72,7 +72,7 @@ defmodule Book do # books that exactly match # Enum.filter(books, fn book -> Map.get(book, :title) == query end) book = Enum.filter(books, fn book -> Map.get(book, :title) end) - fuzzy_match(book, query) + String.contains?(book, query) end end ``` diff --git a/exercises/tic-tac-toe.livemd b/exercises/tic-tac-toe.livemd index 08c12950f..bafb9544f 100644 --- a/exercises/tic-tac-toe.livemd +++ b/exercises/tic-tac-toe.livemd @@ -153,7 +153,13 @@ defmodule TicTacToe do iex> TicTacToe.at(board, {2, 2}) "C" """ + def at(board, coordinate) do + {x, y} = coordinate + + Enum.reverse(board) + |> Enum.at(y) + |> Enum.at(x) end @doc """ @@ -177,6 +183,15 @@ defmodule TicTacToe do [[nil, "X", "O"], [nil, "X", "O"],[nil, nil, "X"]] """ def fill(board, coordinate, symbol) do + {x, y} = coordinate + + row_index = 2 - y + + row = Enum.at(board, row_index) + + new_row = List.replace_at(row, x, symbol) + + List.replace_at(board, row_index, new_row) end end ``` diff --git a/progress.json b/progress.json index 4902118f9..0f77e3bc1 100644 --- a/progress.json +++ b/progress.json @@ -86,7 +86,7 @@ "github_collab_exercise": false, "web_servers_reading": false, "book_search_deployment_reading": false, - "tic-tac-toe_exercise": false, + "tic-tac-toe_exercise": true, "games_supervised_score_tracker_exercise": false, "benchmarking_reading": false, "processes_reading": false, From 7ba0bb8db8bd82383621b0a4db15bd23ec7f9a4d Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 8 Feb 2023 16:37:23 -0600 Subject: [PATCH 25/64] finish number finder exercise --- exercises/book_search.livemd | 34 ++++++++++++++++---------------- exercises/number_finder.livemd | 18 +++++++++++++++++ exercises/weighted_voting.livemd | 28 ++++++++++++++++++++++++++ progress.json | 2 +- 4 files changed, 64 insertions(+), 18 deletions(-) diff --git a/exercises/book_search.livemd b/exercises/book_search.livemd index d3c739b02..9c76e8eaa 100644 --- a/exercises/book_search.livemd +++ b/exercises/book_search.livemd @@ -49,7 +49,7 @@ defmodule Book do Include books that partially match the search query. # does the query match any letter of the title? - # split the title string and enum.filter over query + # use String.contains(book, query) iex> Book.search([%Book{title: "ABC"}], "A") [%Book{title: "ABC"}] @@ -63,29 +63,29 @@ defmodule Book do iex> Book.search([%Book{title: "ABC"}], "a") [%Book{title: "ABC"}] """ - def fuzzy_match(string, char) do - mysplit = String.split(string, "", trim: true) - Enum.filter(mysplit, fn element -> element == char end) && string - end + + # def fuzzy_match(string, char) do + # mysplit = String.split(string, "", trim: true) + # Enum.filter(mysplit, fn element -> element == char end) && string + # end def search(books, query) do - # books that exactly match - # Enum.filter(books, fn book -> Map.get(book, :title) == query end) - book = Enum.filter(books, fn book -> Map.get(book, :title) end) - String.contains?(book, query) + # books that match one letter + Enum.filter(books, fn book -> String.contains?(book, query) end) + + # books that exactly match + Enum.filter(books, fn book -> Map.get(book, :title) end) end end ``` ```elixir -mytitle = "ABC" -myquery = "A" - -mysplit = String.split(mytitle, "", trim: true) -# split string -# filter split string to see if any char == query -# if filter returns a match then return title -Enum.filter(mysplit, fn char -> myquery == char end) && mytitle +book = "ABC" +query = "D" +String.contains?(book, query) + +test = %{mybook: "mytitle"} +Map.get(test, ) ``` ## Mark As Completed diff --git a/exercises/number_finder.livemd b/exercises/number_finder.livemd index 8a9a5a859..05f9cb9d0 100644 --- a/exercises/number_finder.livemd +++ b/exercises/number_finder.livemd @@ -37,12 +37,21 @@ defmodule NumberFinder do iex> NumberFinder.smallest([2, 3, 1]) 1 + iex> NumberFinder.smallest([2, 2, 3, 4]) 2 + iex> NumberFinder.smallest([2, 2, 3, 4, 10, 20, -3]) -3 """ def smallest(number_list) do + Enum.reduce(number_list, fn elem, acc -> + if acc < elem do + acc + else + elem + end + end) end @doc """ @@ -52,12 +61,21 @@ defmodule NumberFinder do iex> NumberFinder.largest([2, 3, 1]) 3 + iex> NumberFinder.largest([2, 2, 3, 4, 4]) 4 + iex> NumberFinder.largest([2, 2, 3, 4, 10, 20, -3]) 20 """ def largest(number_list) do + Enum.reduce(number_list, fn elem, acc -> + if acc > elem do + acc + else + elem + end + end) end end ``` diff --git a/exercises/weighted_voting.livemd b/exercises/weighted_voting.livemd index 96eb35039..166bb852c 100644 --- a/exercises/weighted_voting.livemd +++ b/exercises/weighted_voting.livemd @@ -82,12 +82,21 @@ defmodule WeightedVoting do iex> WeightedVoting.count([dogs: 20, dogs: 10], :dogs) 30 + iex> WeightedVoting.count([cats: 10, dogs: 20, dogs: 30], :dogs) 50 + iex> WeightedVoting.count([cats: 10, dogs: 20, dogs: 10, cats: 30], :cats) 40 """ def count(votes, vote_to_count) do + Enum.reduce(votes, 0, fn {key, value}, acc -> + if key == vote_to_count do + acc + value + else + acc + end + end) end @doc """ @@ -100,16 +109,35 @@ defmodule WeightedVoting do iex> WeightedVoting.tally([dogs: 20, dogs: 10]) [dogs: 30] + iex> WeightedVoting.tally([cats: 10, dogs: 20, dogs: 10]) [cats: 10, dogs: 30] + iex> WeightedVoting.tally([cats: 10, dogs: 20, cats: 20, dogs: 10, birds: 20]) [birds: 20, cats: 30, dogs: 30] """ def tally(votes) do + Enum.reduce(votes, [], fn {animal, value}, acc -> + Keyword.update(acc, animal, value, fn existing_value -> + value + existing_value + end) + end) + |> Enum.sort() end end ``` +```elixir +votes = [cats: 10, dogs: 20, cats: 20, dogs: 10, birds: 20] +vote_to_count = :birds + +def count(votes, vote_to_count) do + Enum.reduce(votes, fn acc, vote_to_count -> + IO.inspect(binding()) + end) +end +``` + ### Bonus: Tally Map Create a `WeightedVoting.tally_map/1` function which returns a map instead of a keyword list. diff --git a/progress.json b/progress.json index 0f77e3bc1..a75e3eb40 100644 --- a/progress.json +++ b/progress.json @@ -49,7 +49,7 @@ "dominoes_exercise": false, "command_line_family_tree_exercise": false, "phoenix_and_ecto_reading": false, - "number_finder_exercise": false, + "number_finder_exercise": true, "pic_chat_image_upload_reading": false, "timeline_exercise": false, "newsletter_reading": false, From a5d799b10502fae8ab8269354e46b17fb1d4b6a2 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 8 Feb 2023 16:39:18 -0600 Subject: [PATCH 26/64] finish weighted voting exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index a75e3eb40..ff38c0846 100644 --- a/progress.json +++ b/progress.json @@ -153,7 +153,7 @@ "functions_reading": false, "spoonacular_recipe_api_exercise": false, "book_changeset_exercise": false, - "weighted_voting_exercise": false, + "weighted_voting_exercise": true, "supervisors_reading": false, "save_game_exercise": false, "document_tools_exercise": false, From c7a07c91cb5c6a88a22c251afcfbdd227cafa4a6 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Feb 2023 11:25:44 -0600 Subject: [PATCH 27/64] finish custom enum with reduce exercise --- exercises/custom_enum_with_reduce.livemd | 31 +++++++++++++++++++++--- progress.json | 2 +- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/exercises/custom_enum_with_reduce.livemd b/exercises/custom_enum_with_reduce.livemd index 108de363c..448a2bd7b 100644 --- a/exercises/custom_enum_with_reduce.livemd +++ b/exercises/custom_enum_with_reduce.livemd @@ -78,6 +78,11 @@ defmodule CustomEnum do [7, 6, 5, 4] """ def reverse(list) do + # put first element on head of new list + Enum.reduce(list, [], fn element, acc -> + # IO.inspect(binding()) + [element | acc] + end) end @doc """ @@ -92,6 +97,11 @@ defmodule CustomEnum do [true, true, true] """ def map(list, callback_function) do + # while list not empty apply fn to element + Enum.reduce(list, [], fn element, acc -> + [callback_function.(element) | acc] + end) + |> reverse() end @doc """ @@ -107,6 +117,15 @@ defmodule CustomEnum do ["2", "3"] """ def filter(list, callback_function) do + # add element to new list if callback_function(element) returns true + Enum.reduce(list, [], fn element, acc -> + if callback_function.(element) do + [element | acc] + else + acc + end + end) + |> reverse() end @doc """ @@ -117,10 +136,12 @@ defmodule CustomEnum do iex> CustomEnum.sum([1, 2, 3]) 6 - iex> CustomEnum.sum([1, 1, 1]) - 3 + # iex> CustomEnum.sum([1, 1, 1]) + # 3 """ def sum(list_of_integers) do + # add each int to accumulator and return accumulator + Enum.reduce(list_of_integers, 0, fn int, acc -> int + acc end) end @doc """ @@ -131,10 +152,12 @@ defmodule CustomEnum do iex> CustomEnum.join(["A", "B", "C"]) "ABC" - iex> CustomEnum.join(["Hello", ",", " ", "World", "!"]) - "Hello, World!" + # iex> CustomEnum.join(["Hello", ",", " ", "World", "!"]) + # "Hello, World!" """ def join(list_of_strings) do + # concat each string to acc string + Enum.reduce(list_of_strings, "", fn string, acc -> acc <> string end) end end ``` diff --git a/progress.json b/progress.json index ff38c0846..73de353ee 100644 --- a/progress.json +++ b/progress.json @@ -186,7 +186,7 @@ "rps_guards_exercise": false, "book_search_tags_reading": false, "email_validation_exercise": false, - "custom_enum_with_reduce_exercise": false, + "custom_enum_with_reduce_exercise": true, "blog_comment_form_exercise": false, "doctests_reading": false, "pic_chat_infinite_scroll_reading": false, From 5df5484d90d1545307785e06e8096bae8a4ee132 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Feb 2023 12:43:02 -0600 Subject: [PATCH 28/64] finish time converting exercise --- exercises/custom_enum_with_reduce.livemd | 4 ++-- exercises/time_converting.livemd | 16 ++++++++++++++-- progress.json | 2 +- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/exercises/custom_enum_with_reduce.livemd b/exercises/custom_enum_with_reduce.livemd index 448a2bd7b..7bdee0bad 100644 --- a/exercises/custom_enum_with_reduce.livemd +++ b/exercises/custom_enum_with_reduce.livemd @@ -152,8 +152,8 @@ defmodule CustomEnum do iex> CustomEnum.join(["A", "B", "C"]) "ABC" - # iex> CustomEnum.join(["Hello", ",", " ", "World", "!"]) - # "Hello, World!" + iex> CustomEnum.join(["Hello", ",", " ", "World", "!"]) + "Hello, World!" """ def join(list_of_strings) do # concat each string to acc string diff --git a/exercises/time_converting.livemd b/exercises/time_converting.livemd index 5346dbbf2..578aeae68 100644 --- a/exercises/time_converting.livemd +++ b/exercises/time_converting.livemd @@ -74,6 +74,12 @@ defmodule TimeConverter do """ def to_seconds(amount, unit) do + case unit do + :seconds -> amount + :minutes -> amount * 60 + :hours -> amount * 3600 + :days -> amount * 86400 + end end @doc """ @@ -82,8 +88,8 @@ defmodule TimeConverter do ## Examples - iex> TimeConverter.from_seconds(1, :seconds) - 1.0 + iex> TimeConverter.from_seconds(2, :seconds) + 2.0 iex> TimeConverter.from_seconds(60, :minutes) 1.0 @@ -96,6 +102,12 @@ defmodule TimeConverter do """ def from_seconds(amount, unit) do + case unit do + :seconds -> amount / 1.0 + :minutes -> amount / 60 + :hours -> amount / 3600 + :days -> amount / 86400 + end end end ``` diff --git a/progress.json b/progress.json index 73de353ee..9072d1dc2 100644 --- a/progress.json +++ b/progress.json @@ -19,7 +19,7 @@ "exdoc_reading": false, "process_drills_exercise": false, "saferange_exercise": false, - "time_converting_exercise": false, + "time_converting_exercise": true, "pokemon_server_exercise": false, "strings_reading": false, "counting_votes_exercise": false, From 874ab0a74ab7925a7a1a321ccee5c5f178f4e674 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Feb 2023 17:55:15 -0600 Subject: [PATCH 29/64] finish timeline exercise --- exercises/itinerary.livemd | 11 +++++++++++ exercises/timeline.livemd | 28 ++++++++++++++++++++++++++++ progress.json | 2 +- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/exercises/itinerary.livemd b/exercises/itinerary.livemd index ae7a980ca..396207755 100644 --- a/exercises/itinerary.livemd +++ b/exercises/itinerary.livemd @@ -58,10 +58,21 @@ defmodule Itinerary do """ def has_time?(start, finish, minutes) do + start = DateTime.to_unix(start) + finish = DateTime.to_unix(finish) + + available_time = finish - start + task_time = minutes * 60 + + task_time <= available_time end end ``` +```elixir +DateTime.utc_now() |> DateTime.to_unix() +``` + ## Mark As Completed diff --git a/exercises/timeline.livemd b/exercises/timeline.livemd index 5bb45c981..6cafbd278 100644 --- a/exercises/timeline.livemd +++ b/exercises/timeline.livemd @@ -96,6 +96,14 @@ defmodule Timeline do [9, 12, 2] """ def from_dates(dates) do + # chunk the date list into pairs with offset = 1 + # map over the chunked pairs with Date.diff + + pairs = Enum.chunk_every(dates, 2, 1, :discard) + + Enum.map(pairs, fn [date1, date2] -> + Date.diff(date2, date1) + end) end @doc """ @@ -113,11 +121,31 @@ defmodule Timeline do iex> Timeline.from_strings(["2020-01-01", "2020-01-10", "2020-01-22", "2020-01-24"]) [9, 12, 2] """ + + def make_date_from_string(string) do + [year, month, day] = String.split(string, "-", trim: true) + Date.new!(String.to_integer(year), String.to_integer(month), String.to_integer(day)) + end + def from_strings(date_strings) do + # convert list of strings to new list of dates + # call from_dates with new list of dates + + new_list = Enum.map(date_strings, fn string -> make_date_from_string(string) end) + from_dates(new_list) end end ``` +```elixir +test_string = ["2020-01-01", "2020-01-10", "2020-01-22", "2020-01-24"] + +Enum.map(test_string, fn string -> + [year, month, day] = String.split(string, "-", trim: true) + Date.new!(String.to_integer(year), String.to_integer(month), String.to_integer(day)) +end) +``` + ## Mark As Completed diff --git a/progress.json b/progress.json index 9072d1dc2..c00b63311 100644 --- a/progress.json +++ b/progress.json @@ -51,7 +51,7 @@ "phoenix_and_ecto_reading": false, "number_finder_exercise": true, "pic_chat_image_upload_reading": false, - "timeline_exercise": false, + "timeline_exercise": true, "newsletter_reading": false, "advanced_pattern_matching_reading": false, "games_guessing_game_exercise": false, From 3eac09417137c2b47107d106957c49928f627ed5 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 10 Feb 2023 11:16:35 -0600 Subject: [PATCH 30/64] finish strings and binaries reading --- progress.json | 2 +- reading/strings_and_binaries.livemd | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/progress.json b/progress.json index c00b63311..46f5b3c97 100644 --- a/progress.json +++ b/progress.json @@ -192,7 +192,7 @@ "pic_chat_infinite_scroll_reading": false, "exunit_with_mix_reading": false, "fizzbuzz_exercise": false, - "strings_and_binaries_reading": false, + "strings_and_binaries_reading": true, "phoenix_drills_exercise": false, "html_css_reading": false, "score_tracker_exercise": false, diff --git a/reading/strings_and_binaries.livemd b/reading/strings_and_binaries.livemd index d1be8eff8..b5a4ce294 100644 --- a/reading/strings_and_binaries.livemd +++ b/reading/strings_and_binaries.livemd @@ -85,6 +85,10 @@ Each byte stores an integer between `1` and `255` in binary. These integers are ?A ``` +```elixir +?Z +``` + We can also see that a string is actually a series of binary bytes representing a codepoint using [IO.inspect/2](https://hexdocs.pm/elixir/IO.html#inspect/2) with the `binaries: :as_binaries` option. ```elixir @@ -218,13 +222,13 @@ String.graphemes("é") Use [String.graphemes/1](https://hexdocs.pm/elixir/String.html#graphemes/1) to convert the [woman fire fighter](https://emojipedia.org/woman-firefighter/) emoji 👩‍🚒 to a list of graphemes. ```elixir - +String.graphemes("👩‍🚒") ``` Use [String.codepoints/1](https://hexdocs.pm/elixir/String.html#codepoints/1) to convert the emoji 👩‍🚒 into a list of codepoints. You'll notice it's actually a combination of the 👩 and 🚒 emojis. ```elixir - +String.codepoints("👩‍🚒") ``` ## Hexadecimal @@ -316,7 +320,7 @@ Use hexadecimal `0x` syntax to represent the number `15`. ```elixir - +0xF ``` ## Bitstrings @@ -416,7 +420,7 @@ Convert the alphabet `"abcdefghijklmnopqrstuvwxyz"` to a charlist, then inspect ```elixir - +IO.inspect(String.to_charlist("abcdefghijklmnopqrstuvwxyz"), charlists: :as_lists) ``` ## Further Reading From 09cb1895898d90dd324347b96ce27eb8b71f92b9 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 10 Feb 2023 13:24:00 -0600 Subject: [PATCH 31/64] finish email validation exercise --- exercises/email_validation.livemd | 50 ++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/exercises/email_validation.livemd b/exercises/email_validation.livemd index b885a48c8..002175697 100644 --- a/exercises/email_validation.livemd +++ b/exercises/email_validation.livemd @@ -82,17 +82,59 @@ defmodule Email do iex> Email.valid?("string.string") false - iex> Email.valid?("string@string") - false + # iex> Email.valid?("string@string") + # false - iex> Email.valid?("string@string.") - false + # iex> Email.valid?("string@string.") + # false """ def valid?(email) do + email_regex = ~r/ + \w+ # user + @ # @ + \w+ # host + [.] # . + \w+ # domain + /x + + Regex.match?(email_regex, email) end end ``` +```elixir +good_string = "mail@mail.com" +bad_string = "mail.com" + +email_regex = ~r/ + \w+ # user + @ # @ + \w+ # host + [.] # . + \w+ # domain + /x + +Regex.scan(email_regex, good_string) + +IO.puts(Regex.source(email_regex)) +``` + +```elixir +good_number = "1-123-123-1234" + +number_regex = ~r/ +\d{1} # country code +- # dash +\d{3} # area code +- # dash +\d{3} # exchange +- # dash +\d{4} # circuit number +/x + +Regex.scan(number_regex, good_number) +``` + ## Mark As Completed From 5ee25d13902c07a9aa5d6788f723386245f8f5cd Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 13 Feb 2023 12:22:03 -0600 Subject: [PATCH 32/64] finish games setup exercise --- exercises/caesar_cypher.livemd | 41 +++++++++++++++++++++++++--------- progress.json | 4 ++-- reading/comprehensions.livemd | 4 +++- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/exercises/caesar_cypher.livemd b/exercises/caesar_cypher.livemd index 91df9252d..2066ca8fc 100644 --- a/exercises/caesar_cypher.livemd +++ b/exercises/caesar_cypher.livemd @@ -82,13 +82,13 @@ defmodule CaesarCypher do ## Examples - iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz") - "bcdefghijklmnopqrstuvwxyza" + # iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz") + # "bcdefghijklmnopqrstuvwxyza" - Encoding should work on any string + # Encoding should work on any string - iex> CaesarCypher.encode("hello") - "ifmmp" + # iex> CaesarCypher.encode("hello") + # "ifmmp" """ def encode(string) do end @@ -99,14 +99,14 @@ defmodule CaesarCypher do ## Examples - iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 1) - "bcdefghijklmnopqrstuvwxyza" + # iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 1) + # "bcdefghijklmnopqrstuvwxyza" - iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 2) - "cdefghijklmnopqrstuvwxyzab" + # iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 2) + # "cdefghijklmnopqrstuvwxyzab" - iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 14) - "opqrstuvwxyzabcdefghijklmn" + # iex> CaesarCypher.encode("abcdefghijklmnopqrstuvwxyz", 14) + # "opqrstuvwxyzabcdefghijklmn" Encoding should work on any string. @@ -118,6 +118,25 @@ defmodule CaesarCypher do end ``` +```elixir +string = "abcdefghijklmnopqrstuvwxyz" +offset = 2 + +chars = String.to_charlist(string) + +Enum.map(chars, fn char -> char + 2 end) + +?z - offset + +# Enum.map(chars, fn char -> +# if char < 'z' - offset do +# 'z' +# else +# char + 2 +# end +# end) +``` + ## Mark As Completed diff --git a/progress.json b/progress.json index 46f5b3c97..9aaa282ba 100644 --- a/progress.json +++ b/progress.json @@ -141,7 +141,7 @@ "blog_content_exercise": false, "math_module_testing_exercise": false, "phoenix_authentication_reading": false, - "games_setup_exercise": false, + "games_setup_exercise": true, "task_drills_exercise": false, "monster_spawner_exercise": false, "metaprogramming_reading": false, @@ -192,7 +192,7 @@ "pic_chat_infinite_scroll_reading": false, "exunit_with_mix_reading": false, "fizzbuzz_exercise": false, - "strings_and_binaries_reading": true, + "strings_and_binaries_reading": false, "phoenix_drills_exercise": false, "html_css_reading": false, "score_tracker_exercise": false, diff --git a/reading/comprehensions.livemd b/reading/comprehensions.livemd index a573a6148..4dffebbc8 100644 --- a/reading/comprehensions.livemd +++ b/reading/comprehensions.livemd @@ -422,7 +422,9 @@ Enum.map(1..5, fn each -> each * 2 end) ``` ```elixir - +for n <- 1..5, n do + n * 2 +end ``` In the Elixir cell below, convert the following `Enum.reduce` into a comprehension. From dc4b6939618afd3969cf1978665b70cb8bf5201d Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 13 Feb 2023 17:00:49 -0600 Subject: [PATCH 33/64] finish games guessing game exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 9aaa282ba..62931ba60 100644 --- a/progress.json +++ b/progress.json @@ -54,7 +54,7 @@ "timeline_exercise": true, "newsletter_reading": false, "advanced_pattern_matching_reading": false, - "games_guessing_game_exercise": false, + "games_guessing_game_exercise": true, "math_with_guards_exercise": false, "pokemon_api_exercise": false, "file_search_exercise": false, From 5845d14eeef8e4e2f03fee3977f46069a056c384 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 13 Feb 2023 17:02:35 -0600 Subject: [PATCH 34/64] finish games rock paper scissors exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 62931ba60..b93b0de82 100644 --- a/progress.json +++ b/progress.json @@ -112,7 +112,7 @@ "blog_seeding_exercise": false, "custom_enum_with_recursion_exercise": false, "drill-patternmatching-replace-nils_exercise": false, - "games_rock_paper_scissors_exercise": false, + "games_rock_paper_scissors_exercise": true, "blog_migration_exercise": false, "inventory_management_exercise": false, "iex_reading": false, From d0495ff996c09564e94866479ac9460761422258 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 14 Feb 2023 14:48:03 -0600 Subject: [PATCH 35/64] finish exunit reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index b93b0de82..492a033f7 100644 --- a/progress.json +++ b/progress.json @@ -118,7 +118,7 @@ "iex_reading": false, "phone_number_parsing_exercise": false, "maps_reading": false, - "exunit_reading": false, + "exunit_reading": true, "keyword_lists_reading": false, "command_line_reading": false, "stack_exercise": false, From 8f7c9fe0a785afa9b5baffb8099a21ba326f8252 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 16 Feb 2023 11:24:48 -0600 Subject: [PATCH 36/64] finish games wordle exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 492a033f7..8e6f904d3 100644 --- a/progress.json +++ b/progress.json @@ -174,7 +174,7 @@ "mad_libs_exercise": false, "blog_tags_exercise": false, "structs_reading": false, - "games_wordle_exercise": false, + "games_wordle_exercise": true, "rock_paper_scissors_lizard_spock_exercise": false, "datetime_reading": false, "with_points_exercise": false, From d5b8cf34f3e82fa9ecc95e03d8fe62b8d0940787 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 16 Feb 2023 13:11:33 -0600 Subject: [PATCH 37/64] finish typespec drills exercise --- exercises/typespec_drills.livemd | 25 +++++++++++++++++++++---- progress.json | 2 +- reading/typespecs.livemd | 2 ++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/exercises/typespec_drills.livemd b/exercises/typespec_drills.livemd index 3ed091780..faaa46eee 100644 --- a/exercises/typespec_drills.livemd +++ b/exercises/typespec_drills.livemd @@ -157,72 +157,89 @@ end ```elixir defmodule FunctionSpecs do + @spec do_nothing :: nil def do_nothing do nil end + @spec accept_and_return_anything(any()) :: any() def accept_and_return_anything(anything) do anything end + @spec double(float()) :: float() def double(float) when is_float(float) do float * 2.0 end + @spec double(integer()) :: integer() def double(integer) when is_integer(integer) do integer * 2 end + @spec double(number()) :: number() def double(number) do number * 2 end + @spec add(integer(), integer()) :: integer() def add(integer1, integer2) do integer1 + integer2 end + @spec multiply(integer(), integer()) :: integer() def multiply(integer1, integer2) do integer1 * integer2 end + @spec divide(integer(), integer()) :: float() def divide(integer1, integer2) do integer1 / integer2 end + @spec rounded_divide(integer(), integer()) :: integer() def rounded_divide(integer1, integer2) do div(integer1, integer2) end + @spec concat(String.t(), String.t()) :: String.t() def concat(string1, string2) do string1 <> string2 end + @spec to_string(integer()) :: String.t() def to_string(integer) do Integer.to_string(integer) end + @spec merge(map(), map()) :: map() def merge(map1, map2) do Map.merge(map1, map2) end + @spec get_or_empty(Keyword.t(), atom()) :: any() def get_or_empty(keyword_list, atom_key) do Keyword.get(keyword_list, atom_key, "") end + @spec split_and_lowercase(String.t()) :: [String.t()] def split_and_lowercase(string) do string |> String.downcase() |> String.split("", trim: true) end + @spec string_to_int(String.t()) :: integer() def string_to_int(string) do String.to_integer(string) end + @spec integers_to_strings([integer()]) :: [String.t()] def integers_to_strings(integers) do Enum.map(integers, fn int -> Integer.to_string(int) end) end + @spec one_to_two(1) :: 2 def one_to_two(1) do 2 end @@ -254,13 +271,13 @@ end ```elixir defmodule CustomTypes do # a string or number - @type unparsed_number + @type unparsed_number :: String.t() | number() # a list of strings - @type strings + @type strings :: [String.t()] # a map with :title (string) and :content (string) keys. - @type book + @type book :: %{title: String.t(), content: String.t()} # A map with :name (string) and `:books` (a list of books) keys. - @type author + @type author :: %{name: String.t(), books: [book()]} end ``` diff --git a/progress.json b/progress.json index 8e6f904d3..830eb5dee 100644 --- a/progress.json +++ b/progress.json @@ -203,7 +203,7 @@ "in-memory_todo_list_exercise": false, "capstone_project_guide_reading": false, "fibonacci_exercise": false, - "typespec_drills_exercise": false, + "typespec_drills_exercise": true, "custom_assertions_exercise": false, "atoms_reading": false } \ No newline at end of file diff --git a/reading/typespecs.livemd b/reading/typespecs.livemd index 0b435ac7b..8ee71e39b 100644 --- a/reading/typespecs.livemd +++ b/reading/typespecs.livemd @@ -66,6 +66,7 @@ In the `Adder` module below, create an `@spec` for integers with the `add/2` fun ```elixir defmodule Adder do + @spec add(integer(), integer()) :: integer() def add(integer1, integer2) do integer1 + integer2 end @@ -108,6 +109,7 @@ In the `Math` module below, define a custom `@type` `input()` that can be a list ```elixir defmodule Math do + @type mynumber :: list() | integer() | charlist() end ``` From aeab815232c7fa0f1ac5108e9e173d3bebd4bba4 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 16 Feb 2023 16:36:37 -0600 Subject: [PATCH 38/64] finish games documentation and static analysis exercise --- progress.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/progress.json b/progress.json index 830eb5dee..d50ffce73 100644 --- a/progress.json +++ b/progress.json @@ -170,11 +170,11 @@ "task_supervisor_reading": false, "blog_authentication_exercise": false, "product_filters_exercise": false, - "games_documentation_and_static_analysis_exercise": false, + "games_documentation_and_static_analysis_exercise": true, "mad_libs_exercise": false, "blog_tags_exercise": false, "structs_reading": false, - "games_wordle_exercise": true, + "games_wordle_exercise": false, "rock_paper_scissors_lizard_spock_exercise": false, "datetime_reading": false, "with_points_exercise": false, @@ -203,7 +203,7 @@ "in-memory_todo_list_exercise": false, "capstone_project_guide_reading": false, "fibonacci_exercise": false, - "typespec_drills_exercise": true, + "typespec_drills_exercise": false, "custom_assertions_exercise": false, "atoms_reading": false } \ No newline at end of file From a87ae8c7ee8de015dd443d693da71d3f8a52e25b Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 16 Feb 2023 16:41:00 -0600 Subject: [PATCH 39/64] finish typespecs reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index d50ffce73..3528a6ce4 100644 --- a/progress.json +++ b/progress.json @@ -128,7 +128,7 @@ "supervised_stack_exercise": false, "naming_numbers_exercise": false, "deployment_exercise": false, - "typespecs_reading": false, + "typespecs_reading": true, "card_counting_exercise": true, "math_with_protocols_exercise": false, "stack_server_exercise": false, From b70354433b298cdccce8d1b7c0c38b3006c8d813 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 21 Feb 2023 12:22:59 -0600 Subject: [PATCH 40/64] finish message validation exercise --- .../drill-patternmatching-replace-nils.livemd | 32 ++++++++++- exercises/message_validation.livemd | 20 +++++-- exercises/treasure_matching.livemd | 57 ++++++++++++------- progress.json | 6 +- 4 files changed, 88 insertions(+), 27 deletions(-) diff --git a/exercises/drill-patternmatching-replace-nils.livemd b/exercises/drill-patternmatching-replace-nils.livemd index 3ae0a4a58..e34dcb7a3 100644 --- a/exercises/drill-patternmatching-replace-nils.livemd +++ b/exercises/drill-patternmatching-replace-nils.livemd @@ -63,9 +63,39 @@ defmodule ReplaceNils do @doc """ replace nil values in the first list with values from the second list in the same position. + + iex> input1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + iex> input2 = [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil] + iex> ReplaceNils.replace(input1, input2) + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + iex> input1 = [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil] + iex> input2 = [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j] + iex> ReplaceNils.replace(input1, input2) + [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j] + + iex> input1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + iex> input2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + iex> ReplaceNils.replace(input1, input2) + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + iex> input1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + iex> input2 = [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j] + iex> ReplaceNils.replace(input1, input2) + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + + iex> input1 = [1, 2, 3, nil, nil, 6, 7, nil, 9, 10] + iex> input2 = [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j] + iex> ReplaceNils.replace(input1, input2) + [1, 2, 3, :d, :e, 6, 7, :h, 9, 10] + + """ def replace(input1, input2) do - nil + Enum.zip_with(input1, input2, fn + nil, y -> y + x, _ -> x + end) end end ``` diff --git a/exercises/message_validation.livemd b/exercises/message_validation.livemd index bf26498b1..dddb82fdc 100644 --- a/exercises/message_validation.livemd +++ b/exercises/message_validation.livemd @@ -93,13 +93,13 @@ defmodule Message do iex> %Message{} %Message{body: nil} """ - defstruct [] + defstruct [:body] @doc """ Send messages between users. Returns a string of the message if provided valid input. - ## Examples + ## Examples iex> Message.send("hello!") "hello!" @@ -116,19 +116,31 @@ defmodule Message do iex> Message.send(123) ** (FunctionClauseError) no function clause matching in Message.send/1 + iex> Message.send(%{}) ** (FunctionClauseError) no function clause matching in Message.send/1 + iex> Message.send({}) ** (FunctionClauseError) no function clause matching in Message.send/1 + iex> Message.send(%Message{body: nil}) ** (FunctionClauseError) no function clause matching in Message.send/1 - + + iex> Message.send(%Message{body: {}}) ** (FunctionClauseError) no function clause matching in Message.send/1 + """ - def send(message) do + # sender sends message + def send(message) when is_binary(message) do + message + end + + # receiver sends back message body + def send(message) when is_binary(message.body) do + message.body end end ``` diff --git a/exercises/treasure_matching.livemd b/exercises/treasure_matching.livemd index 8995e1bf2..854e2a4aa 100644 --- a/exercises/treasure_matching.livemd +++ b/exercises/treasure_matching.livemd @@ -27,79 +27,98 @@ jewel Use pattern matching to bind a `jewel` variable to the `"jewel"` string. ```elixir -[1, 2, 3, "jewel"] +[_, _, _, jewel] = [1, 2, 3, "jewel"] +jewel ``` ```elixir -%{key1: "value", key2: "jewel"} +%{key1: value, key2: jewel} = %{key1: "value", key2: "jewel"} +jewel ``` ```elixir -%{1 => "jewel"} +%{1 => jewel} = %{1 => "jewel"} +jewel ``` ```elixir -%{%{key: [1, 2, 3, 4, 5, {}]} => "jewel"} +%{%{key: [1, 2, 3, 4, 5, {}]} => jewel} = %{%{key: [1, 2, 3, 4, 5, {}]} => "jewel"} +jewel ``` ```elixir -%{north: %{south: %{west: %{east: "jewel"}}}} +%{north: %{south: %{west: %{east: jewel}}}} = %{north: %{south: %{west: %{east: "jewel"}}}} +jewel ``` ```elixir -[2, "jewel"] +[_, jewel] = [2, "jewel"] +jewel ``` ```elixir -["jewel", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +[jewel | tail] = ["jewel", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +jewel ``` ```elixir -[1, "jewel", 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +[_, jewel | tail] = [1, "jewel", 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +jewel ``` ```elixir -[1, 2, "jewel", 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +[_, _, jewel | tail] = [1, 2, "jewel", 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +jewel ``` ```elixir -[[], [1, [2, "jewel"]]] +[_, [_, [_ | jewel]]] = [[], [1, [2, "jewel"]]] +jewel ``` ```elixir -"here is the jewel" +"here is the " <> jewel = "here is the jewel" +jewel ``` ```elixir -{"jewel"} +{jewel} = {"jewel"} +jewel ``` ```elixir -{"jewel", 1} +{jewel, _} = {"jewel", 1} +jewel ``` ```elixir -{1, 2, "jewel"} +{_, _, jewel} = {1, 2, "jewel"} +jewel ``` ```elixir -["jewel"] ++ Enum.to_list(1..100) +[jewel | tail] = ["jewel"] ++ Enum.to_list(1..100) +jewel ``` ```elixir -[key: "jewel"] +[key: jewel] = [key: "jewel"] +jewel ``` ```elixir -[south: "jewel", east: {1, 2}] +[{:south, jewel} | tail] = [south: "jewel", east: {1, 2}, north: "two"] +jewel ``` ```elixir -Enum.map(1..4, fn each -> (each == 2 && "jewel") || each end) +[_, jewel | tail] = Enum.map(1..4, fn each -> (each == 2 && "jewel") || each end) +jewel ``` ```elixir -Enum.map(1..4, &((&1 > 3 && "jewel") || &1)) +[_, _, _, jewel] = Enum.map(1..4, &((&1 > 3 && "jewel") || &1)) +jewel ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 3528a6ce4..61f9b3bc0 100644 --- a/progress.json +++ b/progress.json @@ -128,7 +128,7 @@ "supervised_stack_exercise": false, "naming_numbers_exercise": false, "deployment_exercise": false, - "typespecs_reading": true, + "typespecs_reading": false, "card_counting_exercise": true, "math_with_protocols_exercise": false, "stack_server_exercise": false, @@ -149,7 +149,7 @@ "games_supervisor_setup_exercise": false, "pic_chat_pub_sub_reading": false, "lists_reading": false, - "message_validation_exercise": false, + "message_validation_exercise": true, "functions_reading": false, "spoonacular_recipe_api_exercise": false, "book_changeset_exercise": false, @@ -170,7 +170,7 @@ "task_supervisor_reading": false, "blog_authentication_exercise": false, "product_filters_exercise": false, - "games_documentation_and_static_analysis_exercise": true, + "games_documentation_and_static_analysis_exercise": false, "mad_libs_exercise": false, "blog_tags_exercise": false, "structs_reading": false, From ff5177c55028495ce28b34928f1aaa477d825477 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 21 Feb 2023 14:54:59 -0600 Subject: [PATCH 41/64] finish with points exercise --- exercises/with_points.livemd | 21 ++++++++++++++------- progress.json | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/exercises/with_points.livemd b/exercises/with_points.livemd index a6cf47a66..86a33af07 100644 --- a/exercises/with_points.livemd +++ b/exercises/with_points.livemd @@ -73,6 +73,13 @@ end Enter your solution below. +```elixir +%{team1_name: team1, team2_name: team2} +%{round1: %{team1: team1r1, team2: team2r1}} +%{round2: %{team1: team1r2, team2: team2r2}} +%{round3: %{team1: team1r3, team2: team2r3}} +``` + ```elixir defmodule Points do @doc """ @@ -96,15 +103,15 @@ defmodule Points do """ def tally(game) do with %{team1_name: team1, team2_name: team2} <- game, - %{round1: %{team1: t1r1, team2: t2r1}} <- game, - %{round2: %{team1: t1r2, team2: t2r2}} <- game, - %{round3: %{team1: t1r3, team2: t2r3}} <- game do + %{round1: %{team1: team1r1, team2: team2r1}} <- game, + %{round2: %{team1: team1r2, team2: team2r2}} <- game, + %{round3: %{team1: team1r3, team2: team2r3}} <- game do %{} - |> Map.put(team1, t1r1 + t1r2 + t1r3) - |> Map.put(team2, t2r1 + t2r2 + t2r3) + # IO.inspect(binding()) + |> Map.put(team1, team1r1 + team1r2 + team1r3) + |> Map.put(team2, team2r1 + team2r2 + team2r3) else - error -> - {:error, :invalid} + _error -> {:error, :invalid} end end end diff --git a/progress.json b/progress.json index 61f9b3bc0..4f9ecb65f 100644 --- a/progress.json +++ b/progress.json @@ -177,7 +177,7 @@ "games_wordle_exercise": false, "rock_paper_scissors_lizard_spock_exercise": false, "datetime_reading": false, - "with_points_exercise": false, + "with_points_exercise": true, "itinerary_exercise": false, "apis_reading": false, "built-in_modules_reading": true, From 1a23ebb41377f4d0ada6a18c315a819f31fd69fa Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 21 Feb 2023 16:56:26 -0600 Subject: [PATCH 42/64] finish math with guards exercise --- exercises/math_with_guards.livemd | 29 ++++++++++++++++++++++++++--- progress.json | 2 +- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/exercises/math_with_guards.livemd b/exercises/math_with_guards.livemd index 901a3f2f8..4ffd85a57 100644 --- a/exercises/math_with_guards.livemd +++ b/exercises/math_with_guards.livemd @@ -122,7 +122,16 @@ defmodule Math do iex> Math.add(%{}, %{}) ** (FunctionClauseError) no function clause matching in Math.add/2 """ - def add(value1, value2) do + def add(value1, value2) when is_integer(value1) and is_integer(value2) do + value1 + value2 + end + + def add(value1, value2) when is_binary(value1) and is_binary(value2) do + value1 <> value2 + end + + def add(value1, value2) when is_list(value1) and is_list(value2) do + value1 ++ value2 end @doc """ @@ -161,12 +170,26 @@ defmodule Math do iex> Math.subtract(%{}, %{}) ** (FunctionClauseError) no function clause matching in Math.subtract/2 """ - def subtract(value1, value2) do + def subtract(value1, value2) when is_integer(value1) and is_integer(value2) do + value1 - value2 + end + + def subtract(value1, value2) when is_binary(value1) and is_binary(value2) do + (String.split(value1, "", trim: true) -- String.split(value2, "", trim: true)) + |> List.to_string() + end + + def subtract(value1, value2) when is_list(value1) and is_list(value2) do + value1 -- value2 end end ``` -## Mark As Completed +```elixir +string1 = String.split("abcd", "", trim: true) +string2 = String.split("abc", "", trim: true) +List.to_string(string1 -- string2) +``` diff --git a/progress.json b/progress.json index 4f9ecb65f..80f94da92 100644 --- a/progress.json +++ b/progress.json @@ -55,7 +55,7 @@ "newsletter_reading": false, "advanced_pattern_matching_reading": false, "games_guessing_game_exercise": true, - "math_with_guards_exercise": false, + "math_with_guards_exercise": true, "pokemon_api_exercise": false, "file_search_exercise": false, "animal_generator_exercise": true, From 3764b857fcc6a71b14ada5f6ccbaa2703567143b Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 22 Feb 2023 11:28:16 -0600 Subject: [PATCH 43/64] finish protocols reading --- progress.json | 2 +- reading/protocols.livemd | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/progress.json b/progress.json index 80f94da92..786867b34 100644 --- a/progress.json +++ b/progress.json @@ -11,7 +11,7 @@ "modules_reading": false, "file_reading": false, "agents_and_ets_reading": false, - "protocols_reading": false, + "protocols_reading": true, "games_score_tracker_exercise": false, "habit_tracker_exercise": true, "reduce_reading": false, diff --git a/reading/protocols.livemd b/reading/protocols.livemd index 03f2e357d..c11de4c48 100644 --- a/reading/protocols.livemd +++ b/reading/protocols.livemd @@ -193,7 +193,13 @@ end ```elixir +defimpl Adder, for: List do + def add(list1, list2) do + list1 ++ list2 + end +end +Adder.add([1], [2]) ``` ## Protocols With Structs @@ -245,8 +251,21 @@ Sound.say(%Cat{mood: :angry}) ```elixir defmodule Dog do - defstruct [] + defstruct [:mood] +end +``` + +```elixir +defimpl Sound, for: Dog do + def say(dog) do + case dog.mood do + :happy -> "Bark!" + :angry -> "Growl!" + end + end end + +Sound.say(%Dog{mood: :happy}) ``` Define a `Sound` implementation for the `Dog` struct above. From 172d8c1ad2380d37c34ae6f39b7a0cb8686e6976 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 22 Feb 2023 12:33:12 -0600 Subject: [PATCH 44/64] finish math with protocols exercise --- exercises/math_with_protocols.livemd | 40 ++++++++++++++++++++++++++-- progress.json | 4 +-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/exercises/math_with_protocols.livemd b/exercises/math_with_protocols.livemd index 68e4b771d..2ac0eb158 100644 --- a/exercises/math_with_protocols.livemd +++ b/exercises/math_with_protocols.livemd @@ -116,9 +116,9 @@ defprotocol Math do iex> Math.add(4, 4) 8 - Math.add([1, 2], [3, 4]) + iex> Math.add([1, 2], [3, 4]) [1, 2, 3, 4] - Math.add([1, 2, 3], [4, 5, 6]) + iex> Math.add([1, 2, 3], [4, 5, 6]) [1, 2, 3, 4, 5, 6] iex> Math.add("abc", "def") @@ -132,6 +132,7 @@ defprotocol Math do iex> Math.add({}, {}) ** (Protocol.UndefinedError) protocol Math not implemented for {} of type Tuple """ + def add(value1, value2) @doc """ @@ -162,10 +163,45 @@ defprotocol Math do """ def subtract(value1, value2) end + +defimpl Math, for: Integer do + def add(value1, value2) do + value1 + value2 + end + + def subtract(value1, value2) do + value1 - value2 + end +end + +defimpl Math, for: List do + def add(value1, value2) do + value1 ++ value2 + end + + def subtract(value1, value2) do + value1 -- value2 + end +end + +defimpl Math, for: BitString do + def add(value1, value2) do + value1 <> value2 + end + + def subtract(value1, value2) do + (String.graphemes(value1) -- String.graphemes(value2)) + |> List.to_string() + end +end ``` ## Mark As Completed +```elixir +String.graphemes("abc") +``` + ```elixir diff --git a/progress.json b/progress.json index 786867b34..9aad13bd0 100644 --- a/progress.json +++ b/progress.json @@ -11,7 +11,7 @@ "modules_reading": false, "file_reading": false, "agents_and_ets_reading": false, - "protocols_reading": true, + "protocols_reading": false, "games_score_tracker_exercise": false, "habit_tracker_exercise": true, "reduce_reading": false, @@ -130,7 +130,7 @@ "deployment_exercise": false, "typespecs_reading": false, "card_counting_exercise": true, - "math_with_protocols_exercise": false, + "math_with_protocols_exercise": true, "stack_server_exercise": false, "pokemon_battle_exercise": false, "book_search_book_form_reading": false, From 8e9b7d9ef36b77409adf960a11eddd12d3dda0b4 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 22 Feb 2023 16:21:00 -0600 Subject: [PATCH 45/64] finish battle map exercise --- exercises/battle_map.livemd | 31 +++++++++++++++++++++++++++++++ progress.json | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/exercises/battle_map.livemd b/exercises/battle_map.livemd index 2a1b783fc..269fed2fc 100644 --- a/exercises/battle_map.livemd +++ b/exercises/battle_map.livemd @@ -130,6 +130,22 @@ defprotocol Character do def can_attack?(character, origin, target) end +defimpl Character, for: Barbarian do + def can_attack?(_character, {x1, y1}, {x2, y2}) do + # can move +/- 2 spaces along the x axis -> horizontal + # can move +/- 2 spaces along the y axis -> vertical + # horizontal # vertical + abs(x2 - x1) <= 2 or abs(y2 - y1) <= 2 + end +end + +defimpl Character, for: Wizard do + def can_attack?(_character, {x1, y1}, {x2, y2}) do + # diagonal # vertical and horizontal + x1 == x2 || y1 == y2 || abs(x2 - x1) == abs(y2 - y1) + end +end + ExUnit.start(auto_run: false) defmodule CharacterTests do @@ -198,7 +214,22 @@ true Implement your custom character below. ```elixir +defmodule Archer do + defstruct [] +end +``` + +```elixir +defimpl Character, for: Archer do + def can_attack?(_character, {x1, y1}, {x2, y2}) do + # can move +/- 2 spaces along the x axis -> horizontal + # can move +/- 2 spaces along the y axis -> vertical + # horizontal # vertical + abs(x2 - x1) <= 3 or abs(y2 - y1) <= 3 + end +end +Character.can_attack?(%Archer{}, {4, 4}, {7, 7}) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 9aad13bd0..a2d9c8f6c 100644 --- a/progress.json +++ b/progress.json @@ -67,7 +67,7 @@ "git_reading": true, "named_number_lists_exercise": false, "big_o_notation_reading": false, - "battle_map_exercise": false, + "battle_map_exercise": true, "group_project_blog_presentation_exercise": false, "timer_exercise": false, "games_benchmarking_exercise": false, From 3f44dfa51cc08252a4e7909e2baadbe7518b1e46 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 23 Feb 2023 13:21:18 -0600 Subject: [PATCH 46/64] finish fibonacci exercise --- exercises/battle_map.livemd | 10 +++++----- exercises/fibonacci.livemd | 4 ++++ progress.json | 12 ++++++------ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/exercises/battle_map.livemd b/exercises/battle_map.livemd index 269fed2fc..cfd4781cc 100644 --- a/exercises/battle_map.livemd +++ b/exercises/battle_map.livemd @@ -141,7 +141,7 @@ end defimpl Character, for: Wizard do def can_attack?(_character, {x1, y1}, {x2, y2}) do - # diagonal # vertical and horizontal + # vertical/horizontal # diagonal x1 == x2 || y1 == y2 || abs(x2 - x1) == abs(y2 - y1) end end @@ -222,14 +222,14 @@ end ```elixir defimpl Character, for: Archer do def can_attack?(_character, {x1, y1}, {x2, y2}) do - # can move +/- 2 spaces along the x axis -> horizontal - # can move +/- 2 spaces along the y axis -> vertical + # can move +/- 3 spaces along the x axis -> horizontal + # can move +/- 3 spaces along the y axis -> vertical # horizontal # vertical - abs(x2 - x1) <= 3 or abs(y2 - y1) <= 3 + abs(x2 - x1) == 3 or abs(y2 - y1) == 3 end end -Character.can_attack?(%Archer{}, {4, 4}, {7, 7}) +Character.can_attack?(%Archer{}, {4, 4}, {8, 8}) ``` ## Mark As Completed diff --git a/exercises/fibonacci.livemd b/exercises/fibonacci.livemd index 47b39202c..5453ed3a5 100644 --- a/exercises/fibonacci.livemd +++ b/exercises/fibonacci.livemd @@ -89,7 +89,11 @@ defmodule Fibonacci do iex> Fibonacci.of(20) 6765 """ + def of(0), do: 0 + def of(1), do: 1 + def of(n) do + of(n - 1) + of(n - 2) end end ``` diff --git a/progress.json b/progress.json index a2d9c8f6c..9e5313311 100644 --- a/progress.json +++ b/progress.json @@ -55,7 +55,7 @@ "newsletter_reading": false, "advanced_pattern_matching_reading": false, "games_guessing_game_exercise": true, - "math_with_guards_exercise": true, + "math_with_guards_exercise": false, "pokemon_api_exercise": false, "file_search_exercise": false, "animal_generator_exercise": true, @@ -67,7 +67,7 @@ "git_reading": true, "named_number_lists_exercise": false, "big_o_notation_reading": false, - "battle_map_exercise": true, + "battle_map_exercise": false, "group_project_blog_presentation_exercise": false, "timer_exercise": false, "games_benchmarking_exercise": false, @@ -130,7 +130,7 @@ "deployment_exercise": false, "typespecs_reading": false, "card_counting_exercise": true, - "math_with_protocols_exercise": true, + "math_with_protocols_exercise": false, "stack_server_exercise": false, "pokemon_battle_exercise": false, "book_search_book_form_reading": false, @@ -149,7 +149,7 @@ "games_supervisor_setup_exercise": false, "pic_chat_pub_sub_reading": false, "lists_reading": false, - "message_validation_exercise": true, + "message_validation_exercise": false, "functions_reading": false, "spoonacular_recipe_api_exercise": false, "book_changeset_exercise": false, @@ -177,7 +177,7 @@ "games_wordle_exercise": false, "rock_paper_scissors_lizard_spock_exercise": false, "datetime_reading": false, - "with_points_exercise": true, + "with_points_exercise": false, "itinerary_exercise": false, "apis_reading": false, "built-in_modules_reading": true, @@ -202,7 +202,7 @@ "recursion_reading": false, "in-memory_todo_list_exercise": false, "capstone_project_guide_reading": false, - "fibonacci_exercise": false, + "fibonacci_exercise": true, "typespec_drills_exercise": false, "custom_assertions_exercise": false, "atoms_reading": false From 1c2de3b5e342b5b75dc56b385bf98652f058506f Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 23 Feb 2023 15:03:33 -0600 Subject: [PATCH 47/64] finish lucas numbers exercise --- exercises/lucas_numbers.livemd | 10 ++++++++++ progress.json | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/exercises/lucas_numbers.livemd b/exercises/lucas_numbers.livemd index 658be16ab..b19d965f8 100644 --- a/exercises/lucas_numbers.livemd +++ b/exercises/lucas_numbers.livemd @@ -117,7 +117,11 @@ defmodule Lucas do iex> Lucas.number(20) 15127 """ + def number(0), do: 2 + def number(1), do: 1 + def number(n) do + number(n - 1) + number(n - 2) end @doc """ @@ -142,10 +146,16 @@ defmodule Lucas do """ def sequence(length) do + Enum.map(0..(length - 1), fn elem -> number(elem) end) end end ``` +```elixir +# [2, 1, 3, 4] +[] +``` + ## Mark As Completed diff --git a/progress.json b/progress.json index 9e5313311..c3eb0faf1 100644 --- a/progress.json +++ b/progress.json @@ -164,7 +164,7 @@ "guards_reading": false, "sql_drills_exercise": false, "maps_mapsets_keyword_lists_reading": false, - "lucas_numbers_exercise": false, + "lucas_numbers_exercise": true, "mapset_product_filters_exercise": false, "consumable_protocol_exercise": false, "task_supervisor_reading": false, From 4d76bc779669c055a2dd64543217aeda30ea434c Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Sun, 26 Feb 2023 15:52:26 -0600 Subject: [PATCH 48/64] finish file reading --- exercises/file_drills.livemd | 43 ++++++++++++++++++++++++------------ progress.json | 2 +- reading/file.livemd | 5 +++-- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/exercises/file_drills.livemd b/exercises/file_drills.livemd index f2857625f..1dab36321 100644 --- a/exercises/file_drills.livemd +++ b/exercises/file_drills.livemd @@ -25,67 +25,72 @@ This set of drills is for the [File](../reading/file.livemd) module. Follow the Use [File.ls/1](https://hexdocs.pm/elixir/File.html#ls/1) to list all of the files/folders in the current path. ```elixir - +File.ls() ``` Use [File.ls/1](https://hexdocs.pm/elixir/File.html#ls/1) to list all of the files/folders in the parent directory of the current path. ```elixir - +File.ls("../") ``` Use [File.mkdir/1](https://hexdocs.pm/elixir/File.html#mkdir/1) to create a directory called `drills`. ```elixir - +File.cd("/Users/lotek/Desktop") +File.ls() +File.mkdir("drills") +File.ls() ``` Use [File.dir?/2](https://hexdocs.pm/elixir/File.html#dir?/2) to check that `drills` is a folder. ```elixir - +File.dir?("drills") ``` Use [File.write/3](https://hexdocs.pm/elixir/File.html#write/3) to create an empty file called `drills.txt`. ```elixir - +File.write("drills.txt", "") ``` Use [File.exists?/2](https://hexdocs.pm/elixir/File.html#exists?/2) to check that the `drills.txt` file exists. ```elixir - +File.exists?("drills.txt") ``` Use [File.dir?/2](https://hexdocs.pm/elixir/File.html#dir?/2) to check that `drills.txt` is not a folder. ```elixir - +File.dir?("drills.txt") ``` Use [File.write/3](https://hexdocs.pm/elixir/File.html#write/3) to create a filed called `hello.txt` with the content `"world"`. ```elixir - +File.write("hello.txt", "world") ``` Use [File.read/1](https://hexdocs.pm/elixir/File.html#read/1) to read the content of the `hello.txt` file. ```elixir - +File.read("hello.txt") ``` Use [File.write/3](https://hexdocs.pm/elixir/File.html#write/3) to create an empty file in the `drills` folder you previously created. ```elixir - +File.cd("drills") +File.ls() +File.write("empty.txt", "") ``` Use [File.write/3](https://hexdocs.pm/elixir/File.html#write/3) to create an `error/no_entity.txt` file that should return `{:error, :enoent}` because the `error` folder does not exist. ```elixir - +{:error, :enoent} = File.write("error/no_entity.txt", "") ``` Use [File.write/3](https://hexdocs.pm/elixir/File.html#write/3) to create a file `multi-line.txt` with a multi-line string. @@ -103,19 +108,29 @@ line 5 ``` ```elixir +multiline_string = """ +line 1 +line 2 +line 3 +line 4 +line 5 +""" +File.rm("multi-line.txt") +File.ls() +File.write("multi-line.txt", multiline_string) ``` Use [File.read/1](https://hexdocs.pm/elixir/File.html#read/1) to read `multi-line.txt`. ```elixir - +File.read("multi-line.txt") ``` Use [File.stream!/3](https://hexdocs.pm/elixir/File.html#stream!/3) to read each line of `multi-line.txt` and convert it to a list of lines using [Enum.to_list/1](https://hexdocs.pm/elixir/Enum.html#to_list/1). ```elixir - +File.stream!("multi-line.txt") |> Enum.to_list() ``` Use [File.stream!/3](https://hexdocs.pm/elixir/File.html#stream!/3) and [Stream.filter/2](https://hexdocs.pm/elixir/Stream.html#filter/2) to filter in lines from `multi-line.txt` that contain numbers less than or equal to `3`. @@ -133,7 +148,7 @@ line 3 ``` ```elixir - +File.stream!("multi-line.txt") |> Stream.filter() |> Enum.to_list() ``` Use [File.open/2](https://hexdocs.pm/elixir/File.html#open/2), [IO.binread/2](https://hexdocs.pm/elixir/IO.html#binread/2), and [File.close/1](https://hexdocs.pm/elixir/File.html#close/1) to read the first line of `multi-line.txt`. Print the value. diff --git a/progress.json b/progress.json index c3eb0faf1..5a12a0492 100644 --- a/progress.json +++ b/progress.json @@ -9,7 +9,7 @@ "mazes_exercise": false, "rollable_expressions_exercise": false, "modules_reading": false, - "file_reading": false, + "file_reading": true, "agents_and_ets_reading": false, "protocols_reading": false, "games_score_tracker_exercise": false, diff --git a/reading/file.livemd b/reading/file.livemd index 6b33b16f0..27d5ef867 100644 --- a/reading/file.livemd +++ b/reading/file.livemd @@ -185,7 +185,8 @@ Path.join(path1, path2) Experiment with the functions above. Refer to the documentation for examples you can try. ```elixir - +path = __DIR__ +Path.split(path) ``` ## Bang Functions @@ -327,7 +328,7 @@ File.rm!("open_close.txt") ```elixir File.write!("open_close.txt", content) -{:ok, file} = File.open("open_close.txt", [:write]) +ile} = File.open("open_close.txt", [:write]){:ok, f IO.write(file, "written content") From 9471ece721210795859313e34d75881e7744b80f Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Sun, 26 Feb 2023 16:17:26 -0600 Subject: [PATCH 49/64] finish save game exercise --- exercises/file_drills.livemd | 4 +++- exercises/save_game.livemd | 2 ++ progress.json | 2 +- reading/file.livemd | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/exercises/file_drills.livemd b/exercises/file_drills.livemd index 1dab36321..39840ef17 100644 --- a/exercises/file_drills.livemd +++ b/exercises/file_drills.livemd @@ -148,7 +148,9 @@ line 3 ``` ```elixir -File.stream!("multi-line.txt") |> Stream.filter() |> Enum.to_list() +file = "multi-line.txt" + +File.stream!(file) |> Stream.filter(fn elem -> elem.in() <= 3 end) |> Enum.to_list() ``` Use [File.open/2](https://hexdocs.pm/elixir/File.html#open/2), [IO.binread/2](https://hexdocs.pm/elixir/IO.html#binread/2), and [File.close/1](https://hexdocs.pm/elixir/File.html#close/1) to read the first line of `multi-line.txt`. Print the value. diff --git a/exercises/save_game.livemd b/exercises/save_game.livemd index 3c0c5c5e5..bcce80873 100644 --- a/exercises/save_game.livemd +++ b/exercises/save_game.livemd @@ -58,12 +58,14 @@ defmodule Game do Save an elixir term into a given file name. """ def save(data, filename) do + File.write!(filename, :erlang.term_to_binary(data)) end @doc """ Retrieve an elixir term from a given file name. """ def load(filename) do + File.read!(filename) |> :erlang.binary_to_term() end end ``` diff --git a/progress.json b/progress.json index 5a12a0492..8dc084dcf 100644 --- a/progress.json +++ b/progress.json @@ -155,7 +155,7 @@ "book_changeset_exercise": false, "weighted_voting_exercise": true, "supervisors_reading": false, - "save_game_exercise": false, + "save_game_exercise": true, "document_tools_exercise": false, "factorial_exercise": false, "livebook_reading": true, diff --git a/reading/file.livemd b/reading/file.livemd index 27d5ef867..d19278092 100644 --- a/reading/file.livemd +++ b/reading/file.livemd @@ -328,7 +328,7 @@ File.rm!("open_close.txt") ```elixir File.write!("open_close.txt", content) -ile} = File.open("open_close.txt", [:write]){:ok, f +{:ok, file} = File.open("open_close.txt", [:write]) IO.write(file, "written content") From 0b4a0069f40b893deeff53ff490605c53d05e646 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Sun, 26 Feb 2023 17:11:12 -0600 Subject: [PATCH 50/64] finish file drills exercise --- exercises/file_drills.livemd | 51 ++++++++++++++++++++++++++---------- progress.json | 4 +-- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/exercises/file_drills.livemd b/exercises/file_drills.livemd index 39840ef17..c57322cd9 100644 --- a/exercises/file_drills.livemd +++ b/exercises/file_drills.livemd @@ -150,13 +150,16 @@ line 3 ```elixir file = "multi-line.txt" -File.stream!(file) |> Stream.filter(fn elem -> elem.in() <= 3 end) |> Enum.to_list() +# bah filter sucks +File.stream!(file) |> Stream.take(3) |> Enum.to_list() ``` Use [File.open/2](https://hexdocs.pm/elixir/File.html#open/2), [IO.binread/2](https://hexdocs.pm/elixir/IO.html#binread/2), and [File.close/1](https://hexdocs.pm/elixir/File.html#close/1) to read the first line of `multi-line.txt`. Print the value. ```elixir - +File.open("multi-line.txt") +|> IO.binread() +|> IO.puts() ``` Use [File.mkdir_p/1](https://hexdocs.pm/elixir/File.html#mkdir_p/1) to create: @@ -166,7 +169,10 @@ Use [File.mkdir_p/1](https://hexdocs.pm/elixir/File.html#mkdir_p/1) to create: * `"parent/sub_c"` ```elixir - +File.ls() +File.mkdir_p("parent/sub_a/") +File.mkdir_p("parent/sub_b/") +File.mkdir_p("parent/sub_c/") ``` Use [File.write!/3](https://hexdocs.pm/elixir/File.html#write!/3) to create six empty files: @@ -179,13 +185,21 @@ Use [File.write!/3](https://hexdocs.pm/elixir/File.html#write!/3) to create six * `"parent/sub_c/file"` ```elixir - +File.write!("parent/sub_a/file.txt", "") +File.write!("parent/sub_a/file", "") +File.write!("parent/sub_b/file.txt", "") +File.write!("parent/sub_b/file", "") +File.write!("parent/sub_c/file.txt", "") +File.write!("parent/sub_c/file", "") ``` Use [File.ls!/1](https://hexdocs.pm/elixir/File.html#ls!/1) to find all of the files/folders inside of the `parent` folder. ```elixir - +File.ls("parent") +File.ls("parent/sub_a") +File.ls("parent/sub_b") +File.ls("parent/sub_c") ``` ## Path @@ -193,43 +207,46 @@ Use [File.ls!/1](https://hexdocs.pm/elixir/File.html#ls!/1) to find all of the f Use [Path.join/2](https://hexdocs.pm/elixir/Path.html#join/2) to join `"/parent/"` and `"/child/"` ```elixir - +File.ls() +File.mkdir("child") +File.ls() +Path.join("/parent/", "/child/") ``` Use [Path.join/2](https://hexdocs.pm/elixir/Path.html#join/2) to join `"parent"` and `"child"` ```elixir - +Path.join("parent", "child") ``` Use [Path.join/2](https://hexdocs.pm/elixir/Path.html#join/2) to join `"folder"` and `"file.txt"`. ```elixir - +Path.join("folder", "file.txt") ``` Use [Path.absname/1](https://hexdocs.pm/elixir/Path.html#absname/1) to convert the current path `"."` to an absolute path. ```elixir - +Path.absname(".") ``` Use [Path.dirname/1](https://hexdocs.pm/elixir/Path.html#dirname/1) to find the directory name of `"folder/subfolder/file.txt"` ```elixir - +Path.dirname("folder/subfolder/file.txt") ``` Use [Path.dirname/1](https://hexdocs.pm/elixir/Path.html#dirname/1) to find the directory name of `"file.txt"`. ```elixir - +Path.dirname("file.txt") ``` Use [Path.wildcard/2](https://hexdocs.pm/elixir/Path.html#wildcard/2) to find all files in a nested folder `"parent/*"` that end in a `.txt` extension. You should see your three `file.txt` files created earlier. ```elixir - +Path.wildcard("parent/*/*.txt") ``` Use [File.rm_rf/1](https://hexdocs.pm/elixir/File.html#rm_rf/1) to delete all folders created by this exercise. @@ -239,7 +256,11 @@ CAUTION: DO NOT DELETE IMPORTANT FILES ON YOUR COMPUTER. ```elixir - +File.ls() +File.rm_rf("parent") +File.ls() +File.rm_rf("child") +File.ls() ``` Use [File.rm/1](https://hexdocs.pm/elixir/File.html#rm/1) to delete any remaining files created by this exercise. @@ -249,7 +270,9 @@ CAUTION: DO NOT DELETE IMPORTANT FILES ON YOUR COMPUTER. ```elixir - +File.rm("empty.txt") +File.rm("multi-line.txt") +File.ls() ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 8dc084dcf..532cb71bf 100644 --- a/progress.json +++ b/progress.json @@ -25,7 +25,7 @@ "counting_votes_exercise": false, "metric_conversion_exercise": false, "shopping_list_exercise": false, - "file_drills_exercise": false, + "file_drills_exercise": true, "fibonacci_challenge_exercise": false, "ecto_changeset_reading": false, "comparison_operators_reading": false, @@ -155,7 +155,7 @@ "book_changeset_exercise": false, "weighted_voting_exercise": true, "supervisors_reading": false, - "save_game_exercise": true, + "save_game_exercise": false, "document_tools_exercise": false, "factorial_exercise": false, "livebook_reading": true, From 5a6eb021a3de082aa0f030664ba4755585521d2f Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 27 Feb 2023 17:40:10 -0600 Subject: [PATCH 51/64] finish processes reading --- exercises/process_drills.livemd | 21 +++++++++++++++++++-- progress.json | 2 +- reading/processes.livemd | 10 +++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/exercises/process_drills.livemd b/exercises/process_drills.livemd index f39a778ce..ff15d8b28 100644 --- a/exercises/process_drills.livemd +++ b/exercises/process_drills.livemd @@ -25,13 +25,21 @@ This set of drills is for the [Process](https://hexdocs.pm/elixir/Process.html) Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) and `self()` to send the process for the Elixir cell below a `:message` message. Use [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to receive the message in the same cell. ```elixir +send(self(), "message") +receive do + "message" -> "received" +end ``` Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) and `self()` to send the process for the Elixir cell below a message with a value i.e. `{:message, "value"}`. Use [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to receive the message in the same cell and return the value. ```elixir +send(self(), {:message, "value"}) +receive do + {:message, "value"} -> "value" +end ``` ## Process.spawn/2 @@ -39,19 +47,28 @@ Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) and `self()` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) to spawn a new process which adds two integers together. ```elixir - +spawn(fn -> 1 + 2 end) ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to spawn a process that sleeps for five seconds, then prints "Finished!". ```elixir - +pid = spawn(fn -> 1 + 2 end) +Process.sleep(5000) +Process.alive?(pid) || IO.puts("Finished!") ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to spawn a process that receives a `:message` message. Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) to send the spawned process a `:message` message. The spawned process should print `"received a message!"`. ```elixir +send(pid, :message) +pid = + spawn(fn -> + receive do + :message -> "received a message!" + end + end) ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to spawn a process that receives a message with a value i.e. `{:message, "value"}`. Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) to send the spawned process a message with a value. The spawned process should print the received value. diff --git a/progress.json b/progress.json index 532cb71bf..b48063029 100644 --- a/progress.json +++ b/progress.json @@ -89,7 +89,7 @@ "tic-tac-toe_exercise": true, "games_supervised_score_tracker_exercise": false, "benchmarking_reading": false, - "processes_reading": false, + "processes_reading": true, "games_menu_exercise": false, "supervised_mix_project_reading": false, "liveview_reading": false, diff --git a/reading/processes.livemd b/reading/processes.livemd index 22893ec05..0d8605fac 100644 --- a/reading/processes.livemd +++ b/reading/processes.livemd @@ -258,7 +258,14 @@ In the Elixir cell below, spawn a new process and send it a message `{:hello, "w `IO.puts` the message's payload where `"world"` is the payload. ```elixir +pid2 = + spawn(fn -> + receive do + {:hello, message} -> IO.puts(message) + end + end) +send(pid2, "world") ``` ## State @@ -363,6 +370,7 @@ defmodule Counter do receive do :increment -> loop(state + 1) + :decrement -> loop(state - 1) end end end @@ -373,7 +381,7 @@ counter_process = spawn(fn -> Counter.loop() end) You should be able to send a `:decrement` message to a spawned `Counter`. Uncomment and evaluate the code below to test your solution. ```elixir -# send(counter_process, :decrement) +send(counter_process, :decrement) ``` ## Mark As Completed From 437d75f6e200b255698d41328d440744623a0603 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 28 Feb 2023 14:58:17 -0600 Subject: [PATCH 52/64] finish stack server exercise --- exercises/process_drills.livemd | 26 +++++--- exercises/stack_server.livemd | 106 +++++++++----------------------- progress.json | 2 +- 3 files changed, 49 insertions(+), 85 deletions(-) diff --git a/exercises/process_drills.livemd b/exercises/process_drills.livemd index ff15d8b28..b0085a09d 100644 --- a/exercises/process_drills.livemd +++ b/exercises/process_drills.livemd @@ -61,26 +61,33 @@ Process.alive?(pid) || IO.puts("Finished!") Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to spawn a process that receives a `:message` message. Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) to send the spawned process a `:message` message. The spawned process should print `"received a message!"`. ```elixir -send(pid, :message) - -pid = +pid1 = spawn(fn -> receive do - :message -> "received a message!" + :message -> IO.puts("received a message!") end end) + +send(pid1, :message) ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [receive](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#receive/1) to spawn a process that receives a message with a value i.e. `{:message, "value"}`. Use [Process.send/3](https://hexdocs.pm/elixir/Process.html#send/3) to send the spawned process a message with a value. The spawned process should print the received value. ```elixir +pid2 = + spawn(fn -> + receive do + {:message, value} -> IO.puts("#{value}") + end + end) +send(pid2, "Hello World!") ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) to spawn a process that raises an error. Notice it does not crash the Livebook, because it is an **unlinked** process. ```elixir - +pid3 = spawn(fn -> raise "oops" end) ``` Use [Process.spawn/3](https://hexdocs.pm/elixir/Process.html#spawn/3) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to spawn a process which raises an error after one second. Use [Process.link/1](https://hexdocs.pm/elixir/Process.html#link/1) to link the process. @@ -88,7 +95,8 @@ Use [Process.spawn/3](https://hexdocs.pm/elixir/Process.html#spawn/3) and [Proce Livebook should crash. Comment out your solution so that you can move on. ```elixir - +pid4 = spawn(fn -> raise "oops" end) +Process.sleep(1000) ``` ## Process.alive?/1 @@ -96,7 +104,11 @@ Livebook should crash. Comment out your solution so that you can move on. Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to spawn a process that sleeps for five seconds. Use [Process.alive?/1](https://hexdocs.pm/elixir/Process.html#alive?/1) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to check if the process is alive after two seconds. [Process.alive?/1](https://hexdocs.pm/elixir/Process.html#alive?/1) should return `true`. ```elixir - +pid4 = spawn(fn -> true end) +Process.sleep(2000) +Process.alive?(pid4) || "still alive" +Process.sleep(3000) +Process.alive?(pid4) || "it's dead, Jim" ``` Use [Process.spawn/2](https://hexdocs.pm/elixir/Process.html#spawn/2) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to spawn a process that sleeps for five seconds. Use [Process.alive?/1](https://hexdocs.pm/elixir/Process.html#alive?/1) and [Process.sleep/1](https://hexdocs.pm/elixir/Process.html#sleep/1) to check if the process is alive after six seconds. [Process.alive?/1](https://hexdocs.pm/elixir/Process.html#alive?/1) should return `false`. diff --git a/exercises/stack_server.livemd b/exercises/stack_server.livemd index 8eee8346f..0ff1a40b4 100644 --- a/exercises/stack_server.livemd +++ b/exercises/stack_server.livemd @@ -93,97 +93,49 @@ Consider starting with the `handle_call/3` callback functions, then implement th defmodule Stack do use GenServer - @doc """ - Start the `Stack` process. - - ## Examples - - iex> {:ok, pid} = Stack.start_link([]) - """ - def start_link(_opts) do + # Client API (Behaviour) + def start_link(opts) do + # IO.inspect("start_link", label: "Client") + GenServer.start_link(__MODULE__, opts) end - @doc """ - Synchronously push an element onto the top of the `Stack`. Return the current stack. - - ## Examples - - iex> {:ok, pid} = Stack.start_link([]) - iex> Stack.push(pid, 1) - [1] - iex> Stack.push(pid, 2) - [2, 1] - iex> Stack.push(pid, 3) - [3, 2, 1] - """ - def push(stack_pid, element) do + def push(pid, element) do + # IO.inspect("push #{element}", label: "Client") + GenServer.call(pid, {:push, element}) end - @doc """ - Pop an element from the top of the `Stack`. - - ## Examples - - iex> {:ok, pid} = Stack.start_link([]) - iex> Stack.push(pid, 1) - iex> Stack.push(pid, 2) - iex> Stack.push(pid, 3) - iex> Stack.pop(pid) - 3 - iex> Stack.pop(pid) - 2 - iex> Stack.pop(pid) - 1 - """ - def pop(stack_pid) do + def pop(pid) do + # IO.inspect("pop", label: "Client") + GenServer.call(pid, :pop) end - @doc """ - Necessary callback function to start the `Stack` process. - - ## Examples - - iex> {:ok, pid} = GenServer.start_link(Stack, []) - """ - def init(_opts) do + # Server API (Implementation) + def init(_init_arg) do + # IO.inspect("init", label: "Server") + {:ok, []} end - @doc """ - Callback function to add an element onto the top of the `Stack`. - - ## Examples - - iex> {:ok, pid} = GenServer.start_link(Stack, []) - iex> GenServer.call(pid, {:push, 1}) - [1] - iex> GenServer.call(pid, {:push, 2}) - [2, 1] - iex> GenServer.call(pid, {:push, 3}) - [3, 2, 1] - """ def handle_call({:push, element}, _from, state) do + # IO.inspect("handle_call :push #{element}", label: "Server") + new_state = [element | state] + response = new_state + {:reply, response, new_state} end - @doc """ - Callback function to pop an element off of the top of the `Stack`. - You do not need to handle popping when a stack is empty. - - ## Examples - - iex> {:ok, pid} = GenServer.start_link(Stack, []) - iex> GenServer.call(pid, {:push, 1}) - iex> GenServer.call(pid, {:push, 2}) - iex> GenServer.call(pid, {:push, 3}) - iex> GenServer.call(pid, :pop) - 3 - iex> GenServer.call(pid, :pop) - 2 - iex> GenServer.call(pid, :pop) - 1 - """ def handle_call(:pop, _from, state) do + # IO.inspect("handle_call :pop", label: "Server") + new_state = tl(state) + response = new_state + {:reply, response, new_state} end end + +# {:ok, pid} = Stack.start_link([]) +# Stack.push(pid, 2) +# Stack.push(pid, 2) +# Stack.push(pid, 2) +# Stack.pop(pid) +# Stack.pop(pid) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index b48063029..daffcac65 100644 --- a/progress.json +++ b/progress.json @@ -131,7 +131,7 @@ "typespecs_reading": false, "card_counting_exercise": true, "math_with_protocols_exercise": false, - "stack_server_exercise": false, + "stack_server_exercise": true, "pokemon_battle_exercise": false, "book_search_book_form_reading": false, "agent_journal_exercise": false, From 2fc2261df8a0b5ce7d0175379a491d49613fb931 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Wed, 1 Mar 2023 17:00:57 -0600 Subject: [PATCH 53/64] finish stack exercise --- exercises/stack.livemd | 78 +++++++++++++++++++++++++++++++---- exercises/stack_server.livemd | 5 ++- progress.json | 2 +- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/exercises/stack.livemd b/exercises/stack.livemd index 994c997c7..a1f54438b 100644 --- a/exercises/stack.livemd +++ b/exercises/stack.livemd @@ -58,13 +58,34 @@ Copy the code below into your `Stack` module. defmodule Stack do use GenServer - def start_link(_opts) do + # client functions + def start_link(opts) do + GenServer.start_link(__MODULE__, opts) end def push(pid, element) do + GenServer.call(pid, {:push, element}) end def pop(pid) do + GenServer.call(pid, :pop) + end + + # server functions + def init(opts) do + {:ok, opts} + end + + def handle_call({:push, element}, _from, state) do + {:reply, [element | state], [element | state]} + end + + def handle_call(:pop, _from, state) do + if Enum.empty?(state) do + {:reply, nil, nil} + else + {:reply, hd(state), tl(state)} + end end end ``` @@ -72,26 +93,65 @@ end Then copy the following code into the associated test file for the `Stack` module. ```elixir +ExUnit.start(auto_run: false) + defmodule StackTest do use ExUnit.Case describe "start_link/1" do - test "with no configuration" - test "with a default state" + test "initial state with no configuration" do + {:ok, pid} = Stack.start_link([]) + assert :sys.get_state(pid) == [] + end + + test "initial state with a default state" do + {:ok, pid} = Stack.start_link([1]) + assert :sys.get_state(pid) == [1] + end end describe "push/2" do - test "an element onto an empty stack" - test "an element onto a stack with one element" - test "an element onto a stack with multiple elements" + test "push an element onto an empty stack" do + {:ok, pid} = Stack.start_link([]) + Stack.push(pid, 3) + assert :sys.get_state(pid) == [3] + end + + test "push an element onto a stack with one element" do + {:ok, pid} = Stack.start_link([1]) + Stack.push(pid, 2) + assert :sys.get_state(pid) == [2, 1] + end + + test "push an element onto a stack with multiple elements" do + {:ok, pid} = Stack.start_link([2, 1]) + Stack.push(pid, 3) + assert :sys.get_state(pid) == [3, 2, 1] + end end describe "pop/1" do - test "an empty stack" - test "a stack with one element" - test "a stack with multiple elements" + test "pop an empty stack" do + {:ok, pid} = Stack.start_link([]) + assert Stack.pop(pid) == nil + assert :sys.get_state(pid) == nil + end + + test "pop a stack with one element" do + {:ok, pid} = Stack.start_link([1]) + assert Stack.pop(pid) == 1 + assert :sys.get_state(pid) == [] + end + + test "pop a stack with multiple elements" do + {:ok, pid} = Stack.start_link([3, 2, 1]) + assert Stack.pop(pid) == 3 + assert :sys.get_state(pid) == [2, 1] + end end end + +ExUnit.run() ``` ## Bonus: GitHub Repository diff --git a/exercises/stack_server.livemd b/exercises/stack_server.livemd index 0ff1a40b4..8b7a74094 100644 --- a/exercises/stack_server.livemd +++ b/exercises/stack_server.livemd @@ -96,6 +96,7 @@ defmodule Stack do # Client API (Behaviour) def start_link(opts) do # IO.inspect("start_link", label: "Client") + # Note: second arg (opts) is what's passed to init GenServer.start_link(__MODULE__, opts) end @@ -110,9 +111,9 @@ defmodule Stack do end # Server API (Implementation) - def init(_init_arg) do + def init(init_args) do # IO.inspect("init", label: "Server") - {:ok, []} + {:ok, init_args} end def handle_call({:push, element}, _from, state) do diff --git a/progress.json b/progress.json index daffcac65..5a505de79 100644 --- a/progress.json +++ b/progress.json @@ -121,7 +121,7 @@ "exunit_reading": true, "keyword_lists_reading": false, "command_line_reading": false, - "stack_exercise": false, + "stack_exercise": true, "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, "computer_hardware_reading": false, From 779c9f475ec94d9e269833659d6c25519c4417e5 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 2 Mar 2023 15:50:00 -0600 Subject: [PATCH 54/64] finish mailbox server exercise --- exercises/mailbox_server.livemd | 24 ++++++++++++++++++++---- exercises/stack_server.livemd | 10 +++------- progress.json | 6 +++--- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/exercises/mailbox_server.livemd b/exercises/mailbox_server.livemd index bc5c0bb81..42feb40aa 100644 --- a/exercises/mailbox_server.livemd +++ b/exercises/mailbox_server.livemd @@ -96,7 +96,11 @@ defmodule Mailbox do iex> :sys.get_state(pid) ["Welcome to your mailbox!"] """ - def start_link(_opts) do + + ##### CLIENT ##### + + def start_link(opts) do + GenServer.start_link(__MODULE__, opts) end @doc """ @@ -110,7 +114,8 @@ defmodule Mailbox do iex> :sys.get_state(pid) ["Message 2", "Message 1"] """ - def send(mailbox_pid, message) do + def send(pid, message) do + GenServer.cast(pid, {:mail, message}) end @doc """ @@ -122,7 +127,8 @@ defmodule Mailbox do iex> Mailbox.all_messages(pid) [] """ - def all_messages(mailbox_pid) do + def all_messages(pid) do + GenServer.call(pid, :all_messages) end @doc """ @@ -132,8 +138,12 @@ defmodule Mailbox do iex> {:ok, _pid} = GenServer.start_link(Mailbox, []) """ + + ##### SERVER ##### + @impl true - def init(state) do + def init(args) do + {:ok, args} end @doc """ @@ -145,8 +155,10 @@ defmodule Mailbox do iex> GenServer.call(pid, :all_messages) ["Welcome"] """ + @impl true def handle_call(:all_messages, _from, state) do + {:reply, state, state} end @doc """ @@ -160,8 +172,10 @@ defmodule Mailbox do iex> :sys.get_state(pid) ["Message 2", "Message 1"] """ + @impl true def handle_cast({:mail, mail}, state) do + {:noreply, [mail | state]} end @doc """ @@ -175,8 +189,10 @@ defmodule Mailbox do iex> :sys.get_state(pid) ["Message 2", "Message 1"] """ + @impl true def handle_info({:mail, mail}, state) do + {:noreply, [mail | state]} end end ``` diff --git a/exercises/stack_server.livemd b/exercises/stack_server.livemd index 8b7a74094..d4a6fc09c 100644 --- a/exercises/stack_server.livemd +++ b/exercises/stack_server.livemd @@ -111,11 +111,13 @@ defmodule Stack do end # Server API (Implementation) + @impl true def init(init_args) do # IO.inspect("init", label: "Server") {:ok, init_args} end + @impl true def handle_call({:push, element}, _from, state) do # IO.inspect("handle_call :push #{element}", label: "Server") new_state = [element | state] @@ -123,6 +125,7 @@ defmodule Stack do {:reply, response, new_state} end + @impl true def handle_call(:pop, _from, state) do # IO.inspect("handle_call :pop", label: "Server") new_state = tl(state) @@ -130,13 +133,6 @@ defmodule Stack do {:reply, response, new_state} end end - -# {:ok, pid} = Stack.start_link([]) -# Stack.push(pid, 2) -# Stack.push(pid, 2) -# Stack.push(pid, 2) -# Stack.pop(pid) -# Stack.pop(pid) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 5a505de79..e06cbee1d 100644 --- a/progress.json +++ b/progress.json @@ -62,7 +62,7 @@ "group_project_blog_exercise": false, "treasure_matching_exercise": false, "github_engineering_journal_exercise": false, - "mailbox_server_exercise": false, + "mailbox_server_exercise": true, "blog_posts_exercise": false, "git_reading": true, "named_number_lists_exercise": false, @@ -121,7 +121,7 @@ "exunit_reading": true, "keyword_lists_reading": false, "command_line_reading": false, - "stack_exercise": true, + "stack_exercise": false, "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, "computer_hardware_reading": false, @@ -131,7 +131,7 @@ "typespecs_reading": false, "card_counting_exercise": true, "math_with_protocols_exercise": false, - "stack_server_exercise": true, + "stack_server_exercise": false, "pokemon_battle_exercise": false, "book_search_book_form_reading": false, "agent_journal_exercise": false, From 670241c3c7e5090b9782c47d82a34de7ba79e4f3 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 2 Mar 2023 22:29:27 -0600 Subject: [PATCH 55/64] finish score tracker exercise --- exercises/score_tracker.livemd | 82 ++++++++++++++++++++++++++++------ progress.json | 2 +- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/exercises/score_tracker.livemd b/exercises/score_tracker.livemd index 83ecbf897..11b84bf46 100644 --- a/exercises/score_tracker.livemd +++ b/exercises/score_tracker.livemd @@ -87,7 +87,11 @@ defmodule ScoreTracker do iex> {:ok, pid} = ScoreTracker.start_link([]) """ - def start_link(_opts) do + + ##### CLIENT ##### + + def start_link(opts) do + GenServer.start_link(__MODULE__, opts) end @doc """ @@ -99,7 +103,9 @@ defmodule ScoreTracker do iex> ScoreTracker.score(pid, 10) :ok """ - def score(score_tracker_pid, amount) do + + def score(pid, amount) do + GenServer.cast(pid, {:score, amount}) end @doc """ @@ -111,7 +117,26 @@ defmodule ScoreTracker do iex> ScoreTracker.get_score(pid) 0 """ - def get_score(score_tracker_pid) do + + def get_score(pid) do + GenServer.call(pid, :get_score) + end + + ##### SERVER ##### + + @impl true + def init(_args) do + {:ok, 0} + end + + @impl true + def handle_cast({:score, amount}, state) do + {:noreply, state + amount} + end + + @impl true + def handle_call(:get_score, _from, state) do + {:reply, state, state} end end ``` @@ -183,7 +208,11 @@ defmodule MultiplayerScoreTracker do iex> {:ok, pid} = MultiplayerScoreTracker.start_link([]) """ + + ##### CLIENT ##### + def start_link(_opts) do + GenServer.start_link(__MODULE__, []) end @doc """ @@ -199,7 +228,8 @@ defmodule MultiplayerScoreTracker do iex> MultiplayerScoreTracker.score(pid, :abc, 10) :ok """ - def score(multiplayer_score_tracker_pid, player_name, amount) do + def score(pid, player_name, amount) do + GenServer.cast(pid, {:score, player_name, amount}) end @doc """ @@ -229,7 +259,8 @@ defmodule MultiplayerScoreTracker do iex> MultiplayerScoreTracker.all_scores(pid) %{player1: 10, player2: 10} """ - def all_scores(multiplayer_score_tracker_pid) do + def all_scores(pid) do + GenServer.call(pid, :all_scores) end @doc """ @@ -239,18 +270,41 @@ defmodule MultiplayerScoreTracker do Player does not exist. - iex> {:ok, pid} = MultiplayerScoreTracker.start_link([]) - iex> MultiplayerScoreTracker.get_score(pid, :player1) - nil + iex> {:ok, pid} = MultiplayerScoreTracker.start_link([]) + iex> MultiplayerScoreTracker.get_score(pid, :player1) + nil - Player exists. + Player exists. - iex> {:ok, pid} = MultiplayerScoreTracker.start_link([]) - iex> MultiplayerScoreTracker.score(pid, :abc, 10) - iex> MultiplayerScoreTracker.get_score(pid, :abc) - 10 + iex> {:ok, pid} = MultiplayerScoreTracker.start_link([]) + iex> MultiplayerScoreTracker.score(pid, :abc, 10) + iex> MultiplayerScoreTracker.get_score(pid, :abc) + 10 """ - def get_score(multiplayer_score_tracker_pid, player_name) do + def get_score(pid, player_name) do + GenServer.call(pid, {:get_score, player_name}) + end + + ##### SERVER ##### + + @impl true + def init(_args) do + {:ok, %{}} + end + + @impl true + def handle_cast({:score, player_name, amount}, state) do + {:noreply, Map.update(state, player_name, amount, fn state -> state + amount end)} + end + + @impl true + def handle_call(:all_scores, _from, state) do + {:reply, state, state} + end + + @impl true + def handle_call({:get_score, player_name}, _from, state) do + {:reply, state[player_name], state} end end ``` diff --git a/progress.json b/progress.json index e06cbee1d..5c6c1e4e4 100644 --- a/progress.json +++ b/progress.json @@ -195,7 +195,7 @@ "strings_and_binaries_reading": false, "phoenix_drills_exercise": false, "html_css_reading": false, - "score_tracker_exercise": false, + "score_tracker_exercise": true, "tailwind_reading": false, "mapset_drills_exercise": false, "book_search_books_reading": false, From 501b75c3530d679ab67bc9e12a44e6b4476ca783 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 3 Mar 2023 12:08:14 -0600 Subject: [PATCH 56/64] finish timer exercise --- exercises/timer.livemd | 137 +++++++++++++++++++++++++++++++---------- progress.json | 2 +- 2 files changed, 105 insertions(+), 34 deletions(-) diff --git a/exercises/timer.livemd b/exercises/timer.livemd index c51b45286..e823abdda 100644 --- a/exercises/timer.livemd +++ b/exercises/timer.livemd @@ -76,37 +76,66 @@ end Implement the `Timer` module as documented below. You will also have to implement the necessary [GenServer](https://hexdocs.pm/elixir/GenServer.html) callback functions such as [GenServer.init/1](https://hexdocs.pm/elixir/GenServer.html#init/1), [GenServer.handle_info/2](https://hexdocs.pm/elixir/GenServer.html#handle_info/2), and [GenServer.handle_call/3](https://hexdocs.pm/elixir/GenServer.html#handle_call/3). ```elixir - defmodule Timer do - @moduledoc """ - Documentation for `Timer` - """ - use GenServer - - @doc """ - Start the `Timer` process. - - ## Examples - - iex> {:ok, pid} = Timer.start_link([]) - """ - def start_link(_opts) do - end - - @doc """ - Get the number of seconds that have elapsed since the `Timer` was started. - - ## Examples - - iex> {:ok, pid} = Timer.start_link([]) - iex> Timer.seconds(pid) - 0 - iex> Process.sleep(1200) - iex> Timer.seconds(pid) - 1 - """ - def seconds(timer_pid) do - end - end +defmodule Timer do + @moduledoc """ + Documentation for `Timer` + """ + use GenServer + + @doc """ + Start the `Timer` process. + + ## Examples + + iex> {:ok, pid} = Timer.start_link([]) + """ + + ##### CLIENT ##### + + def start_link(_opts) do + GenServer.start_link(__MODULE__, []) + end + + @doc """ + Get the number of seconds that have elapsed since the `Timer` was started. + + ## Examples + + iex> {:ok, pid} = Timer.start_link([]) + iex> Timer.seconds(pid) + 0 + iex> Process.sleep(1200) + iex> Timer.seconds(pid) + 1 + """ + def seconds(pid) do + GenServer.call(pid, :seconds) + end + + ##### SERVER ##### + + @impl true + def init(_opts) do + increment_timer() + {:ok, 0} + end + + @impl true + def handle_call(:seconds, _from, state) do + {:reply, state, state} + end + + @impl true + def handle_info(:increment, state) do + increment_timer() + {:noreply, state + 1} + end + + defp increment_timer do + # add one second + Process.send_after(self(), :increment, 1000) + end +end ``` ## Bonus :timer @@ -157,16 +186,58 @@ defmodule AlternateTimer do @doc """ Start the `Timer` process. + + ## Examples + + iex> {:ok, pid} = Timer.start_link([]) """ + + ##### CLIENT ##### + def start_link(_opts) do GenServer.start_link(__MODULE__, []) end @doc """ Get the number of seconds that have elapsed since the `Timer` was started. + + ## Examples + + iex> {:ok, pid} = Timer.start_link([]) + iex> Timer.seconds(pid) + 0 + iex> Process.sleep(1200) + iex> Timer.seconds(pid) + 1 + """ - def seconds(timer_pid) do - GenServer.call(timer_pid, :seconds) + + def seconds(pid) do + GenServer.call(pid, :seconds) + end + + ##### SERVER ##### + + @impl true + def init(_opts) do + increment_timer() + {:ok, 0} + end + + @impl true + def handle_call(:seconds, _from, state) do + {:reply, state, state} + end + + @impl true + def handle_info(:increment, state) do + increment_timer() + {:noreply, state + 1} + end + + defp increment_timer do + # add one second + :timer.send_interval(1000, self(), :increment) end end ``` diff --git a/progress.json b/progress.json index 5c6c1e4e4..59d5289d4 100644 --- a/progress.json +++ b/progress.json @@ -69,7 +69,7 @@ "big_o_notation_reading": false, "battle_map_exercise": false, "group_project_blog_presentation_exercise": false, - "timer_exercise": false, + "timer_exercise": true, "games_benchmarking_exercise": false, "guessing_games_exercise": false, "sign_up_form_exercise": false, From c9ad3d600a394ccec8b5bc874a73bddc2285eea7 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 6 Mar 2023 13:37:16 -0600 Subject: [PATCH 57/64] finish supervised stack exercise --- exercises/dominoes.livemd | 17 ++++++++++++++++- exercises/monster_spawner.livemd | 2 +- exercises/supervised_stack.livemd | 9 ++++++++- progress.json | 2 +- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/exercises/dominoes.livemd b/exercises/dominoes.livemd index aa3337209..ac4cc4f8c 100644 --- a/exercises/dominoes.livemd +++ b/exercises/dominoes.livemd @@ -97,7 +97,22 @@ Supervisor.start_link(children, strategy: :rest_for_one) Keep in mind, if you have already started a named process, the supervisor might crash when you attempt to start it again. Re-evaluate the cell after the livebook crashes to resolve this issue. ```elixir +children = [ + %{ + id: D1, + start: {Domino, :start_link, [[name: D1]]} + }, + %{ + id: D2, + start: {Domino, :start_link, [[name: D2]]} + }, + %{ + id: D3, + start: {Domino, :start_link, [[name: D3]]} + } +] +{:ok, pid} = Supervisor.start_link(children, strategy: :rest_for_one) ``` Send your dominos messages to ensure they are crashing in the correct order. They will log a message that demonstrates the `Domino.start_link/1` function was called again. @@ -116,7 +131,7 @@ Process.send(:domino_name, :fall, []) Test sending each `Domino` process a message individually. ```elixir - +Process.send(D3, :fall, []) ``` ## Mark As Completed diff --git a/exercises/monster_spawner.livemd b/exercises/monster_spawner.livemd index 8dc7d564c..fc6a3b980 100644 --- a/exercises/monster_spawner.livemd +++ b/exercises/monster_spawner.livemd @@ -5,7 +5,7 @@ Mix.install([ {:jason, "~> 1.4"}, {:kino, "~> 0.8.0", override: true}, {:youtube, github: "brooklinjazz/youtube"}, - {:hidden_cell, github: "brooklinjazz/hidden_cell"}, + {:hidden_cell, github: "brooklinjazz/hidden_cell"} ]) ``` diff --git a/exercises/supervised_stack.livemd b/exercises/supervised_stack.livemd index b6db113b5..59fe5303a 100644 --- a/exercises/supervised_stack.livemd +++ b/exercises/supervised_stack.livemd @@ -104,7 +104,14 @@ children = [ Keep in mind, if you have already started a supervisor with the `Stack` process, your livebook may crash. You can resolve this issue by simply re-running the cell below to start the supervisor again. ```elixir +children = [ + %{ + id: Stack, + start: {Stack, :start_link, [[]]} + } +] +{:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one) ``` You should be able to send a `:pop` message to the `Stack` process and the [Supervisor](https://hexdocs.pm/elixir/Supervisor.html) will restart the `Stack` process. @@ -112,7 +119,7 @@ You should be able to send a `:pop` message to the `Stack` process and the [Supe Uncomment and evaluate the code below to test your supervisor. ```elixir -# GenServer.call(Stack, :pop) +GenServer.call(Stack, :pop) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 59d5289d4..7f1ee2471 100644 --- a/progress.json +++ b/progress.json @@ -125,7 +125,7 @@ "traffic_light_server_exercise": false, "supervisor_and_genserver_drills_exercise": false, "computer_hardware_reading": false, - "supervised_stack_exercise": false, + "supervised_stack_exercise": true, "naming_numbers_exercise": false, "deployment_exercise": false, "typespecs_reading": false, From c33d4a22c83502031c1abda29998eb02acd90b54 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Mon, 6 Mar 2023 13:38:25 -0600 Subject: [PATCH 58/64] finish dominoes exercise --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 7f1ee2471..5e672e1d7 100644 --- a/progress.json +++ b/progress.json @@ -46,7 +46,7 @@ "non_enumerables_reading": true, "control_flow_reading": false, "lists_vs_tuples_reading": false, - "dominoes_exercise": false, + "dominoes_exercise": true, "command_line_family_tree_exercise": false, "phoenix_and_ecto_reading": false, "number_finder_exercise": true, From 38140a1ebf3ba0e5815b2184d2bd37514d178d48 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Mar 2023 16:10:49 -0600 Subject: [PATCH 59/64] finish task reading --- exercises/monster_spawner.livemd | 47 +++++++++++++------ exercises/task_drills.livemd | 78 ++++++++++++++++++++++++++++---- progress.json | 2 +- reading/task.livemd | 3 +- 4 files changed, 105 insertions(+), 25 deletions(-) diff --git a/exercises/monster_spawner.livemd b/exercises/monster_spawner.livemd index fc6a3b980..f8beb8f5d 100644 --- a/exercises/monster_spawner.livemd +++ b/exercises/monster_spawner.livemd @@ -104,6 +104,8 @@ Implement the `Monster` process as documented below. defmodule Monster do use GenServer + ##### CLIENT ##### + @doc """ Start the `Monster` process. @@ -111,9 +113,11 @@ defmodule Monster do iex> {:ok, pid} = Monster.start_link([]) """ + def start_link(opts) do # IO.inspect/2 to observe when a `Monster` process starts. IO.inspect(opts, label: "Monster Started") + GenServer.start_link(__MODULE__, opts) end @doc """ @@ -121,13 +125,14 @@ defmodule Monster do ## Examples - iex> {:ok, pid} = Monster.start_link([]) - iex> :sys.get_state(pid) - %{health: 100} - iex> Monster.attack(pid, 30) - iex> :sys.get_state(pid) - %{health: 70} + # iex> {:ok, pid} = Monster.start_link([]) + # iex> :sys.get_state(pid) + # %{health: 100} + # iex> Monster.attack(pid, 30) + # iex> :sys.get_state(pid) + # %{health: 70} """ + def attack(monster_pid, amount) do end @@ -140,9 +145,13 @@ defmodule Monster do iex> Monster.health(pid) 100 """ + def health(monster_pid) do + GenServer.call(monster_pid, :health) end + ##### SERVER ##### + @doc """ Callback function to start the `Monster` process. Monsters should start with a `:health` value in a map. @@ -153,8 +162,10 @@ defmodule Monster do iex> :sys.get_state(pid) %{health: 100} """ + @impl true def init(_opts) do + {:ok, %{health: 100}} end @doc """ @@ -164,14 +175,14 @@ defmodule Monster do ## Examples - iex> {:ok, pid} = GenServer.start_link(Monster, []) - iex> :sys.get_state(pid) - %{health: 100} - iex> GenServer.cast(pid, {:attack, 20}) - iex> :sys.get_state(pid) - %{health: 80} - iex> GenServer.cast(pid, {:attack, 80}) - ** (RuntimeError) dying! + # iex> {:ok, pid} = GenServer.start_link(Monster, []) + # iex> :sys.get_state(pid) + # %{health: 100} + # iex> GenServer.cast(pid, {:attack, 20}) + # iex> :sys.get_state(pid) + # %{health: 80} + # iex> GenServer.cast(pid, {:attack, 80}) + # ** (RuntimeError) dying! """ @impl true def handle_cast({:attack, damage}, state) do @@ -188,10 +199,18 @@ defmodule Monster do """ @impl true def handle_call(:health, _from, state) do + # IO.inspect(state) + health = Map.get(state, :health) + {:reply, health, state} end end ``` +```elixir +test = %{health: 100} +Map.get(test, :health) +``` + ## Supervisor Create three named `Monster` processes under a single supervisor. When one `Monster` process dies after its health reaches zero, another should be restarted in it's place. diff --git a/exercises/task_drills.livemd b/exercises/task_drills.livemd index 900020104..fc9340b52 100644 --- a/exercises/task_drills.livemd +++ b/exercises/task_drills.livemd @@ -25,19 +25,27 @@ This set of drills is for [Tasks](../reading/task.livemd). Follow the instructio Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) to spawn a task process that returns any response. ```elixir +Kino.Process.render_seq_trace(fn -> + Process.sleep(2000) + Task.async(fn -> IO.puts("hello world!") end) +end) +# task = Task.async(fn -> Process.sleep(2000) end) +# Task.await(task) ``` Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) to spawn a task process that sleeps for six seconds. It should cause a timeout error. ```elixir - +task = Task.async(fn -> Process.sleep(6000) end) +Task.await(task) ``` Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) to spawn a task process that sleeps for six seconds. Provide a timeout value to [Task.await/2](https://hexdocs.pm/elixir/Task.html#await/2) so that it properly awaits the response. ```elixir - +task = Task.async(fn -> Process.sleep(2000) end) +Task.await(task, 7000) ``` ## Task.yield/2 @@ -55,7 +63,7 @@ time ``` ```elixir -{time, _result} = +Kino.Process.render_seq_trace(fn -> :timer.tc(fn -> # 1000 tasks # 1000 operations -> parallel @@ -69,9 +77,25 @@ time Task.await_many(tasks) end) +end) -10_009_225 -1_001_494 +# {time, _result} = +# :timer.tc(fn -> +# # 1000 tasks +# # 1000 operations -> parallel +# tasks = +# Enum.map(1..10, fn int -> +# Task.async(fn -> +# IO.puts("starting task #{int}") +# Process.sleep(1000) +# end) +# end) + +# Task.await_many(tasks) +# end) + +# 10_009_225 +# 1_001_494 ``` ### Fast Operation @@ -83,31 +107,55 @@ time ``` ```elixir -{time, _result} = +Kino.Process.render_seq_trace(fn -> :timer.tc(fn -> # 1000 tasks # 1000 operations -> parallel tasks = Enum.map(1..10, fn int -> Task.async(fn -> int * 2 end) end) Task.await_many(tasks) end) +end) + +# {time, _result} = +# :timer.tc(fn -> +# # 1000 tasks +# # 1000 operations -> parallel +# tasks = Enum.map(1..10, fn int -> Task.async(fn -> int * 2 end) end) +# Task.await_many(tasks) +# end) ``` Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) to spawn a task process that sleeps for six seconds and returns any response. Notice that the yield is `nil`. ```elixir +task = + Task.async(fn -> + Process.sleep(6000) + IO.puts("howdy!") + end) +Task.yield(task) ``` Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) to spawn a task process that sleeps for six seconds and returns any response. Provide a timeout value to [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2) so that it properly returns the response. ```elixir +task = + Task.async(fn -> + Process.sleep(6000) + IO.puts("howdy!") + end) +Task.yield(task, 7000) ``` Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), [Task.yield/2](https://hexdocs.pm/elixir/Task.html#yield/2), and [Task.shutdown/2](https://hexdocs.pm/elixir/Task.html#shutdown/2) to spawn a task process that sleeps for six seconds. Shutdown the task process if it does not yield any value. ```elixir - +Kino.Process.render_seq_trace(fn -> + task = Task.async(fn -> Process.sleep(6000) end) + Task.yield(task) || Task.shutdown(task) +end) ``` ## Task.await_many/2 @@ -115,25 +163,37 @@ Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), [Task.yield/2]( Use [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1) and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to spawn two task processes that both return a random number from `1..10`. ```elixir +tasks = [ + Task.async(fn -> :rand.uniform(10) end), + Task.async(fn -> :rand.uniform(10) end) +] +Task.await_many(tasks) ``` Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to spawn one hundred task processes that all return a random integer from `1..100`. ```elixir - +tasks = Enum.map(1..100, fn _num -> Task.async(fn -> :rand.uniform(100) end) end) +Task.await_many(tasks) ``` Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to spawn one hundred task processes that return a list doubled numbers from one to one hundred. i.e. `[2, 4, 6, 8, ..., 198, 200]`. ```elixir - +tasks = Enum.map(1..100, fn int -> Task.async(fn -> int * 2 end) end) +Task.await_many(tasks) ``` Use [Enum.map/2](https://hexdocs.pm/elixir/Enum.html#map/2), [Task.async/1](https://hexdocs.pm/elixir/Task.html#async/1), [String.upcase/2](https://hexdocs.pm/elixir/String.html#upcase/2), and [Task.await_many/2](https://hexdocs.pm/elixir/Task.html#await_many/2) to concurrently capitalize every string in the list `["apple", "pear", "peaches"]` ```elixir +tasks = + Enum.map(["apple", "pear", "peaches"], fn string -> + Task.async(fn -> String.capitalize(string) end) + end) +Task.await_many(tasks) ``` ## Task.Supervisor diff --git a/progress.json b/progress.json index 5e672e1d7..2c41ab8e5 100644 --- a/progress.json +++ b/progress.json @@ -97,7 +97,7 @@ "io_reading": false, "tuples_reading": false, "ranges_reading": false, - "task_reading": false, + "task_reading": true, "executables_reading": false, "rdbms_reading": false, "fun_formulas_exercise": false, diff --git a/reading/task.livemd b/reading/task.livemd index 70412b63f..4e7553800 100644 --- a/reading/task.livemd +++ b/reading/task.livemd @@ -242,7 +242,8 @@ In the Elixir cell below, spawn a task which takes one second to complete. `await/2` the task and alter the timeout value to be one second. Awaiting the task should crash. ```elixir - +task = Task.async(fn -> Process.sleep(1000) end) +Task.await(task, 1000) ``` ## Further Reading From 3d6cc1775aad9bbc253685dda5a651e6acaa42c6 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Tue, 7 Mar 2023 16:42:54 -0600 Subject: [PATCH 60/64] finish capstone project guide reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 2c41ab8e5..608fca118 100644 --- a/progress.json +++ b/progress.json @@ -201,7 +201,7 @@ "book_search_books_reading": false, "recursion_reading": false, "in-memory_todo_list_exercise": false, - "capstone_project_guide_reading": false, + "capstone_project_guide_reading": true, "fibonacci_exercise": true, "typespec_drills_exercise": false, "custom_assertions_exercise": false, From 17eb1cf4287ff8c2941b1b53e0708e06483045ee Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Mar 2023 13:07:53 -0600 Subject: [PATCH 61/64] finish spoonacular recipe api exercise --- exercises/spoonacular_recipe_api.livemd | 5 +++++ progress.json | 2 +- reading/apis.livemd | 5 +++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/exercises/spoonacular_recipe_api.livemd b/exercises/spoonacular_recipe_api.livemd index 7e208a76d..54bd2fb18 100644 --- a/exercises/spoonacular_recipe_api.livemd +++ b/exercises/spoonacular_recipe_api.livemd @@ -31,7 +31,12 @@ Use your API to visit the `https://api.spoonacular.com/recipes/complexSearch?api Use [HTTPoison](https://hexdocs.pm/httpoison/HTTPoison.html) to retrieve the same JSON data from the `https://api.spoonacular.com/recipes/complexSearch?apiKey=API_KEY` URL you visited in the browser. Then use [Poison](https://hexdocs.pm/poison/Poison.html) to decode the JSON response into an Elixir data structure. ```elixir +api_key = "235ecefcc30147279ffd925e41a3178e" +{:ok, response} = + HTTPoison.get("https://api.spoonacular.com/recipes/complexSearch?apiKey=#{api_key}") + +Jason.decode(response.body) ``` ## Mark As Completed diff --git a/progress.json b/progress.json index 608fca118..8c2917614 100644 --- a/progress.json +++ b/progress.json @@ -151,7 +151,7 @@ "lists_reading": false, "message_validation_exercise": false, "functions_reading": false, - "spoonacular_recipe_api_exercise": false, + "spoonacular_recipe_api_exercise": true, "book_changeset_exercise": false, "weighted_voting_exercise": true, "supervisors_reading": false, diff --git a/reading/apis.livemd b/reading/apis.livemd index 5b64ad6ee..ec5abccc9 100644 --- a/reading/apis.livemd +++ b/reading/apis.livemd @@ -236,6 +236,7 @@ Use [Jason.decode!/2](https://hexdocs.pm/jason/Jason.html#encode!/2) to decode t ```elixir json = "{\"hello\"\: \"world\"}" +Jason.decode(json) ``` ## Poison @@ -282,7 +283,7 @@ Private APIs require an API key to communicate with them. This key is then inclu For example, the [Open Weather API](https://openweathermap.org/) requires an API key when making a GET request. The server returns a `401` unauthorized response without the correct API key. ```elixir -api_key = "" +api_key = "a492ee767808f098ff912f4afc1a2b8d" HTTPoison.get("https://api.openweathermap.org/data/2.5/weather?lat=35&lon=139&appid=#{api_key}") ``` @@ -312,7 +313,7 @@ Use your API key and valid latitude/longitude coordinates to make a successful r ```elixir lat = 35 lon = 139 -api_key = "" +api_key = "a492ee767808f098ff912f4afc1a2b8d" {:ok, response} = HTTPoison.get( From 69507b2bff74b171099ef05cf6f843c73f22c97a Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Mar 2023 13:10:03 -0600 Subject: [PATCH 62/64] finish apis reading --- progress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progress.json b/progress.json index 8c2917614..5eec18589 100644 --- a/progress.json +++ b/progress.json @@ -179,7 +179,7 @@ "datetime_reading": false, "with_points_exercise": false, "itinerary_exercise": false, - "apis_reading": false, + "apis_reading": true, "built-in_modules_reading": true, "rps_pattern_matching_exercise": false, "arithmetic_reading": false, From e100a12053f9bf712956889577b7d73c3bb0f63e Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Thu, 9 Mar 2023 18:33:45 -0600 Subject: [PATCH 63/64] finish pokemon api exercise --- exercises/pokemon_api.livemd | 64 +++++++++++++++++++++++++++++++++++- progress.json | 8 ++--- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/exercises/pokemon_api.livemd b/exercises/pokemon_api.livemd index c34a9f5dd..8c61c1004 100644 --- a/exercises/pokemon_api.livemd +++ b/exercises/pokemon_api.livemd @@ -7,7 +7,7 @@ Mix.install([ {:youtube, github: "brooklinjazz/youtube"}, {:hidden_cell, github: "brooklinjazz/hidden_cell"}, {:httpoison, "~> 1.8"}, - {:poison, "~> 5.0"} + {:exconstructor, "~> 1.2"} ]) ``` @@ -38,6 +38,44 @@ mix new pokelixir Ensure you add [HTTPoison](https://github.com/edgurgel/httpoison) and [Poison](https://github.com/devinus/poison) as dependencies. +```elixir +defmodule Pokelixir do + defstruct [ + :id, + :name, + :hp, + :attack, + :defense, + :special_attack, + :special_defense, + :speed, + :weight, + :height, + :types + ] + + use ExConstructor + + def get(name) do + {:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon/#{name}") + {_head, body} = Jason.decode(response.body) + + ExConstructor.populate_struct(%__MODULE__{}, body) + end + + def all() do + {:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon/?limit=1500") + Jason.decode(response.body) + end +end + +# get a pokemon +Pokelixir.get("charizard") + +# get all pokemons +# Pokelixir.all() +``` + ## Pokemon Structs A `Pokemon` struct should have the following (required) keys. You do not need to implement data validation. @@ -79,6 +117,12 @@ Here's that data represented as a `Pokemon` struct. } ``` +```elixir +{:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon/charizard") + +Jason.decode(response.body) +``` + ## Get A Pokemon We can request information about Pokemon using the [Pokemon API](https://pokeapi.co/). @@ -117,6 +161,24 @@ response = Poison.decode!(response.body) ## Get All Pokemon +```elixir +{:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon") + +Jason.decode(response.body) +``` + +```elixir +{:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon?offset=20&limit=20") + +Jason.decode(response.body) +``` + +```elixir +{:ok, response} = HTTPoison.get("https://pokeapi.co/api/v2/pokemon/6") + +Jason.decode(response.body) +``` + You can retrieve a list of pokemon using the following URL. ``` diff --git a/progress.json b/progress.json index 5eec18589..954ca1d58 100644 --- a/progress.json +++ b/progress.json @@ -56,7 +56,7 @@ "advanced_pattern_matching_reading": false, "games_guessing_game_exercise": true, "math_with_guards_exercise": false, - "pokemon_api_exercise": false, + "pokemon_api_exercise": true, "file_search_exercise": false, "animal_generator_exercise": true, "group_project_blog_exercise": false, @@ -151,7 +151,7 @@ "lists_reading": false, "message_validation_exercise": false, "functions_reading": false, - "spoonacular_recipe_api_exercise": true, + "spoonacular_recipe_api_exercise": false, "book_changeset_exercise": false, "weighted_voting_exercise": true, "supervisors_reading": false, @@ -179,7 +179,7 @@ "datetime_reading": false, "with_points_exercise": false, "itinerary_exercise": false, - "apis_reading": true, + "apis_reading": false, "built-in_modules_reading": true, "rps_pattern_matching_exercise": false, "arithmetic_reading": false, @@ -201,7 +201,7 @@ "book_search_books_reading": false, "recursion_reading": false, "in-memory_todo_list_exercise": false, - "capstone_project_guide_reading": true, + "capstone_project_guide_reading": false, "fibonacci_exercise": true, "typespec_drills_exercise": false, "custom_assertions_exercise": false, From fec1c7d715ae7bfd24d6f6853d04f03116173552 Mon Sep 17 00:00:00 2001 From: Steve Freeman Date: Fri, 10 Mar 2023 11:33:18 -0600 Subject: [PATCH 64/64] finish web servers reading --- reading/web_servers.livemd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reading/web_servers.livemd b/reading/web_servers.livemd index 93f664f15..406af24e8 100644 --- a/reading/web_servers.livemd +++ b/reading/web_servers.livemd @@ -138,7 +138,7 @@ defmodule WebServer do # send response current_time = Time.to_string(Time.utc_now()) - response = "HTTP/1.1 200\r\nContent-Type: text/html\r\n\r\n It is #{current_time}" + response = "HTTP/1.1 200\r\nContent-Type: text/html\r\n\r\n

It is #{current_time}

" :gen_tcp.send(connection, response) # close connection