diff --git a/languages/purescript/config.json b/languages/purescript/config.json index f5b05436b0..53b869cfd4 100644 --- a/languages/purescript/config.json +++ b/languages/purescript/config.json @@ -8,7 +8,14 @@ "indent_size": 2 }, "exercises": { - "concept": [], + "concept": [ + { + "slug": "booleans", + "uuid": "f1eb2cab-d6bc-447a-bce3-6780c44e4b22", + "concepts": ["booleans"], + "prerequisites": [] + } + ], "practice": [] } } diff --git a/languages/purescript/exercises/concept/booleans/.docs/after.md b/languages/purescript/exercises/concept/booleans/.docs/after.md new file mode 100644 index 0000000000..be5e36690d --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/.docs/after.md @@ -0,0 +1,5 @@ +PureScript uses `true` and `false` to represent the two truth values of logic. + +In PureScript, for each of the three logical operations (AND, OR and NOT) there is a corresponding operator: `&&`, `||` and `not`. In general, there are rules regarding the order of the operations, and in this case `not` (negation) is applied first, and then `&&` (conjunction) and then `||` (disjunction). + +You can always 'escape' these rules by using an operator with an even higher precedence, namely, `( )` named the 'Grouping operator' or simply called 'parentheses'. diff --git a/languages/purescript/exercises/concept/booleans/.docs/hints.md b/languages/purescript/exercises/concept/booleans/.docs/hints.md new file mode 100644 index 0000000000..aa56fd3130 --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/.docs/hints.md @@ -0,0 +1,11 @@ +### 1. Check if the 'Fast Attack' action is possible + +- The logical NOT operator (`not`) can be placed before an expression to negate its value. + +### 2. Check if the 'Approach and Spy' action is possible + +- Logical expressions are evaluated from left to right and are tested for possible 'short-circuits'. + +### 3. Check if the 'Signal Prisoner' action is possible + +- Logical operators in the order of their precedence (from highest to lowest): `not`, `&&`, `||`. diff --git a/languages/purescript/exercises/concept/booleans/.docs/instructions.md b/languages/purescript/exercises/concept/booleans/.docs/instructions.md new file mode 100644 index 0000000000..3bf737a478 --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/.docs/instructions.md @@ -0,0 +1,76 @@ +In this exercise, you'll be implementing the quest logic for a new RPG game a friend is developing. The game's main character is Annalyn, a brave girl with a fierce and loyal pet dog. Unfortunately, disaster strikes, as her best friend was kidnapped while searching for berries in the forest. Annalyn will try to find and free her best friend, optionally taking her dog with her on this quest. + +After some time spent following her best friend's trail, she finds the camp in which her best friend is imprisoned. It turns out there are two kidnappers: a mighty knight and a cunning archer. + +Having found the kidnappers, Annalyn considers which of the following actions she can engage in: + +- Fast attack: a fast attack can be made if the knight is sleeping, as it takes time for him to get his armor on, so he will be vulnerable. +- Spy: the group can be spied upon if at least one of them is awake. Otherwise, spying is a waste of time. +- Signal prisoner: the prisoner can be signalled using bird sounds if the prisoner is awake and the archer is sleeping, as archers are trained in bird signaling so they could intercept the message. +- Free prisoner: if the prisoner is awake and the other two characters are sleeping, a sneaky entry into the camp can free the prisoner. This won't work if the prisoner is sleeping, as the prisoner will be startled by the sudden appearance of her friend and the knight and archer will be awoken. The prisoner can also be freed if the archer is sleeping and Annalyn has her pet dog with her, as the knight will be scared by the dog and will withdraw, and the archer can't equip his bow fast enough to prevent the prisoner from being freed. + +You have four tasks: to implement the logic for determining if the above actions are available based on the state of the three characters found in the forest and whether Annalyn's pet dog is present or not. + +## Tasks + +### 1. Check if the 'Fast Attack' action is possible + +Implement a function named `canExecuteFastAttack` that takes a boolean value which indicates if the knight is awake. This function returns `true` if the 'Fast Attack' action is available based on the state of the character. Otherwise, returns `false`: + +```purescript +knightIsAwake :: Boolean +knightIsAwake = true + +canExecuteFastAttack knightIsAwake -- => false +``` + +### 2. Check if the 'Spy' action is possible + +Implement a function named `canSpy` that takes three boolean values, indicating if the knight, archer and the prisoner, respectively, are awake. The function returns `true` if the 'Spy' action is available based on the state of the characters. Otherwise, returns `false`: + +```purescript +knightIsAwake :: Boolean +knightIsAwake = true + +archerIsAwake :: Boolean +archerIsAwake = true + +prisonerIsAwake :: Boolean +prisonerIsAwake = true + +canSpy knightIsAwake archerIsAwake prisonerIsAwake -- => true +``` + +### 3. Check if the 'Signal Prisoner' action is possible + +Implement a function named `canSignalPrisoner` that takes two boolean values, indicating if the archer and the prisoner, respectively, are awake. The function returns `true` if the 'Signal Prisoner' action is available based on the state of the characters. Otherwise, returns `false`: + +```purescript +archerIsAwake :: Boolean +archerIsAwake = false + +prisonerIsAwake :: Boolean +prisonerIsAwake = true + +canSignalPrisoner archerIsAwake prisonerIsAwake -- => true +``` + +### 4. Check if the 'Free Prisoner' action is possible + +Implement a function named `canFreePrisoner` that takes four boolean values. The first three parameters indicate if the knight, archer and the prisoner, respectively, are awake. The last parameter indicates if Annalyn's pet dog is present. The function returns `true` if the 'Free Prisoner' action is available based on the state of the characters and Annalyn's pet dog presence. Otherwise, it returns `false`: + +```purescript +knightIsAwake :: Boolean +knightIsAwake = true + +archerIsAwake :: Boolean +archerIsAwake = false + +prisonerIsAwake :: Boolean +prisonerIsAwake = true + +petDogIsPresent :: Boolean +petDogIsPresent = true + +canFreePrisoner knightIsAwake archerIsAwake prisonerIsAwake petDogIsPresent -- => false +``` diff --git a/languages/purescript/exercises/concept/booleans/.docs/introduction.md b/languages/purescript/exercises/concept/booleans/.docs/introduction.md new file mode 100644 index 0000000000..7ddf5aeec2 --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/.docs/introduction.md @@ -0,0 +1 @@ +A boolean represents one of two values: `true` or `false`. Logical operators (`not`, `&&`, `||`) are typically used with boolean values and they return a boolean value. diff --git a/languages/purescript/exercises/concept/booleans/.gitignore b/languages/purescript/exercises/concept/booleans/.gitignore new file mode 100644 index 0000000000..30efe19975 --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/.gitignore @@ -0,0 +1,10 @@ +/bower_components/ +/node_modules/ +/.pulp-cache/ +/output/ +/generated-docs/ +/.psc-package/ +/.psc* +/.purs* +/.psa* +/.spago diff --git a/languages/purescript/exercises/concept/booleans/.meta/Example.purs b/languages/purescript/exercises/concept/booleans/.meta/Example.purs new file mode 100644 index 0000000000..b7f523a95e --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/.meta/Example.purs @@ -0,0 +1,15 @@ +module Booleans where + +import Prelude + +canExecuteFastAttack :: Boolean -> Boolean +canExecuteFastAttack knightIsAwake = not knightIsAwake + +canSpy :: Boolean -> Boolean -> Boolean -> Boolean +canSpy knightIsAwake archerIsAwake prisonerIsAwake = knightIsAwake || archerIsAwake || prisonerIsAwake + +canSignalPrisoner :: Boolean -> Boolean -> Boolean +canSignalPrisoner archerIsAwake prisonerIsAwake = not archerIsAwake && prisonerIsAwake + +canFreePrisoner :: Boolean -> Boolean -> Boolean -> Boolean -> Boolean +canFreePrisoner knightIsAwake archerIsAwake prisonerIsAwake petDogIsPresent = not knightIsAwake && not archerIsAwake && prisonerIsAwake || petDogIsPresent && not archerIsAwake diff --git a/languages/purescript/exercises/concept/booleans/.meta/config.json b/languages/purescript/exercises/concept/booleans/.meta/config.json new file mode 100644 index 0000000000..2d7fcdfb64 --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/.meta/config.json @@ -0,0 +1,9 @@ +{ + "authors": [ + { + "github_username": "aimorris", + "exercism_username": "Adam-Morris" + } + ], + "forked_from": ["javascript/booleans"] +} diff --git a/languages/purescript/exercises/concept/booleans/packages.dhall b/languages/purescript/exercises/concept/booleans/packages.dhall new file mode 100644 index 0000000000..d293079bb3 --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/packages.dhall @@ -0,0 +1,128 @@ +{- +Welcome to your new Dhall package-set! + +Below are instructions for how to edit this file for most use +cases, so that you don't need to know Dhall to use it. + +## Warning: Don't Move This Top-Level Comment! + +Due to how `dhall format` currently works, this comment's +instructions cannot appear near corresponding sections below +because `dhall format` will delete the comment. However, +it will not delete a top-level comment like this one. + +## Use Cases + +Most will want to do one or both of these options: +1. Override/Patch a package's dependency +2. Add a package not already in the default package set + +This file will continue to work whether you use one or both options. +Instructions for each option are explained below. + +### Overriding/Patching a package + +Purpose: +- Change a package's dependency to a newer/older release than the + default package set's release +- Use your own modified version of some dependency that may + include new API, changed API, removed API by + using your custom git repo of the library rather than + the package set's repo + +Syntax: +Replace the overrides' "{=}" (an empty record) with the following idea +The "//" or "⫽" means "merge these two records and + when they have the same value, use the one on the right:" +------------------------------- +let overrides = + { packageName = + upstream.packageName // { updateEntity1 = "new value", updateEntity2 = "new value" } + , packageName = + upstream.packageName // { version = "v4.0.0" } + , packageName = + upstream.packageName // { repo = "https://www.example.com/path/to/new/repo.git" } + } +------------------------------- + +Example: +------------------------------- +let overrides = + { halogen = + upstream.halogen // { version = "master" } + , halogen-vdom = + upstream.halogen-vdom // { version = "v4.0.0" } + } +------------------------------- + +### Additions + +Purpose: +- Add packages that aren't already included in the default package set + +Syntax: +Replace the additions' "{=}" (an empty record) with the following idea: +------------------------------- +let additions = + { package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "tag ('v4.0.0') or branch ('master')" + } + , package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "tag ('v4.0.0') or branch ('master')" + } + , etc. + } +------------------------------- + +Example: +------------------------------- +let additions = + { benchotron = + { dependencies = + [ "arrays" + , "exists" + , "profunctor" + , "strings" + , "quickcheck" + , "lcg" + , "transformers" + , "foldable-traversable" + , "exceptions" + , "node-fs" + , "node-buffer" + , "node-readline" + , "datetime" + , "now" + ] + , repo = + "https://github.com/hdgarrood/purescript-benchotron.git" + , version = + "v7.0.0" + } + } +------------------------------- +-} + + +let upstream = + https://github.com/purescript/package-sets/releases/download/psc-0.13.6-20200404/packages.dhall sha256:f239f2e215d0cbd5c203307701748581938f74c4c78f4aeffa32c11c131ef7b6 + +let overrides = {=} + +let additions = {=} + +in upstream // overrides // additions diff --git a/languages/purescript/exercises/concept/booleans/spago.dhall b/languages/purescript/exercises/concept/booleans/spago.dhall new file mode 100644 index 0000000000..fd8711e800 --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/spago.dhall @@ -0,0 +1,9 @@ +{- +Welcome to a Spago project! +You can edit this file as you like. +-} +{ name = "booleans" +, dependencies = [ "spec" ] +, packages = ./packages.dhall +, sources = [ "src/**/*.purs", "test/**/*.purs" ] +} diff --git a/languages/purescript/exercises/concept/booleans/src/Booleans.purs b/languages/purescript/exercises/concept/booleans/src/Booleans.purs new file mode 100644 index 0000000000..f39bef5160 --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/src/Booleans.purs @@ -0,0 +1,15 @@ +module Booleans where + +import Prelude + +canExecuteFastAttack :: Boolean -> Boolean +canExecuteFastAttack knightIsAwake = -- You need to implement this function! + +canSpy :: Boolean -> Boolean -> Boolean -> Boolean +canSpy knightIsAwake archerIsAwake prisonerIsAwake = -- You need to implement this function! + +canSignalPrisoner :: Boolean -> Boolean -> Boolean +canSignalPrisoner archerIsAwake prisonerIsAwake = -- You need to implement this function! + +canFreePrisoner :: Boolean -> Boolean -> Boolean -> Boolean -> Boolean +canFreePrisoner knightIsAwake archerIsAwake prisonerIsAwake petDogIsPresent = -- You need to implement this function! diff --git a/languages/purescript/exercises/concept/booleans/test/Main.purs b/languages/purescript/exercises/concept/booleans/test/Main.purs new file mode 100644 index 0000000000..0dbf7ae6b5 --- /dev/null +++ b/languages/purescript/exercises/concept/booleans/test/Main.purs @@ -0,0 +1,47 @@ +module Test.Main where + +import Prelude + +import Booleans (canExecuteFastAttack, canSpy, canSignalPrisoner, canFreePrisoner) +import Effect (Effect) +import Effect.Aff (launchAff_) +import Test.Spec (describe, it) +import Test.Spec.Assertions (shouldEqual) +import Test.Spec.Reporter.Console (consoleReporter) +import Test.Spec.Runner (runSpec) + +main :: Effect Unit +main = launchAff_ $ runSpec [consoleReporter] do + describe "Can fast attack" do + it "Knight is awake" $ canExecuteFastAttack true `shouldEqual` false + it "Knight is asleep" $ canExecuteFastAttack false `shouldEqual` true + describe "Can spy" do + it "Knight is asleep, archer is asleep, prisoner is awake" $ canSpy false false true `shouldEqual` true + it "Knight is asleep, archer is awake, prisoner is asleep" $ canSpy false true false `shouldEqual` true + it "Knight is awake, archer is asleep, prisoner is asleep" $ canSpy true false false `shouldEqual` true + it "Knight is awake, archer is asleep, prisoner is awake" $ canSpy true false true `shouldEqual` true + it "Knight is awake, archer is awake, prisoner is asleep" $ canSpy true true false `shouldEqual` true + it "Knight is awake, archer is awake, prisoner is awake" $ canSpy true true true `shouldEqual` true + it "Knight is asleep, archer is asleep, prisoner is asleep" $ canSpy false false false `shouldEqual` false + describe "Can signal prisoner" do + it "Archer is asleep, prisoner is asleep" $ canSignalPrisoner false false `shouldEqual` false + it "Archer is asleep, prisoner is awake" $ canSignalPrisoner false true `shouldEqual` true + it "Archer is awake, prisoner is asleep" $ canSignalPrisoner true false `shouldEqual` false + it "Archer is awake, prisoner is awake" $ canSignalPrisoner true true `shouldEqual` false + describe "Can free prisoner" do + it "Knight is asleep, archer is asleep, prisoner is asleep, pet dog is not present" $ canFreePrisoner false false false false `shouldEqual` false + it "Knight is asleep, archer is asleep, prisoner is asleep, pet dog is present" $ canFreePrisoner false false false true `shouldEqual` true + it "Knight is asleep, archer is asleep, prisoner is awake, pet dog is not present" $ canFreePrisoner false false true false `shouldEqual` true + it "Knight is asleep, archer is asleep, prisoner is awake, pet dog is present" $ canFreePrisoner false false true true `shouldEqual` true + it "Knight is asleep, archer is awake, prisoner is asleep, pet dog is not present" $ canFreePrisoner false true false false `shouldEqual` false + it "Knight is asleep, archer is awake, prisoner is asleep, pet dog is present" $ canFreePrisoner false true false true `shouldEqual` false + it "Knight is asleep, archer is awake, prisoner is awake, pet dog is not present" $ canFreePrisoner false true true false `shouldEqual` false + it "Knight is asleep, archer is awake, prisoner is awake, pet dog is present" $ canFreePrisoner false true true true `shouldEqual` false + it "Knight is awake, archer is asleep, prisoner is asleep, pet dog is not present" $ canFreePrisoner true false false false `shouldEqual` false + it "Knight is awake, archer is asleep, prisoner is asleep, pet dog is present" $ canFreePrisoner true false false true `shouldEqual` true + it "Knight is awake, archer is asleep, prisoner is awake, pet dog is not present" $ canFreePrisoner true false true false `shouldEqual` false + it "Knight is awake, archer is asleep, prisoner is awake, pet dog is present" $ canFreePrisoner true false true true `shouldEqual` true + it "Knight is awake, archer is awake, prisoner is asleep, pet dog is not present" $ canFreePrisoner true true false false `shouldEqual` false + it "Knight is awake, archer is awake, prisoner is asleep, pet dog is present" $ canFreePrisoner true true false true `shouldEqual` false + it "Knight is awake, archer is awake, prisoner is awake, pet dog is not present" $ canFreePrisoner true true true false `shouldEqual` false + it "Knight is awake, archer is awake, prisoner is awake, pet dog is present" $ canFreePrisoner true true true true `shouldEqual` false diff --git a/reference/concepts/boolean_logic.md b/reference/concepts/boolean_logic.md index 8c2e50209b..a057f30e13 100644 --- a/reference/concepts/boolean_logic.md +++ b/reference/concepts/boolean_logic.md @@ -20,4 +20,17 @@ This exercise looks at various game events and determine if they have occured by | ------ | --------------------------------- | ------- | | Elixir | [booleans][implementation-elixir] | None | +### RPG game logic + +This exercise determines whether specific characters are awake (true or false) and checks whether a certain plan will work or not dependent on which characters are sleeping. The implementation teaches: + +- boolean values +- boolean operators +- boolean operators precedence + +| Track | Exercise | Changes | +| ----- | ------------------------------- | ---------------------------------- | +| PureScript | [booleans][implementation-purescript] | None | + [implementation-elixir]: ../../languages/elixir/exercises/concept/booleans/.docs/introduction.md +[implementation-purescript]: ../../languages/purescript/exercises/concept/booleans/.docs/introduction.md