Repository: exercism/clojure
Pull request #553 (2023-06-02 22:40:18)

Add unit test to robot name
The instructions state:

> Your solution must ensure that every existing robot has a unique name.

However, there was not any test to ensure that the solution satisfies this.


Patch:
diff --git a/concepts/booleans/introduction.md b/concepts/booleans/introduction.md
index 4402d62..95af9df 100644
--- a/concepts/booleans/introduction.md
+++ b/concepts/booleans/introduction.md
@@ -2,6 +2,6 @@
 
 Booleans in Clojure are represented by `true` or `false`. All values are logically true or false. The only "false" values are `false` and `nil` - all other values are logically true.
 
-Predicate functions (functions which return a boolean) will typically end with a quesion mark (`?`), but this is by convention only.
+Predicate functions (functions which return a boolean) will typically end with a question mark (`?`), but this is by convention only.
 
 The core library includes functions for logical operators such as `not`, `and`, and `or`.
diff --git a/concepts/chars/.meta/config.json b/concepts/chars/.meta/config.json
new file mode 100644
index 0000000..a39f3f3
--- /dev/null
+++ b/concepts/chars/.meta/config.json
@@ -0,0 +1,6 @@
+{
+    "blurb": "A char is a type that represents a Unicode UTF-16 value. Strings are composed of chars.",
+    "authors": [
+      "porkostomus"
+    ]
+  }
\ No newline at end of file
diff --git a/concepts/chars/about.md b/concepts/chars/about.md
new file mode 100644
index 0000000..6c801d9
--- /dev/null
+++ b/concepts/chars/about.md
@@ -0,0 +1,12 @@
+# About
+
+Clojure uses the underlying `java.lang.Character` type, which is a 16 bit quantity to represent the smallest addressable components of text.
+Multiple `char`s can comprise a string such as `"word"` or `char`s can be
+processed independently. Their literals are written like `\a \b \c`.
+
+Clojure's `char`s support UTF-16 Unicode encoding so in addition to the latin character set
+pretty much all the writing systems in use world can be represented,
+e.g. the Greek letter `'β'`.
+
+There are many library methods to inspect and manipulate `char`s. These
+can be accessed by interop as the methods of the `Character` class. Clojure also includes a built-in string utility library, `clojure.string`, which offers many powerful functions for operating on characters.
diff --git a/concepts/chars/introduction.md b/concepts/chars/introduction.md
new file mode 100644
index 0000000..2fc21f9
--- /dev/null
+++ b/concepts/chars/introduction.md
@@ -0,0 +1,12 @@
+# Introduction
+
+Clojure uses the underlying `java.lang.Character` type, which is a 16 bit quantity to represent the smallest addressable components of text.
+Multiple `char`s can comprise a string such as `"word"` or `char`s can be
+processed independently. Their literals are written like `\a \b \c`.
+
+Clojure's `char`s support UTF-16 Unicode encoding so in addition to the latin character set
+pretty much all the writing systems in use world can be represented,
+e.g. the Greek letter `'β'`.
+
+There are many library methods to inspect and manipulate `char`s. These
+can be accessed by interop as the methods of the `Character` class. Clojure also includes a built-in string utility library, `clojure.string`, which offers many powerful functions for operating on characters.
diff --git a/concepts/chars/links.json b/concepts/chars/links.json
new file mode 100644
index 0000000..5b16953
--- /dev/null
+++ b/concepts/chars/links.json
@@ -0,0 +1,30 @@
+[
+    {
+      "url": "https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html#isISOControl-char-",
+      "description": "java-ctrl"
+    },
+    {
+      "url": "https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Character.html#isLetter(char)",
+      "description": "java-isletter"
+    },
+    {
+        "url": "https://clojuredocs.org/clojure.string/includes_q",
+        "description": "str-includes"
+    },
+    {
+        "url": "https://clojuredocs.org/clojure.string/join",
+        "description": "str-join"
+    },
+    {
+        "url": "https://clojuredocs.org/clojure.string/replace",
+        "description": "str-replace"
+    },
+    {
+        "url": "https://clojuredocs.org/clojure.string/split",
+        "description": "str-split"
+    },
+    {
+        "url": "https://clojuredocs.org/clojure.string/upper-case",
+        "description": "str-upper-case"
+    }
+  ]
\ No newline at end of file
diff --git a/config.json b/config.json
index a2d7c8d..e8831ee 100644
--- a/config.json
+++ b/config.json
@@ -142,9 +142,9 @@
         "slug": "squeaky-clean",
         "name": "Squeaky Clean",
         "uuid": "3af5b219-d751-4243-89f7-c8f05216f534",
