diff --git a/concepts/bitwise-operations/.meta/config.json b/concepts/bitwise-operations/.meta/config.json
new file mode 100644
index 00000000..de93ebb4
--- /dev/null
+++ b/concepts/bitwise-operations/.meta/config.json
@@ -0,0 +1,7 @@
+{
+ "authors": [
+ "stewartmurrie"
+ ],
+ "contributors": ["jiegillet"],
+ "blurb": "Learn how to use integer bitwise operations in Elm"
+}
diff --git a/concepts/bitwise-operations/about.md b/concepts/bitwise-operations/about.md
new file mode 100644
index 00000000..fb478c0d
--- /dev/null
+++ b/concepts/bitwise-operations/about.md
@@ -0,0 +1,117 @@
+# About
+
+## Bitwise operations
+
+Bitwise operations allow us to manipulate individual digits within binary numbers.
+These operations are fundamental in computing, providing an efficient way to perform low-level tasks, such as controlling specific bits in memory, optimizing mathematical calculations, encryption, communications, and encoding/decoding data.
+
+### Understanding 32-bit Integers in Elm
+
+In Elm, integers are stored as 32-bit signed integers using [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement) representation, meaning they use 32 binary digits (_bits_) to store each integer value.
+This bit limit affects the range of integers that Elm can represent directly:
+
+Positive Range: 0 to 231 - 1 (or 0 to 2,147,483,647)
+Negative Range: -231 to -1 (or -2,147,483,648 to -1).
+
+For example, the integer `5` is represented in binary as `00000000000000000000000000000101`, although usually we ignore the leading zeros and just say `101`.
+
+### Bitwise operations
+
+Elm provides several bitwise operators in its [Bitwise module](https://package.elm-lang.org/packages/elm/core/latest/Bitwise)
+
+### Basic operations
+
+Modifying individual bits of a number is called _masking_.
+A _mask_ is a number where specific bits have been set in a particular way to manipulate another number using bitwise operators such as `and`, `or`, and `xor`.
+
+#### and
+
+`and` combines two numbers by keeping only the bits that are `1` in both.
+This is useful for checking to see if an individual bit is set.
+For example, to check if the 4th bit of a number is set to `1`, `and` it with a mask of `01000` (`8` in decimal) and see if the result is non-zero:
+
+````elm
+Bitwise.and 13 8 --> 8
+-- 13 = 01101
+-- 8 = 01000
+-- and = 01000 = 8
+
+
+### or
+
+`or` combines two numbers by setting each bit to `1` if it is `1` in either or both numbers.
+This is useful for setting a specific bit to `1`.
+For example, to set the 2nd bit in `10101`, `or` it with the mask `00010`:
+
+```elm
+Bitwise.or 21 2 --> 23
+-- 21 = 10101
+-- 2 = 00010
+-- or = 10111 = 23
+````
+
+### Exclusive-or (xor)
+
+`xor` combines two numbers by setting each bit to `1` if it is `1` in one number but `0` in the other.
+This is useful for flipping a bit to its opposite value:
+
+````elm
+Bitwise.xor 21 4 --> 17
+-- 21 = 10101
+-- 4 = 00100
+-- xor = 10001 = 17
+
+#### Complement
+
+`complement` inverts each bit of a number (`0` becomes `1`, `1` becomes `0`).
+
+Note that this will result in positive numbers becoming negative, and negative numbers becoming positive.
+This is because negative numbers in binary are represented with `1` in the left-most position.
+
+```elm
+Bitwise.complement 21 --> -22
+-- 21 = 00000000000000000000000000010101
+-- complement = 11111111111111111111111111101010 = -22
+````
+
+### Bit shifting
+
+The following operators move bits left or right by a specified number of positions, effectively multiplying or dividing by powers of 2.
+
+`shiftLeftBy` moves bits to the left, filling in with `0` from the right-hand side.
+For example, to shift `21` left by 3 places:
+
+```elm
+Bitwise.shiftLeftBy 3 21 --> 168
+-- 21 = 10101
+-- shiftLeftBy 3 = 10101000 = 168
+```
+
+This is the same as saying `21 * 2^3 = 21 * 2 * 2 * 2 = 168`
+
+`shiftRightBy`: Moves bits to the right:
+
+```elm
+Bitwise.shiftRightBy 2 21 --> 5
+-- 21 = 10101
+-- shiftRightBy 2 = 00101 = 5
+```
+
+Shifting to the right by 2 places is the same as integer division by 4.
+
+Note that this function duplicates whatever value is in the leftmost bit.
+So, negative numbers will stay negative:
+
+```elm
+Bitwise.shiftRightBy 3 -21 --> -6
+-- -21 = 111...10101
+-- shiftRightBy 3 = 111...11101 = -6
+```
+
+If you want to shift right and fill in with zeros, use `shiftRightZfBy`:
+
+```elm
+Bitwise.shiftRightZfBy 3 -21 --> 1073741818
+-- -21 = 111...10101
+-- shiftRightZfBy 3 = 00111...11101 = 1073741818
+```
diff --git a/concepts/bitwise-operations/introduction.md b/concepts/bitwise-operations/introduction.md
new file mode 100644
index 00000000..9580c794
--- /dev/null
+++ b/concepts/bitwise-operations/introduction.md
@@ -0,0 +1,104 @@
+# Introduction
+
+Bitwise operations allow us to manipulate individual digits within binary numbers.
+
+## Bitwise operations
+
+Elm provides several bitwise operators in its [Bitwise module](https://package.elm-lang.org/packages/elm/core/latest/Bitwise)
+
+## Basic operations
+
+Modifying individual bits of a number is called _masking_.
+A _mask_ is a number where specific bits have been set in a particular way to manipulate another number using bitwise operators such as `and`, `or`, and `xor`.
+
+### and
+
+`and` combines two numbers by keeping only the bits that are `1` in both.
+This is useful for checking to see if an individual bit is set.
+For example, to check if the 4th bit of a number is set to `1`, `and` it with a mask of `01000` (`8` in decimal) and see if the result is non-zero:
+
+````elm
+Bitwise.and 13 8 --> 8
+-- 13 = 01101
+-- 8 = 01000
+-- and = 01000 = 8
+
+
+### or
+
+`or` combines two numbers by setting each bit to `1` if it is `1` in either or both numbers.
+This is useful for setting a specific bit to `1`.
+For example, to set the 2nd bit in `10101`, `or` it with the mask `00010`:
+
+```elm
+Bitwise.or 21 2 --> 23
+-- 21 = 10101
+-- 2 = 00010
+-- or = 10111 = 23
+````
+
+### Exclusive-or (xor)
+
+`xor` combines two numbers by setting each bit to `1` if it is `1` in one number but `0` in the other.
+This is useful for flipping a bit to its opposite value:
+
+````elm
+Bitwise.xor 21 4 --> 17
+-- 21 = 10101
+-- 4 = 00100
+-- xor = 10001 = 17
+
+### Complement
+
+`complement` inverts each bit of a number (`0` becomes `1`, `1` becomes `0`).
+
+Note that this will result in positive numbers becoming negative, and negative numbers becoming positive.
+This is because negative numbers in binary are represented with `1` in the left-most position.
+
+```elm
+Bitwise.complement 21 --> -22
+-- 21 = 00000000000000000000000000010101
+-- complement = 11111111111111111111111111101010 = -22
+````
+
+## Bit shifting
+
+The following operators move bits left or right by a specified number of positions, effectively multiplying or dividing by powers of 2.
+
+`shiftLeftBy` moves bits to the left, filling in with `0` from the right-hand side.
+For example, to shift `21` left by 3 places:
+
+```elm
+Bitwise.shiftLeftBy 3 21 --> 168
+-- 21 = 10101
+-- shiftLeftBy 3 = 10101000 = 168
+```
+
+This is the same as saying `21 * 2^3 = 21 * 2 * 2 * 2 = 168`
+
+`shiftRightBy`: Moves bits to the right:
+
+```elm
+Bitwise.shiftRightBy 2 21 --> 5
+-- 21 = 10101
+-- shiftRightBy 2 = 00101 = 5
+```
+
+Shifting to the right by 2 places is the same as integer division by 4.
+
+Note that this function duplicates whatever value is in the leftmost bit.
+So, negative numbers will stay negative:
+
+```elm
+Bitwise.shiftRightBy 3 -21 --> -6
+-- -21 = 111...10101
+-- shiftRightBy 3 = 111...11101 = -6
+```
+
+If you want to shift right and fill in with zeros, use `shiftRightZfBy`:
+
+```elm
+Bitwise.shiftRightZfBy 3 -21 --> 1073741818
+-- -21 = 111...10101
+-- shiftRightZfBy 3 = 00111...11101 = 1073741818
+```
diff --git a/concepts/bitwise-operations/links.json b/concepts/bitwise-operations/links.json
new file mode 100644
index 00000000..f3c37daa
--- /dev/null
+++ b/concepts/bitwise-operations/links.json
@@ -0,0 +1,10 @@
+[
+ {
+ "url": "https://package.elm-lang.org/packages/elm/core/latest/Bitwise",
+ "description": "Bitwise module"
+ },
+ {
+ "url": "https://guide.elm-lang.org/appendix/types_as_bits",
+ "description": "Documentation on how Elm represents types as bits"
+ }
+]
diff --git a/config.json b/config.json
index 823ab69c..f1f4d154 100644
--- a/config.json
+++ b/config.json
@@ -339,6 +339,18 @@
"booleans"
],
"status": "beta"
+ },
+ {
+ "slug": "secrets",
+ "name": "Secrets",
+ "uuid": "89a899b1-8cb2-4099-98c9-468723728a28",
+ "concepts": [
+ "bitwise-operations"
+ ],
+ "prerequisites": [
+ "basics-1",
+ "basics-2"
+ ]
}
],
"practice": [
@@ -503,11 +515,14 @@
"slug": "allergies",
"name": "Allergies",
"uuid": "29b5a28a-417a-4cee-ba6f-9dd942ceffaa",
- "practices": [],
- "prerequisites": [],
+ "practices": [
+ "bitwise-operations"
+ ],
+ "prerequisites": [
+ "bitwise-operations"
+ ],
"difficulty": 4,
"topics": [
- "bitwise_operations",
"enumerations",
"filtering"
]
@@ -1255,8 +1270,11 @@
"slug": "secret-handshake",
"name": "Secret Handshake",
"uuid": "6c7a96ec-0bfb-4284-bd9f-2aa6989c3bb5",
- "practices": [],
+ "practices": [
+ "bitwise-operations"
+ ],
"prerequisites": [
+ "bitwise-operations",
"custom-types",
"pattern-matching",
"maybe",
@@ -1505,6 +1523,11 @@
"uuid": "357ffb6e-5a73-49b6-8b69-98ecd3c74c33",
"slug": "random",
"name": "Random"
+ },
+ {
+ "uuid": "8737961b-c96f-4313-8737-6b88034c66d8",
+ "slug": "bitwise-operations",
+ "name": "Bitwise Operations"
}
],
"key_features": [
diff --git a/exercises/concept/secrets/.docs/hints.md b/exercises/concept/secrets/.docs/hints.md
new file mode 100644
index 00000000..1c38b6aa
--- /dev/null
+++ b/exercises/concept/secrets/.docs/hints.md
@@ -0,0 +1,38 @@
+# Hints
+
+- The documentation for the `Bitwise` package can be found [here][bitwise-docs].
+
+## 1. Shift back the bits
+
+- There are two functions for shifting bits to the right, but [only one][bitwise-shiftRightZfBy] will always insert a 0.
+
+## 2. Set some bits
+
+- [One of the bitwise functions][bitwise-or] will always set a bit to 1 where the bits in both values are 1.
+
+## 3. Flip specific bits
+
+- There is [a bitwise function][bitwise-xor] that will flip a bit where the mask is 1.
+
+## 4. Clear specific bits
+
+- [One of the bitwise functions][bitwise-and] clears bits where the bit in the mask is 0.
+- But, you may need to combine it with [another function][bitwise-complement] to clear bits where the mask is 1.
+
+## 5. Decrypt a message
+
+- Apply the other functions you wrote to the input in the following order, taking the output of one and using it as the input to the next one:
+
+1. `setBits`
+2. `flipBits`
+3. `shiftBack`
+4. `clearBits`
+
+For step 4, you'll need to convert the binary number with the 1st and 5th bits set (10001) to decimal.
+
+[bitwise-docs]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise
+[bitwise-shiftRightZfBy]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#shiftRightZfBy
+[bitwise-or]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#or
+[bitwise-xor]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#xor
+[bitwise-complement]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#complement
+[bitwise-and]: https://package.elm-lang.org/packages/elm/core/latest/Bitwise#and
diff --git a/exercises/concept/secrets/.docs/instructions.md b/exercises/concept/secrets/.docs/instructions.md
new file mode 100644
index 00000000..c7f2d684
--- /dev/null
+++ b/exercises/concept/secrets/.docs/instructions.md
@@ -0,0 +1,68 @@
+# Instructions
+
+Your friend has just sent you a message with an important secret.
+Not wanting to make it easy for others to read it, the message was encrypted by performing a series of bit manipulations.
+You will need to write the functions to help decrypt the message.
+
+## 1. Shift back the bits
+
+The first step in decrypting the message is to undo the shifting from the encryption process by shifting the bits back to the right.
+There will be further steps in the decryption process that assume `0`s are inserted from the left hand side.
+
+Implement the `shiftBack` function that takes a number of places to shift by and a value and peforms the shift.
+
+```elm
+shiftBack 2 42 --> 10
+```
+
+## 2. Set some bits
+
+Next, there are some bits that need to be set to `1`.
+
+Implement the `setBits` function that takes a mask and value and returns the result of setting the bits in value to `1`.
+A bit from value should be set to `1` where the bit in the mask is also `1`.
+All other bits should be kept unchanged.
+
+```elm
+setBits 66 212 --> 64
+```
+
+## 3. Flip specific bits
+
+Some bits are flipped during encryption.
+They will need to be flipped back to decrypt the message.
+
+Implement the `flipBits` function that takes a mask and a value.
+The mask indicates which bits in the value to flip.
+If the bit is `1` in mask, the bit is flipped in the value.
+All other bits are kept unchanged.
+
+```elm
+flipBits 23 157 --> 138
+```
+
+## 4. Clear specific bits
+
+There are also certain bits that always decrypt to 0.
+
+Implement the `clearBits` function that takes a mask and a value.
+The bits in the `value` should be set to 0 where the bit in the mask is 1.
+All other bits should be kept unchanged.
+
+```elm
+clearBits 2 15 --> 13
+```
+
+## 5. Decrypt a message
+
+Now that you have all the functions you need, you can decode your friend's message.
+Implement the `decrypt` function that performs the following operations:
+
+1. Set the bits from the year your friend was born (1996)
+2. Flip the result with the year that you first met (2009)
+3. Shift the bits back by the number of classes you take together (5)
+4. Clear the first and fifth bit.
+
+```elm
+decrypt 380182 --> 11840
+```
diff --git a/exercises/concept/secrets/.docs/introduction.md b/exercises/concept/secrets/.docs/introduction.md
new file mode 100644
index 00000000..6fc4f9b3
--- /dev/null
+++ b/exercises/concept/secrets/.docs/introduction.md
@@ -0,0 +1,104 @@
+# Introduction
+
+Bitwise operations allow us to manipulate individual digits within binary numbers.
+
+## Bitwise operations
+
+Elm provides several bitwise operators in its [Bitwise module](https://package.elm-lang.org/packages/elm/core/latest/Bitwise)
+
+### Basic operations
+
+Modifying individual bits of a number is called _masking_.
+A _mask_ is a number where specific bits have been set in a particular way to manipulate another number using bitwise operators such as `and`, `or`, and `xor`.
+
+#### and
+
+`and` combines two numbers by keeping only the bits that are `1` in both.
+This is useful for checking to see if an individual bit is set.
+For example, to check if the 4th bit of a number is set to `1`, `and` it with a mask of `01000` (`8` in decimal) and see if the result is non-zero:
+
+````elm
+Bitwise.and 13 8 --> 8
+-- 13 = 01101
+-- 8 = 01000
+-- and = 01000 = 8
+
+
+### or
+
+`or` combines two numbers by setting each bit to `1` if it is `1` in either or both numbers.
+This is useful for setting a specific bit to `1`.
+For example, to set the 2nd bit in `10101`, `or` it with the mask `00010`:
+
+```elm
+Bitwise.or 21 2 --> 23
+-- 21 = 10101
+-- 2 = 00010
+-- or = 10111 = 23
+````
+
+### Exclusive-or (xor)
+
+`xor` combines two numbers by setting each bit to `1` if it is `1` in one number but `0` in the other.
+This is useful for flipping a bit to its opposite value:
+
+````elm
+Bitwise.xor 21 4 --> 17
+-- 21 = 10101
+-- 4 = 00100
+-- xor = 10001 = 17
+
+#### Complement
+
+`complement` inverts each bit of a number (`0` becomes `1`, `1` becomes `0`).
+
+Note that this will result in positive numbers becoming negative, and negative numbers becoming positive.
+This is because negative numbers in binary are represented with `1` in the left-most position.
+
+```elm
+Bitwise.complement 21 --> -22
+-- 21 = 00000000000000000000000000010101
+-- complement = 11111111111111111111111111101010 = -22
+````
+
+### Bit shifting
+
+The following operators move bits left or right by a specified number of positions, effectively multiplying or dividing by powers of 2.
+
+`shiftLeftBy` moves bits to the left, filling in with `0` from the right-hand side.
+For example, to shift `21` left by 3 places:
+
+```elm
+Bitwise.shiftLeftBy 3 21 --> 168
+-- 21 = 10101
+-- shiftLeftBy 3 = 10101000 = 168
+```
+
+This is the same as saying `21 * 2^3 = 21 * 2 * 2 * 2 = 168`
+
+`shiftRightBy`: Moves bits to the right:
+
+```elm
+Bitwise.shiftRightBy 2 21 --> 5
+-- 21 = 10101
+-- shiftRightBy 2 = 00101 = 5
+```
+
+Shifting to the right by 2 places is the same as integer division by 4.
+
+Note that this function duplicates whatever value is in the leftmost bit.
+So, negative numbers will stay negative:
+
+```elm
+Bitwise.shiftRightBy 3 -21 --> -6
+-- -21 = 111...10101
+-- shiftRightBy 3 = 111...11101 = -6
+```
+
+If you want to shift right and fill in with zeros, use `shiftRightZfBy`:
+
+```elm
+Bitwise.shiftRightZfBy 3 -21 --> 1073741818
+-- -21 = 111...10101
+-- shiftRightZfBy 3 = 00111...11101 = 1073741818
+```
diff --git a/exercises/concept/secrets/.docs/introduction.md.tpl b/exercises/concept/secrets/.docs/introduction.md.tpl
new file mode 100644
index 00000000..41cf343b
--- /dev/null
+++ b/exercises/concept/secrets/.docs/introduction.md.tpl
@@ -0,0 +1,3 @@
+# Introduction
+
+%{concept: bitwise-operations}
diff --git a/exercises/concept/secrets/.meta/Exemplar.elm b/exercises/concept/secrets/.meta/Exemplar.elm
new file mode 100644
index 00000000..e20f47cb
--- /dev/null
+++ b/exercises/concept/secrets/.meta/Exemplar.elm
@@ -0,0 +1,29 @@
+module Secrets exposing (clearBits, decrypt, flipBits, setBits, shiftBack)
+
+import Bitwise
+
+
+shiftBack amount value =
+ Bitwise.shiftRightZfBy amount value
+
+
+setBits mask value =
+ Bitwise.or mask value
+
+
+flipBits mask value =
+ Bitwise.xor mask value
+
+
+clearBits mask value =
+ mask
+ |> Bitwise.complement
+ |> Bitwise.and value
+
+
+decrypt secret =
+ secret
+ |> setBits 1996
+ |> flipBits 2009
+ |> shiftBack 5
+ |> clearBits 17
diff --git a/exercises/concept/secrets/.meta/config.json b/exercises/concept/secrets/.meta/config.json
new file mode 100644
index 00000000..42e03920
--- /dev/null
+++ b/exercises/concept/secrets/.meta/config.json
@@ -0,0 +1,20 @@
+{
+ "authors": [
+ "stewartmurrie"
+ ],
+ "files": {
+ "solution": [
+ "src/Secrets.elm"
+ ],
+ "test": [
+ "tests/Tests.elm"
+ ],
+ "exemplar": [
+ ".meta/Exemplar.elm"
+ ]
+ },
+ "forked_from": [
+ "java/secrets"
+ ],
+ "blurb": "Learn about bit manipulation by writing the software for an encryption device."
+}
diff --git a/exercises/concept/secrets/elm.json b/exercises/concept/secrets/elm.json
new file mode 100644
index 00000000..22c9e137
--- /dev/null
+++ b/exercises/concept/secrets/elm.json
@@ -0,0 +1,29 @@
+{
+ "type": "application",
+ "source-directories": [
+ "src"
+ ],
+ "elm-version": "0.19.1",
+ "dependencies": {
+ "direct": {
+ "elm/core": "1.0.5",
+ "elm/json": "1.1.3",
+ "elm/parser": "1.1.0",
+ "elm/random": "1.0.0",
+ "elm/regex": "1.0.0",
+ "elm/time": "1.0.0"
+ },
+ "indirect": {}
+ },
+ "test-dependencies": {
+ "direct": {
+ "elm-explorations/test": "2.1.0",
+ "rtfeldman/elm-iso8601-date-strings": "1.1.4"
+ },
+ "indirect": {
+ "elm/bytes": "1.0.8",
+ "elm/html": "1.0.0",
+ "elm/virtual-dom": "1.0.3"
+ }
+ }
+}
diff --git a/exercises/concept/secrets/src/Secrets.elm b/exercises/concept/secrets/src/Secrets.elm
new file mode 100644
index 00000000..46f37243
--- /dev/null
+++ b/exercises/concept/secrets/src/Secrets.elm
@@ -0,0 +1,21 @@
+module Secrets exposing (clearBits, decrypt, flipBits, setBits, shiftBack)
+
+
+shiftBack amount value =
+ Debug.todo "Please implement shiftBack"
+
+
+setBits mask value =
+ Debug.todo "Please implement setBits"
+
+
+flipBits mask value =
+ Debug.todo "Please implement flipBits"
+
+
+clearBits mask value =
+ Debug.todo "Please implement clearBits"
+
+
+decrypt secret =
+ Debug.todo "Please implement decrypt"
diff --git a/exercises/concept/secrets/tests/Tests.elm b/exercises/concept/secrets/tests/Tests.elm
new file mode 100644
index 00000000..5d5090fd
--- /dev/null
+++ b/exercises/concept/secrets/tests/Tests.elm
@@ -0,0 +1,61 @@
+module Tests exposing (tests)
+
+import Expect
+import Secrets
+import Test exposing (Test, describe, test)
+
+
+tests : Test
+tests =
+ describe "Secrets"
+ [ describe "1"
+ [ test "Shift 8 right by 2" <|
+ \_ ->
+ Secrets.shiftBack 2 8
+ |> Expect.equal 2
+ , test "Shift -8 right by 2" <|
+ \_ ->
+ Secrets.shiftBack 2 -8
+ |> Expect.equal 1073741822
+ ]
+ , describe "2"
+ [ test "Set bits in 5" <|
+ \_ ->
+ Secrets.setBits 3 5
+ |> Expect.equal 7
+ , test "Set bits in 5,652" <|
+ \_ ->
+ Secrets.setBits 26150 5652
+ |> Expect.equal 30262
+ ]
+ , describe "3"
+ [ test "Flip bits in 5" <|
+ \_ ->
+ Secrets.flipBits 11 5
+ |> Expect.equal 14
+ , test "Flip bits in 38460" <|
+ \_ ->
+ Secrets.flipBits 15471 38460
+ |> Expect.equal 43603
+ ]
+ , describe "4"
+ [ test "Clear bits from 5" <|
+ \_ ->
+ Secrets.clearBits 11 5
+ |> Expect.equal 4
+ , test "Clear bits from 90" <|
+ \_ ->
+ Secrets.clearBits 240 90
+ |> Expect.equal 10
+ ]
+ , describe "5"
+ [ test "Decrypt 12345" <|
+ \_ ->
+ Secrets.decrypt 12345
+ |> Expect.equal 384
+ , test "Decrypt 123456789" <|
+ \_ ->
+ Secrets.decrypt 123456789
+ |> Expect.equal 3857984
+ ]
+ ]