-        "concepts": [],
-        "prerequisites": [],
-        "status": "wip"
+        "concepts": ["chars"],
+        "prerequisites": ["basics", "strings"],
+        "status": "beta"
       },
       {
         "slug": "date-parser",
@@ -1059,6 +1059,11 @@
       "slug": "strings",
       "name": "Strings"
     },
+    {
+      "uuid": "3e962be9-e7e8-445a-9eb7-206eb1310e9f",
+      "slug": "chars",
+      "name": "Chars"
+    },
     {
       "uuid": "7aa13ace-5597-4d6c-8f93-8b0fb97cf2ff",
       "slug": "vectors",
diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md
index c75dc04..d5c7ab1 100644
--- a/docs/INSTALLATION.md
+++ b/docs/INSTALLATION.md
@@ -3,13 +3,24 @@
 ## Installing the Clojure CLI
 Clojure provides command line tools that can be used to start a Clojure repl, use Clojure and Java libraries, and start Clojure programs.
 
+If you need to install Java, we recommend [Adoptium Temurin 17](https://adoptium.net/).
+
 ### Linux
-Ensure that the following dependencies are installed: `bash`, `curl`, `rlwrap`, and `Java`.
+Ensure that the following dependencies are installed: `bash`, `curl`, `rlwrap`, and `Java`. 
+You can install Clojure either of these 2 ways:
+
+1. LinuxBrew - requires [Homebrew](https://brew.sh/)
+
+```bash
+brew install clojure/tools/clojure
+```
+
+2. Script installer
 
 ```bash
-curl -O https://download.clojure.org/install/linux-install-1.10.3.967.sh
-chmod +x linux-install-1.10.3.967.sh
-sudo ./linux-install-1.10.3.967.sh
+curl -O https://download.clojure.org/install/linux-install-1.11.1.1347.sh
+chmod +x linux-install-1.11.1.1347.sh
+sudo ./linux-install-1.11.1.1347.sh
 ```
 
 ### Homebrew for Mac OS X
@@ -19,15 +30,32 @@ Install the command line tools with brew from the [clojure/tools](https://github
 brew install clojure/tools/clojure
 ```
 
+#### Java
+
+Any distribution of Java will work. If needed, you can install Temurin using brew:
+
+```bash
+brew tap homebrew/cask-versions
+brew install --cask temurin17
+```
+
 ### Windows
-For running Clojure on Windows it is recommended to use WSL2.
+
+Clojure on Windows has improved significantly recently. We used to recommended using WSL2, which works great,
+but there is now a PowerShell installer. Clojure on Windows is currently in an alpha state, see [clj-on-windows](https://github.com/clojure/tools.deps.alpha/wiki/clj-on-Windows#known-issues) for known issues.
+
+Make sure Java is installed and the `JAVA_HOME` environment variable is set, and run:
+
+```powershell
+iwr -useb download.clojure.org/install/win-install-1.11.1.1165.ps1 | iex
+```
 
 Another way to install Clojure on Windows is with the [Scoop](https://scoop.sh/) package manager. To install scoop, open PowerShell and run these 2 commands, one after the other:
 
  ```sh
  iwr -useb get.scoop.sh | iex
 Set-ExecutionPolicy RemoteSigned -Scope CurrentUser -Force
-``
+```
 
 To install Clojure with Scoop you have to add two important buckets first:
 
@@ -61,4 +89,25 @@ After successfully running steps above, you should be able to run Clojure with t
 
 ```sh
 clj
-```
\ No newline at end of file
+```
+
+## Install Leiningen (optional)
+
+While no longer necessary, we still support the full featured project management tool [Leiningen](https://leiningen.org/).
+It offers a wide variety of helpful tasks like convenient testing, builds, and an improved REPL.
+
+1. Download the [lein script](https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein) or [lein.bat](https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein.bat) (Windows)
+2. Place it on your `$PATH` where your shell can find it (eg. `/usr/local/bin/`)
+3. Set it to be executable (`sudo chmod a+x /usr/local/bin/lein`)
+4. Run `lein`.
+
+## Editor integration
+
+The best way to develop Clojure is with an editor-connected REPL. Plugins are available for the most popular editors/IDEs:
+
+- Emacs: [CIDER](https://cider.mx/)
+- IntelliJ: [Cursive](https://cursive-ide.com/)
+- VSCode: [Calva](https://calva.io/)
+- Vim: [Conjure](https://github.com/Olical/conjure)
+
+See the [official docs](https://clojure.org/guides/editors) for more info.
diff --git a/exercises/concept/bird-watcher/.docs/hints.md b/exercises/concept/bird-watcher/.docs/hints.md
index 1eadc67..e32ffb0 100644
--- a/exercises/concept/bird-watcher/.docs/hints.md
+++ b/exercises/concept/bird-watcher/.docs/hints.md
@@ -1,14 +1,14 @@
 # Hints
 
-## Check what the counts were last week
+## 1. Check what the counts were last week
 
 - [Vectors][vectors] are represented in Clojure using square brackets (`[ ]`)
 
-## Check how many birds visited today
+## 2. Check how many birds visited today
 
 - The [`last`][last] function can be used to return the last item in a sequential collection.
 
-## Increment today's count
+## 3. Increment today's count
 
 - The [`update`][update] function can be used to return a new vector with a different element at a given index.
 
@@ -16,7 +16,7 @@
 
 - The [`inc`][inc] and [`dec`][dec] functions can be used to increment and decrement integer values.
 
-## Check if there was a day with no visiting birds
+## 4. Check if there was a day with no visiting birds
 
 - The [`every?`][every?] function can be used to check if all items in a collection satisfy a given predicate.
 
@@ -24,17 +24,17 @@
 
 - The [`not`][not] function returns true if an expression evaluates to logical false.
 
-## Calculate the number of visiting birds for the first number of days
+## 5. Calculate the number of visiting birds for the first number of days
 
 - The [`take`][take] function can be used return a sequence of the first n items in a collection.
 
 - The [`reduce`][reduce] function can be used to add a collection of values together.
 
-## Calculate the number of busy days
+## 6. Calculate the number of busy days
 
 - The [`filter`][filter] higher-order function can be used to return a sequence of items in a collection which satisfy a given predicate.
 
-## Check for odd week
+## 7.  Check for odd week
 
 - The [`=`][equality] function can be used to test equality.
 
diff --git a/exercises/concept/cars-assemble/.docs/introduction.md b/exercises/concept/cars-assemble/.docs/introduction.md
index adf9226..4bf6af8 100644
--- a/exercises/concept/cars-assemble/.docs/introduction.md
+++ b/exercises/concept/cars-assemble/.docs/introduction.md
@@ -7,7 +7,7 @@ Numbers in Clojure include:
 
 Two common numeric types are `int` and `float`. An `int` is a 32-bit integer and a `float` is a 64-bit floating-point number.
 
-Arithmetic is done using the standard arithmetic operators. Numbers can be compared using the standard numeric comparison operators and the equality (`=`) and inequality (`<>`) operators.
+Arithmetic is done using the standard arithmetic operators. Numbers can be compared using the standard numeric comparison operators (`>`, `<`, `<=`, `>=`), the equality operator (`=`) and the non-equality operator (`not=`).
 
 In this exercise you must conditionally execute logic. A common way to do this in Clojure is by using `cond`:
 
@@ -16,3 +16,14 @@ In this exercise you must conditionally execute logic. A common way to do this i
       (> x 7) "Expression to evaluate when x is greater than 7"
       :else   "Expression to evaluate in all other cases")
 ```
+
+## Note
+The `==` operator might be preferable to `=` in some cases where numbers need to be compared irrespective of the exact type. For instance,
+```clojure
+(== 5.0 5) ;; true as both numbers are equal when type is ignored
+(= 5.0 5) ;; false as the types of numbers are also taken into account here i.e. float is different from int
+```
+The [Clojure guide on Equality][guide-equality], specifically the section on [Numbers][guide-numbers] goes into more details.
+
+[guide-equality]: https://clojure.org/guides/equality
+[guide-numbers]: https://clojure.org/guides/equality#numbers
diff --git a/exercises/concept/interest-is-interesting/.docs/hints.md b/exercises/concept/interest-is-interesting/.docs/hints.md
index 880c80f..bef7367 100644
--- a/exercises/concept/interest-is-interesting/.docs/hints.md
+++ b/exercises/concept/interest-is-interesting/.docs/hints.md
@@ -1,14 +1,14 @@
 # Hints
 
-## Calculate the interest rate
+## 1. Calculate the interest rate
 
 - You can refer back to the [conditionals][conditionals] concept if you need to remember how to return values based on an input value.
 
-## Calculate the annual balance update
+## 2. Calculate the annual balance update
 
 - The [`bigdec`][bigdec] function can be used to coerce a number to a [BigDecimal][bigdecimal].
 
-## Calculate how much money to donate
+## 3. Calculate how much money to donate
 
 - The [`int`][int] function can be used to coerce a number to an integer.
 
diff --git a/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md b/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md
index a4834a9..2143a0e 100644
--- a/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md
+++ b/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md
@@ -1,36 +1,34 @@
 # Introduction
 
-In Clojure, binding a value to a name is referred to as a _var_. Top-level (global) vars are similar to constants in other languages, but are commonly redefined to facilitate dynamic development.
+In Clojure, binding a value to a name is referred to as a _var_. Top-level (global) vars are similar to constants in other languages.
 
 Top-level vars are defined using `def`:
 
 ```clojure
 (def fingers 10)
+
+fingers
+;;=> 10
 ```
 
-The `defn` macro can be used to define a function taking zero or more arguments. A function always returns the result of the last expression in its body.
+You can use `defn` to define a function taking zero or more arguments. This is a function that would add 2 numbers together:
 
 ```clojure
 (defn add [x y]
   (+ x y))
 ```
 
-Invoking a function is done by specifying its name and passing arguments for each of the function's parameters.
-
-```clojure
-(def five (add 2 3))
-```
+This function takes 2 arguments which are placed in the vector `[x y]`, followed by the *body* of the function which can contain any number of expressions. The return value is always the result of evaluating the last expression in the body, `(+ x y)`. This expression is a list representing a function call. The first items of the list is the `+` function which is evaluated using the following items `x` and `y` as arguments.
 
-Functions and values in Clojure can only be used _after_ they have been defined. Using it before it has been defined results in a compile error.
+The `add` function defined above is called the same way:
 
 ```clojure
-;; Compile error as `add` has not yet been defined
-(def seven (add 3 4))
-
-(defn add [x y]
-  (+ x y))
+(add 2 3)
+;;=> 5
 ```
 
+Functions and values in Clojure can only be used _after_ they have been defined, i.e. forms are always evaluated in the order they appear.
+
 In Clojure, whitespace has no significance other than formatting.
 
 Clojure functions and vars are organized in namespaces. A namespace groups related functionality and is defined using the `ns` macro:
diff --git a/exercises/concept/squeaky-clean/.docs/hints.md b/exercises/concept/squeaky-clean/.docs/hints.md
index f074fa8..efca0f8 100644
--- a/exercises/concept/squeaky-clean/.docs/hints.md
+++ b/exercises/concept/squeaky-clean/.docs/hints.md
@@ -1,3 +1,30 @@
 # Hints
 
-<!-- TODO: add hints -->
+## 1. Replace any spaces encountered with underscores
+
+The built-in `clojure.string` library contains a [`replace`][str-replace] function.
+
+## 2. Replace control characters with the upper case string "CTRL"
+
+Here we need to use the [`isISOControl`][java-ctrl] method from Java's `Character` class.
+
+## 3. Convert kebab-case to camelCase
+
+Try separating the string on the hyphens with [`string/split`][str-split].
+If there are no hyphens, we need to pass the original string. You can check using [string/includes?][str-includes]. Use [string/upper-case][str-upper-case] to make the "humps" of the camel. Finally, concatenate them with [string/join][str-join].
+
+## 4. Omit characters that are not letters
+
+You can filter characters using [Character/isLetter][java-isletter] as a predicate.
+
+## 5. Omit Greek lower case letters
+
+The lower-case Greek letters are Unicode points `\u03B1` to `\u03C9`, or integer values 945 through 969.
+
+[str-join]: https://clojuredocs.org/clojure.string/join
+[str-upper-case]: https://clojuredocs.org/clojure.string/upper-case
+[str-includes]: https://clojuredocs.org/clojure.string/includes_q
+[str-split]: https://clojuredocs.org/clojure.string/split
+[str-replace]: https://clojuredocs.org/clojure.string/replace
+[java-ctrl]: https://docs.oracle.com/javase/8/docs/api/java/lang/Character.html#isISOControl-char-
+[java-isletter]: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Character.html#isLetter(char)
\ No newline at end of file
diff --git a/exercises/concept/squeaky-clean/.docs/instructions.md b/exercises/concept/squeaky-clean/.docs/instructions.md
index e7e2623..cbb90e3 100644
--- a/exercises/concept/squeaky-clean/.docs/instructions.md
+++ b/exercises/concept/squeaky-clean/.docs/instructions.md
@@ -1,18 +1,22 @@
 # Instructions
 
-In this exercise you will implement a partial set of utility routines to help a developer
-clean up identifier names.
+In this exercise you will implement a partial set of utility routines 
+to help a developer clean up identifier names.
 
-In the 4 tasks you will gradually build up the routine `clean`. A valid identifier comprises
-zero or more letters and underscores.
+In the 5 tasks you will gradually build up the routine `clean`. 
+A valid identifier comprises zero or more letters and underscores.
 
-In all cases the input string is guaranteed to be non-nil. If an empty string is passed to the `clean` function, an empty string should be returned.
+In all cases the input string is guaranteed to be non-nil. 
+If an empty string is passed to the `clean` function, 
+an empty string should be returned.
 
-Note that the caller should avoid calling the routine `clean` with an empty identifier since such identifiers are ineffectual.
+Note that the caller should avoid calling the routine `clean` 
+with an empty identifier since such identifiers are ineffectual.
 
 ## 1. Replace any spaces encountered with underscores
 
-Implement the `clean` function to replace any spaces with underscores. This also applies to leading and trailing spaces.
+Implement the `clean` function to replace any spaces with underscores. 
+This also applies to leading and trailing spaces.
 
 ```clojure
 (clean "my   Id")
@@ -21,7 +25,11 @@ Implement the `clean` function to replace any spaces with underscores. This also
 
 ## 2. Replace control characters with the upper case string "CTRL"
 
-Modify the `clean` function to replace control characters with the upper case string `"CTRL"`.
+Modify the `clean` function to replace control characters with 
+the upper case string `"CTRL"`. 
+A character is considered to be an ISO control character if 
+its code is in the range '\u0000' through '\u001F' 
+or in the range '\u007F' through '\u009F'.
 
 ```clojure
 (clean "my\0Id")
@@ -37,7 +45,17 @@ Modify the `clean` function to convert kebab-case to camelCase.
 ;;=> "àḂç"
 ```
 
-## 4. Omit Greek lower case letters
+## 4. Omit characters that are not letters
+
+Modify the `clean` function to omit any characters that are not letters.
+Note: The underscores must be preserved from the previous step.
+
+```clojure
+(clean "1😀2😀3😀")
+;; => ""
+```
+
+## 5. Omit Greek lower case letters
 
 Modify the `clean` function to omit any Greek letters in the range 'α' to 'ω'.
 
diff --git a/exercises/concept/squeaky-clean/.docs/introduction.md b/exercises/concept/squeaky-clean/.docs/introduction.md
index e08b50d..144fd34 100644
--- a/exercises/concept/squeaky-clean/.docs/introduction.md
+++ b/exercises/concept/squeaky-clean/.docs/introduction.md
@@ -1,3 +1,18 @@
 # Introduction
 
-<!-- TODO: add introduction -->
+## Character operations
+
+Clojure characters are `java.lang.Character` primitives, and we can manipulate them via [interop][clojure-java-interop] using the methods in the [Character class][java-character-class]:
+
+```clojure
+(Character/isDigit \2)
+;;=> true
+```
+
+## String utilities
+
+Clojure ships with a powerful string processing library, [clojure.string][clojure-str]. This is often more idiomatic than interop.
+
+[clojure-str]: https://clojuredocs.org/clojure.string
+[clojure-java-interop]: https://clojure.org/reference/java_interop
+[java-character-class]: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Character.html
\ No newline at end of file
diff --git a/exercises/concept/squeaky-clean/.meta/exemplar.clj b/exercises/concept/squeaky-clean/.meta/exemplar.clj
index 6cc4d87..177123b 100644
--- a/exercises/concept/squeaky-clean/.meta/exemplar.clj
+++ b/exercises/concept/squeaky-clean/.meta/exemplar.clj
@@ -12,15 +12,14 @@
 
 (defn camelize [s]
     (let [words (str/split s #"-")]
-      (if (str/includes? s "-")
-      (str/join "" (cons (first words)
-                         (cons (str/upper-case (ffirst (rest words)))
-                               (rest (first (rest words))))))
-    s)))
+      (if-not (str/includes? s "-") s
+              (str/join (cons (first words)
+                              (cons (str/upper-case (ffirst (rest words)))
+                                    (nfirst (rest words))))))))
 
 (defn letters [s]
-  (apply str (filter #(or (Character/isLetter %)
-                        (= \_ %))
+  (apply str (filter #(or (Character/isLetter %) 
+                          (= \_ %)) 
                      s)))
 
 (defn clean-greek [s]
@@ -28,8 +27,8 @@
 
 (defn clean [s]
   (-> s
-       (str/replace " " "_")
-       camelize
+      (str/replace " " "_")
+      camelize
       escape-ctrl
       letters
       clean-greek))
diff --git a/exercises/concept/squeaky-clean/project.clj b/exercises/concept/squeaky-clean/project.clj
new file mode 100644
index 0000000..662da06
--- /dev/null
+++ b/exercises/concept/squeaky-clean/project.clj
@@ -0,0 +1,4 @@
+(defproject squeaky-clean "0.1.0-SNAPSHOT"
+  :description "squeaky-clean exercise."
+  :url "https://github.com/exercism/clojure/tree/main/exercises/concept/squeaky-clean"
+  :dependencies [[org.clojure/clojure "1.11.1"]])
diff --git a/exercises/practice/hello-world/.docs/instructions.append.md b/exercises/practice/hello-world/.docs/instructions.append.md
index 0075910..1cea9ec 100644
--- a/exercises/practice/hello-world/.docs/instructions.append.md
+++ b/exercises/practice/hello-world/.docs/instructions.append.md
@@ -2,15 +2,18 @@
 
 ## Project Structure
 
-Clojure exercises in exercism use [leiningen](http://leiningen.org/) to configure and run your code
-and use [leiningen standard directory structure](https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#directory-layout).
+Clojure exercises in exercism support the two most common tools for dependency management and testing, [leiningen](http://leiningen.org/) and the [Clojure CLI](https://clojure.org/guides/deps_and_cli).
 
 You will find a test file named `hello_world_test.clj` inside `test` directory.
 Write your code in `src/hello_world.clj`. It should use the namespace `hello-world` so that tests can pick it up.
 
-## Running tests
+### Running tests using the Clojure CLI
 
-Run the tests using `lein test` command and make them pass:
+```
+$ clj -X:test
+```
+
+### Running tests using Leiningen
 
 ```
 $ lein test
diff --git a/exercises/practice/robot-name/.meta/src/example.clj b/exercises/practice/robot-name/.meta/src/example.clj
index 32b61fb..ad913ac 100644
--- a/exercises/practice/robot-name/.meta/src/example.clj
+++ b/exercises/practice/robot-name/.meta/src/example.clj
@@ -1,15 +1,39 @@
 (ns robot-name)
 
-(def ^:private letters (map char (range 65 91)))
-(defn- generate-name []
-  (format "%s%03d" (apply str (repeatedly 2 #(rand-nth letters)))
-          (rand-int 1000)))
+(defn letters [] 
+  (let [letter #(rand-nth (map char (range 65 91)))]
+    (apply str (repeatedly 2 letter))))
+
+(defn numbers []
+  (let [number #(rand-int 10)]
+    (apply str (repeatedly 3 number))))
+
+;; Maintain a set of robot names
+
+(def robots (atom #{}))
+
+;; Before returning robot, check if the set count has increased.
 
 (defn robot []
-  (atom {:name (generate-name)}))
+  (let [active-names @robots
+        robot-count (count active-names)
+        new-name (str (letters) (numbers))]
+    (if (< robot-count (count (conj active-names new-name)))
+      (do (swap! robots conj new-name)
+          (atom {:name new-name}))
+      (recur))))
+
+(comment
+  (robot)
+  @robots
+  )
 
 (defn robot-name [robot]
   (:name @robot))
-
+ 
 (defn reset-name [robot]
-  (swap! robot assoc :name (generate-name)))
+  (swap! robot assoc :name (str (letters) (numbers))))
+
+(comment
+  (re-seq #"[A-Z]{2}\d{3}" (robot-name (robot)))
+  )


Test patch:
diff --git a/exercises/concept/cars-assemble/test/cars_assemble_test.clj b/exercises/concept/cars-assemble/test/cars_assemble_test.clj
index 660dcd0..1eeec2e 100644
--- a/exercises/concept/cars-assemble/test/cars_assemble_test.clj
+++ b/exercises/concept/cars-assemble/test/cars_assemble_test.clj
@@ -14,7 +14,7 @@
   (testing "Production rate for speed 4"
     (is (= 884.0 (cars-assemble/production-rate 4)))))
 
-(deftest ^{:task 1} production-rate-speeed-7-test
+(deftest ^{:task 1} production-rate-speed-7-test
   (testing "Production rate for speed 7"
     (is (= 1392.3 (cars-assemble/production-rate 7)))))
 
diff --git a/exercises/concept/squeaky-clean/test/squeaky_clean_test.clj b/exercises/concept/squeaky-clean/test/squeaky_clean_test.clj
index 035862c..dbd0cf1 100644
--- a/exercises/concept/squeaky-clean/test/squeaky_clean_test.clj
+++ b/exercises/concept/squeaky-clean/test/squeaky_clean_test.clj
@@ -11,9 +11,6 @@
 (deftest ^{:task 1} clean-string-with-spaces
   (is (= "my___Id" (squeaky-clean/clean "my   Id"))))
 
-(deftest ^{:task 1} clean-string-with-no-letters
-  (is (= "" (squeaky-clean/clean "😀😀😀"))))
-
 (deftest ^{:task 1} clean-empty-string
   (is (= "" (squeaky-clean/clean ""))))
 
@@ -23,8 +20,14 @@
 (deftest ^{:task 3} convert-kebab-to-camel-case
   (is (= "àḂç" (squeaky-clean/clean "à-ḃç"))))
 
-(deftest ^{:task 4} omit-lower-case-greek-letters
+(deftest ^{:task 4} clean-string-with-special-characters
+  (is (= "MyFinder" (squeaky-clean/clean "My😀😀Finder😀"))))
+
+(deftest ^{:task 4} clean-string-with-numbers
+  (is (= "MyFinder" (squeaky-clean/clean "1My2Finder3"))))
+
+(deftest ^{:task 5} omit-lower-case-greek-letters
   (is (= "MyΟFinder" (squeaky-clean/clean "MyΟβιεγτFinder"))))
 
-(deftest ^{:task 3} combine-conversions
+(deftest ^{:task 5} combine-conversions
   (is (= "_AbcĐCTRL" (squeaky-clean/clean "9 -abcĐ😀ω\0"))))
diff --git a/exercises/practice/robot-name/test/robot_name_test.clj b/exercises/practice/robot-name/test/robot_name_test.clj
index addeb27..8159e19 100644
--- a/exercises/practice/robot-name/test/robot_name_test.clj
+++ b/exercises/practice/robot-name/test/robot_name_test.clj
@@ -39,9 +39,5 @@
       (is (= its-new-name (robot-name/robot-name a-robot)))))
 
 (deftest new-names-different-each-time
-  (let [a-robot (robot-name/robot)
-        its-original-name (robot-name/robot-name a-robot)
-        its-new-name (do (robot-name/reset-name a-robot)
-                         (robot-name/robot-name a-robot))]
-  (is (not= its-new-name (do (robot-name/reset-name a-robot)
-                             (robot-name/robot-name a-robot))))))
+  (let [four-thousand-names (repeatedly 4000 #(robot-name/robot-name (robot-name/robot)))]
+    (is (= 4000 (count (set four-thousand-names))))))