diff --git a/.github/workflows/check-deprecated-exercises.yml b/.github/workflows/check-deprecated-exercises.yml index 8defbd0cf..47267841d 100644 --- a/.github/workflows/check-deprecated-exercises.yml +++ b/.github/workflows/check-deprecated-exercises.yml @@ -14,7 +14,7 @@ jobs: name: Check for deprecated exercises runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with: fetch-depth: 0 - name: Test deprecated exercises using test-deprecated-exercises diff --git a/.github/workflows/create-configlet-sync-issues.yml b/.github/workflows/create-configlet-sync-issues.yml index 1a256cfb9..07a0ed615 100644 --- a/.github/workflows/create-configlet-sync-issues.yml +++ b/.github/workflows/create-configlet-sync-issues.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v7.0.1 - name: Fetch configlet run: ./bin/fetch-configlet diff --git a/.github/workflows/java.yml b/.github/workflows/java.yml index 867890a6c..2fc8509d9 100644 --- a/.github/workflows/java.yml +++ b/.github/workflows/java.yml @@ -16,9 +16,9 @@ jobs: if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Set up JDK 25 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 + uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 with: java-version: 25 distribution: "temurin" @@ -31,11 +31,11 @@ jobs: if: github.event_name == 'pull_request' runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with: fetch-depth: 0 - name: Set up JDK 25 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 + uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 with: java-version: 25 distribution: "temurin" @@ -47,9 +47,9 @@ jobs: if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Set up JDK 25 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 + uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 with: java-version: 25 distribution: "temurin" @@ -62,11 +62,11 @@ jobs: if: github.event_name == 'pull_request' runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with: fetch-depth: 0 - name: Set up JDK 25 - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 + uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 with: java-version: 25 distribution: "temurin" @@ -78,7 +78,7 @@ jobs: if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Test all exercises using java-test-runner run: bin/test-with-test-runner - name: Print summary @@ -105,7 +105,7 @@ jobs: if: github.event_name == 'pull_request' runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with: fetch-depth: 0 - name: Test changed exercises using java-test-runner diff --git a/.github/workflows/markdown.yml b/.github/workflows/markdown.yml index 9467459c7..5a9f03fc3 100644 --- a/.github/workflows/markdown.yml +++ b/.github/workflows/markdown.yml @@ -17,6 +17,6 @@ jobs: name: Lint Markdown files runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - name: Lint markdown - uses: DavidAnson/markdownlint-cli2-action@6b51ade7a9e4a75a7ad929842dd298a3804ebe8b + uses: DavidAnson/markdownlint-cli2-action@6bf21b07787794f89a243495939cd651942aeabe diff --git a/concepts/maps/about.md b/concepts/maps/about.md index 86a820cf1..9590aefc0 100644 --- a/concepts/maps/about.md +++ b/concepts/maps/about.md @@ -145,7 +145,11 @@ Another common way to create maps is to use [Map.of][map-of-javadoc] or [Map.ofE Map temperatures = Map.of("Mon", 30, "Tue", 28, "Wed", 32); // or using Map.ofEntries -Map temperatures2 = Map.ofEntries(Map.entry("Mon", 30, "Tue", 28, "Wed", 32)); +Map temperatures2 = Map.ofEntries( + Map.entry("Mon", 30), + Map.entry("Tue", 28), + Map.entry("Wed", 32) +); ``` Unlike `HashMap`, they populate the map upfront and become read-only once created. diff --git a/exercises/practice/affine-cipher/.docs/instructions.append.md b/exercises/practice/affine-cipher/.docs/instructions.append.md index e724f3faa..0e61d91c7 100644 --- a/exercises/practice/affine-cipher/.docs/instructions.append.md +++ b/exercises/practice/affine-cipher/.docs/instructions.append.md @@ -1,4 +1,6 @@ # Instructions append +## Implementation + Please notice that the `%` operator is not equivalent to the one described in the problem description ([see Wikipedia entry for Modulo operation](https://en.wikipedia.org/wiki/Modulo_operation)). diff --git a/exercises/practice/anagram/.docs/instructions.append.md b/exercises/practice/anagram/.docs/instructions.append.md index 8d71a920b..273ca3cbe 100644 --- a/exercises/practice/anagram/.docs/instructions.append.md +++ b/exercises/practice/anagram/.docs/instructions.append.md @@ -1,3 +1,5 @@ # Instructions Append +## Implementation + The anagrams can be returned in any order. diff --git a/exercises/practice/anagram/.meta/config.json b/exercises/practice/anagram/.meta/config.json index 1fae320a1..aa9251ddf 100644 --- a/exercises/practice/anagram/.meta/config.json +++ b/exercises/practice/anagram/.meta/config.json @@ -41,7 +41,7 @@ "build.gradle" ] }, - "blurb": "Given a word and a list of possible anagrams, select the correct sublist.", + "blurb": "Find the words that use the same letters as another word.", "source": "Inspired by the Extreme Startup game", "source_url": "https://github.com/rchatley/extreme_startup" } diff --git a/exercises/practice/armstrong-numbers/.docs/instructions.append.md b/exercises/practice/armstrong-numbers/.docs/instructions.append.md index 4f8e31eed..e36afb3dc 100644 --- a/exercises/practice/armstrong-numbers/.docs/instructions.append.md +++ b/exercises/practice/armstrong-numbers/.docs/instructions.append.md @@ -1,4 +1,6 @@ # Instructions append +## Implementation + For more help on how to solve this exercise, please refer to the tutorial provided as part of the hello world exercise: [instructions.append.md](https://github.com/exercism/java/blob/main/exercises/practice/hello-world/.docs/instructions.append.md#tutorial) diff --git a/exercises/practice/bank-account/.docs/instructions.append.md b/exercises/practice/bank-account/.docs/instructions.append.md index 9d3307ee3..0c2dd7775 100644 --- a/exercises/practice/bank-account/.docs/instructions.append.md +++ b/exercises/practice/bank-account/.docs/instructions.append.md @@ -1,5 +1,7 @@ # Instructions append +## Implementation + This exercise introduces [concurrency][oracle-docs-concurrency]. To pass the last test you might find the [`synchronized` keyword or locks][oracle-docs-synchronized] useful. diff --git a/exercises/practice/bob/.meta/tests.toml b/exercises/practice/bob/.meta/tests.toml index 5299e2895..8995c9235 100644 --- a/exercises/practice/bob/.meta/tests.toml +++ b/exercises/practice/bob/.meta/tests.toml @@ -18,6 +18,9 @@ description = "shouting" [d6c98afd-df35-4806-b55e-2c457c3ab748] description = "shouting gibberish" +[3c954328-86fb-4c71-8961-e18d6a5e2517] +description = "shouting a statement containing a question mark" + [8a2e771d-d6f1-4e3f-b6c6-b41495556e37] description = "asking a question" diff --git a/exercises/practice/bob/src/test/java/BobTest.java b/exercises/practice/bob/src/test/java/BobTest.java index 756fb93f8..3806670ab 100644 --- a/exercises/practice/bob/src/test/java/BobTest.java +++ b/exercises/practice/bob/src/test/java/BobTest.java @@ -37,6 +37,14 @@ public void shoutingGibberish() { .isEqualTo("Whoa, chill out!"); } + @Disabled("Remove to run test") + @Test + @DisplayName("shouting a statement containing a question mark") + public void shoutingAStatementContainingQuestionMark() { + assertThat(bob.hey("DO LIONS EAT PEOPLE? AHHHHH.")) + .isEqualTo("Whoa, chill out!"); + } + @Disabled("Remove to run test") @Test @DisplayName("asking a question") diff --git a/exercises/practice/clock/.docs/instructions.append.md b/exercises/practice/clock/.docs/instructions.append.md index 4e1e0fbca..05b5e459d 100644 --- a/exercises/practice/clock/.docs/instructions.append.md +++ b/exercises/practice/clock/.docs/instructions.append.md @@ -1,5 +1,7 @@ # Instructions append +## Implementation + In order to satisfy the requirement that two clocks are considered equal just when they are set to the same time, you will need to override the [`equals`](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals(java.lang.Object)) and [`hashcode`](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode) methods in your `Clock` class. For more information on how to override these methods, see [this JavaWorld article](https://web.archive.org/web/20170528222153/http://www.javaworld.com/article/2072762/java-app-dev/object-equality.html). diff --git a/exercises/practice/dot-dsl/.docs/instructions.append.md b/exercises/practice/dot-dsl/.docs/instructions.append.md index e110bf76b..330706308 100644 --- a/exercises/practice/dot-dsl/.docs/instructions.append.md +++ b/exercises/practice/dot-dsl/.docs/instructions.append.md @@ -1,5 +1,7 @@ # Instructions append +## Implementation + The graph is represented in the DSL by the `Graph` class. The implementation for the nodes and edges (represented by the `Node` and `Edge` classes respectively) are provided. diff --git a/exercises/practice/dot-dsl/.meta/tests.toml b/exercises/practice/dot-dsl/.meta/tests.toml new file mode 100644 index 000000000..bb285760c --- /dev/null +++ b/exercises/practice/dot-dsl/.meta/tests.toml @@ -0,0 +1,90 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[3a50c618-2571-466b-9ee9-346d9943912e] +description = "empty graph" + +[5067feea-e49b-4a9d-865e-4502d6b0540c] +description = "graph with one node" + +[b66cf871-88c6-489a-b0b9-7c79b6819c45] +description = "graph with one node with attribute" + +[f7841da3-c0f8-4541-b594-21b626a764d2] +description = "graph with one edge" + +[bbee70e1-6b0d-4f3a-bd4e-41cd2cfc0e39] +description = "graph with one attribute" + +[ac736158-6684-418d-93d5-7b284e43294e] +description = "graph with comments" +comment = "Not possible to create scenario in test" +include = false + +[69068da9-7690-4d4d-a728-f5c2bf132a33] +description = "graph with nodes, edges, and attributes" + +[f6c53993-3937-4959-bcde-dc16411113ae] +description = "multiple edges on one line" + +[b853dfc1-1f05-45aa-bc98-b0fc6b57529b] +description = "only 1 edge between nodes" +include = false + +[bdc0fdac-aa46-457f-8385-65736ccdc1c7] +description = "malformed input" +comment = "Not possible to create the scenario in test" +include = false + +[f5c4f77d-359c-434a-9c33-b9eb795bafdd] +description = "malformed edge" +comment = "Not possible to create the scenario in test" +include = false + +[2238f6b8-20bb-489f-8ca0-084d1771d758] +description = "malformed edge 2" +comment = "Not possible to create the scenario in test" +include = false + +[4e3a4386-9e80-4315-b70f-253a06a2234e] +description = "invalid edge type" +comment = "Not possible to create the scenario in test" +include = false + +[793adce3-bd19-4458-ac41-c989f7f8d9db] +description = "multiple edges missing a node" +comment = "Not possible to create the scenario in test" +include = false + +[e2930b2c-3a03-4d8f-abe9-78a125a915a7] +description = "multiple edges missing a connector" +comment = "Not possible to create the scenario in test" +include = false + +[55d3f722-f9f1-46e1-b308-da61607952ab] +description = "empty attribute" +comment = "Not possible to create the scenario in test" +include = false + +[4ee2a9c3-54b1-4825-bd58-2b78c2c53953] +description = "malformed attribute" +comment = "Not possible to create the scenario in test" +include = false + +[382a13c8-6419-4286-8dd2-eac708f3e2a8] +description = "empty attribute name" +comment = "Not possible to create the scenario in test" +include = false + +[a6f9e6ab-8c3e-4475-a9fe-5dd061cadec6] +description = "non-alphanumeric node name" +comment = "Not possible to create the scenario in test" +include = false diff --git a/exercises/practice/dot-dsl/src/test/java/GraphTest.java b/exercises/practice/dot-dsl/src/test/java/GraphTest.java index 34c9c0a56..93a6df747 100644 --- a/exercises/practice/dot-dsl/src/test/java/GraphTest.java +++ b/exercises/practice/dot-dsl/src/test/java/GraphTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.Map; + import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -31,8 +32,8 @@ public void testGraphWithOneNode() { @Test @Disabled - @DisplayName("graph with one node with keywords") - public void testGraphWithOneNodeWithKeywords() { + @DisplayName("graph with one node with attribute") + public void testGraphWithOneNodeWithAttribute() { Graph graph = new Graph().node("a", Map.of("color", "green")); assertThat(graph.getNodes()) @@ -55,8 +56,8 @@ public void testGraphWithOneEdge() { @Test @Disabled - @DisplayName("graph with one edge with keywords") - public void testGraphWithOneEdgeWithKeywords() { + @DisplayName("graph with one edge with attribute") + public void testGraphWithOneEdgeWithAttribute() { Graph graph = new Graph().edge("a", "b", Map.of("color", "blue")); assertThat(graph.getNodes()).isEmpty(); @@ -78,8 +79,8 @@ public void testGraphWithOneAttribute() { @Test @Disabled - @DisplayName("graph with attributes") - public void testGraphWithAttributes() { + @DisplayName("graph with nodes, edges, and attributes") + public void testGraphWithNodesEdgesAndAttributes() { Graph graph = new Graph(Map.of("foo", "1", "title", "Testing Attrs", "bar", "true")) .node("a", Map.of("color", "green")) .node("c") @@ -95,11 +96,40 @@ public void testGraphWithAttributes() { assertThat(graph.getEdges()) .containsExactlyInAnyOrder( - new Edge("a", "b", Map.of("color", "blue")), + new Edge("a", "b", Map.of("color", "blue")), new Edge("b", "c")); assertThat(graph.getAttributes()) .containsExactlyInAnyOrderEntriesOf( Map.of("foo", "1", "title", "Testing Attrs", "bar", "true")); } + + @Test + @Disabled + @DisplayName("multiple edges on one line") + public void testMultipleEdgesOnOneLine() { + Graph graph = new Graph() + .node("a") + .node("b") + .node("c") + .node("d") + .edge("a", "b", Map.of("style", "dotted")) + .edge("b", "c", Map.of("style", "dotted")) + .edge("c", "d", Map.of("style", "dotted")); + + assertThat(graph.getNodes()).containsExactlyInAnyOrder( + new Node("a"), + new Node("b"), + new Node("c"), + new Node("d") + ); + + assertThat(graph.getEdges()) + .containsExactlyInAnyOrder( + new Edge("a", "b", Map.of("style", "dotted")), + new Edge("b", "c", Map.of("style", "dotted")), + new Edge("c", "d", Map.of("style", "dotted")) + ); + assertThat(graph.getAttributes()).isEmpty(); + } } diff --git a/exercises/practice/flatten-array/.docs/instructions.append.md b/exercises/practice/flatten-array/.docs/instructions.append.md index c5bf8cb0c..d1b11d9df 100644 --- a/exercises/practice/flatten-array/.docs/instructions.append.md +++ b/exercises/practice/flatten-array/.docs/instructions.append.md @@ -1,3 +1,5 @@ # Instructions append +## Implementation + For the Java track, the input will be provided as a `List` instead of an array, and the output should also be a `List`. diff --git a/exercises/practice/grep/.meta/config.json b/exercises/practice/grep/.meta/config.json index dbf5fb02e..9b8ef04ad 100644 --- a/exercises/practice/grep/.meta/config.json +++ b/exercises/practice/grep/.meta/config.json @@ -26,7 +26,7 @@ "build.gradle" ] }, - "blurb": "Search a file for lines matching a regular expression pattern. Return the line number and contents of each matching line.", + "blurb": "Search a file for lines matching a regular expression pattern.", "source": "Conversation with Nate Foster.", "source_url": "https://www.cs.cornell.edu/courses/cs3110/2014sp/hw/0/ps0.pdf" } diff --git a/exercises/practice/hamming/.docs/instructions.append.md b/exercises/practice/hamming/.docs/instructions.append.md index 77d058700..d76e03c28 100644 --- a/exercises/practice/hamming/.docs/instructions.append.md +++ b/exercises/practice/hamming/.docs/instructions.append.md @@ -1,4 +1,6 @@ -# Hints +# Instructions append + +## Hints This is the first exercise with tests that require you to throw an [`Exception`][exception-docs]. `Exception`s are typically thrown to indicate that a program has encountered an unexpected input or state. diff --git a/exercises/practice/hangman/.docs/instructions.append.md b/exercises/practice/hangman/.docs/instructions.append.md index c5bd1e69e..db700e1e4 100644 --- a/exercises/practice/hangman/.docs/instructions.append.md +++ b/exercises/practice/hangman/.docs/instructions.append.md @@ -1,4 +1,6 @@ -# Hints +# Instructions append + +## Hints One main aspect of Functional Programming is to have side-effect free functions, not to have to wonder that hidden objects a function has changed. diff --git a/exercises/practice/intergalactic-transmission/.docs/instructions.append.md b/exercises/practice/intergalactic-transmission/.docs/instructions.append.md index a5f1cad0d..df86701a8 100644 --- a/exercises/practice/intergalactic-transmission/.docs/instructions.append.md +++ b/exercises/practice/intergalactic-transmission/.docs/instructions.append.md @@ -1,3 +1,5 @@ # Instructions append +## Implementation + Although we're dealing with bytes of data, the inputs and outputs are `List` (instead of `byte[]`) to avoid the need to cast or convert negative values for bytes 128 to 255. diff --git a/exercises/practice/isogram/.docs/instructions.append.md b/exercises/practice/isogram/.docs/instructions.append.md deleted file mode 100644 index 8f338339b..000000000 --- a/exercises/practice/isogram/.docs/instructions.append.md +++ /dev/null @@ -1 +0,0 @@ -# Instructions append diff --git a/exercises/practice/isogram/.meta/config.json b/exercises/practice/isogram/.meta/config.json index 08e8e22f9..c6c0d3c56 100644 --- a/exercises/practice/isogram/.meta/config.json +++ b/exercises/practice/isogram/.meta/config.json @@ -38,7 +38,7 @@ "build.gradle" ] }, - "blurb": "Determine if a word or phrase is an isogram.", + "blurb": "Determine whether a phrase is an isogram, a word with no repeated letters.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Isogram" } diff --git a/exercises/practice/leap/.docs/instructions.append.md b/exercises/practice/leap/.docs/instructions.append.md index 8fd1498b1..f85ccac7e 100644 --- a/exercises/practice/leap/.docs/instructions.append.md +++ b/exercises/practice/leap/.docs/instructions.append.md @@ -1,5 +1,7 @@ # Instructions append +## Implementation + Before you start, make sure you understand how to write code that can pass the test cases. For more context, check out this [tutorial]. diff --git a/exercises/practice/linked-list/.docs/instructions.append.md b/exercises/practice/linked-list/.docs/instructions.append.md index f4b180b90..7fc5c4e7e 100644 --- a/exercises/practice/linked-list/.docs/instructions.append.md +++ b/exercises/practice/linked-list/.docs/instructions.append.md @@ -1,5 +1,7 @@ # Instructions append +## Implementation + This exercise introduces [generics](https://docs.oracle.com/javase/tutorial/java/generics/index.html). To make the tests pass you need to construct your class such that it accepts any type of input, e.g. `Integer` or `String`. diff --git a/exercises/practice/list-ops/.docs/instructions.append.md b/exercises/practice/list-ops/.docs/instructions.append.md index df6022661..054352553 100644 --- a/exercises/practice/list-ops/.docs/instructions.append.md +++ b/exercises/practice/list-ops/.docs/instructions.append.md @@ -1,4 +1,6 @@ -# Hints +# Instructions append + +## Hints In Java it's considered best practice to use instance methods over class methods. However, there are conditions in which it is absolutely appropriate for a function to be `static`. Since classes in Java are closed for modification (i.e. you cannot add members to a class outside its definition like you can in other languages like Ruby or JavaScript), you cannot add new behavior to the class directly. What to do if you still want to define behavior for a given type? The idiomatic solution in this case is to write a utility method. Collections of these kinds of methods are often referred to as "utility classes". Examples of such classes from within the JRE include [Arrays](https://docs.oracle.com/javase/9/docs/api/java/util/Arrays.html) and [Collections](https://docs.oracle.com/javase/9/docs/api/java/util/Collections.html). diff --git a/exercises/practice/nucleotide-count/.meta/config.json b/exercises/practice/nucleotide-count/.meta/config.json index f58c53240..b98277ed6 100644 --- a/exercises/practice/nucleotide-count/.meta/config.json +++ b/exercises/practice/nucleotide-count/.meta/config.json @@ -44,6 +44,6 @@ ] }, "blurb": "Given a DNA string, compute how many times each nucleotide occurs in the string.", - "source": "The Calculating DNA Nucleotides_problem at Rosalind", + "source": "The Counting DNA Nucleotides problem at Rosalind", "source_url": "https://rosalind.info/problems/dna/" } diff --git a/exercises/practice/pangram/.meta/config.json b/exercises/practice/pangram/.meta/config.json index 1a3fc5dae..dbf90a374 100644 --- a/exercises/practice/pangram/.meta/config.json +++ b/exercises/practice/pangram/.meta/config.json @@ -36,7 +36,7 @@ "build.gradle" ] }, - "blurb": "Determine if a sentence is a pangram.", + "blurb": "Determine whether a phrase uses every letter in the Latin alphabet.", "source": "Wikipedia", "source_url": "https://en.wikipedia.org/wiki/Pangram" } diff --git a/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md b/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md index 47e4bf6cc..1c9796ca2 100644 --- a/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md +++ b/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md @@ -1,3 +1,5 @@ # Instructions append +## Implementation + As a stretch goal, consider if your implementation will work for characters with [diacritics or accents](https://en.wikipedia.org/wiki/Diacritic). For example, such solutions should not consider e and ë the same character. An example text for this case is [Wilhelmus](https://en.wikipedia.org/wiki/Wilhelmus), the Dutch national anthem. diff --git a/exercises/practice/perfect-numbers/.meta/config.json b/exercises/practice/perfect-numbers/.meta/config.json index 073f6f424..e65d254da 100644 --- a/exercises/practice/perfect-numbers/.meta/config.json +++ b/exercises/practice/perfect-numbers/.meta/config.json @@ -38,5 +38,5 @@ }, "blurb": "Determine if a number is perfect, abundant, or deficient based on Nicomachus' (60 - 120 CE) classification scheme for positive integers.", "source": "Taken from Chapter 2 of Functional Thinking by Neal Ford.", - "source_url": "https://www.oreilly.com/library/view/functional-thinking/9781449365509/" + "source_url": "https://nealford.com/books/functionalthinking.html" } diff --git a/exercises/practice/raindrops/.approaches/config.json b/exercises/practice/raindrops/.approaches/config.json index a74c828a5..aa7fb01a6 100644 --- a/exercises/practice/raindrops/.approaches/config.json +++ b/exercises/practice/raindrops/.approaches/config.json @@ -22,6 +22,15 @@ "authors": [ "bobahop" ] + }, + { + "uuid": "d16d4056-2434-44ff-aae6-2bd57eb53dd7", + "slug": "modulus", + "title": "Modulus", + "blurb": "Use modular arithmetic to generalize.", + "authors": [ + "habere-et-dispertire" + ] } ] } diff --git a/exercises/practice/raindrops/.approaches/introduction.md b/exercises/practice/raindrops/.approaches/introduction.md index 48b7d6b07..cf1e4777c 100644 --- a/exercises/practice/raindrops/.approaches/introduction.md +++ b/exercises/practice/raindrops/.approaches/introduction.md @@ -54,6 +54,32 @@ class RaindropConverter { For more information, check the [`Map` approach][approach-map]. +## Approach: `Modulus` + +```java +import java.math.BigInteger; +import static java.math.BigInteger.valueOf; + +class RaindropConverter { + + String convert (int n) { + return switch ( valueOf(n).modPow( valueOf(12), valueOf(105) ).intValue() ) { + case 36 -> "Pling"; + case 85 -> "Plang"; + case 91 -> "Plong"; + case 15 -> "PlingPlang"; + case 21 -> "PlingPlong"; + case 70 -> "PlangPlong"; + case 0 -> "PlingPlangPlong"; + default -> String.valueOf(n); // 1 + }; + } + +} +``` + +For more information, check the [Modulus approach][approach-modulus]. + ## Which approach to use? Benchmarking with the [Java Microbenchmark Harness][jmh] is currently outside the scope of this document, @@ -64,4 +90,5 @@ and no other code would need to be added. [remainder-operator]: https://www.geeksforgeeks.org/modulo-or-remainder-operator-in-java/ [approach-if-statements]: https://exercism.org/tracks/java/exercises/raindrops/approaches/if-statements [approach-map]: https://exercism.org/tracks/java/exercises/raindrops/approaches/map +[approach-modulus]: https://exercism.org/tracks/java/exercises/raindrops/approaches/modulus [jmh]: https://github.com/openjdk/jmh diff --git a/exercises/practice/raindrops/.approaches/modulus/content.md b/exercises/practice/raindrops/.approaches/modulus/content.md new file mode 100644 index 000000000..2e2ceb2aa --- /dev/null +++ b/exercises/practice/raindrops/.approaches/modulus/content.md @@ -0,0 +1,31 @@ +# Modulus + +```java +import java.math.BigInteger; +import static java.math.BigInteger.valueOf; + +class RaindropConverter { + + String convert (int n) { + return switch ( valueOf(n).modPow( valueOf(12), valueOf(105) ).intValue() ) { + case 36 -> "Pling"; + case 85 -> "Plang"; + case 91 -> "Plong"; + case 15 -> "PlingPlang"; + case 21 -> "PlingPlong"; + case 70 -> "PlangPlong"; + case 0 -> "PlingPlangPlong"; + default -> String.valueOf(n); // 1 + }; + } + +} +``` + +We can generalize raindrops to any factors if they are [co-prime][co-prime]. +In raindrops, the factors 3, 5 and 7 are co-prime (all sets of prime numbers are co-prime), so we can use [Euler's totient function][euler-totient] to calculate `n¹² mod 105`, giving us unique values for the various sounds. +The math behind how we find the right exponent and modulus is explained in an article on the related problem of [Fizz-Buzz][fizz-buzz]. + +[co-prime]: https://en.wikipedia.org/wiki/Coprime_integers +[euler-totient]: https://en.wikipedia.org/wiki/Euler's_totient_function +[fizz-buzz]: https://philcrissman.net/posts/eulers-fizzbuzz/ diff --git a/exercises/practice/raindrops/.approaches/modulus/snippet.txt b/exercises/practice/raindrops/.approaches/modulus/snippet.txt new file mode 100644 index 000000000..1cefcc71c --- /dev/null +++ b/exercises/practice/raindrops/.approaches/modulus/snippet.txt @@ -0,0 +1,8 @@ +String convert (int n) { + return switch (BigInteger.valueOf(n).modPow(BigInteger.valueOf(12),BigInteger.valueOf(105)).intValue()) { + case 0 -> "PlingPlangPlong"; + case 36 -> "Pling"; + // other cases + default -> String.valueOf(n); // 1 + }; +} diff --git a/exercises/practice/reverse-string/.docs/instructions.append.md b/exercises/practice/reverse-string/.docs/instructions.append.md index 8d7de0aa9..7870cec2a 100644 --- a/exercises/practice/reverse-string/.docs/instructions.append.md +++ b/exercises/practice/reverse-string/.docs/instructions.append.md @@ -1,3 +1,5 @@ # Instructions append +## Implementation + For more help on how to solve this exercise, please refer to the tutorial provided as part of the [hello world](https://exercism.org/tracks/java/exercises/hello-world) exercise. diff --git a/exercises/practice/rna-transcription/.docs/instructions.append.md b/exercises/practice/rna-transcription/.docs/instructions.append.md index 4f8e31eed..e36afb3dc 100644 --- a/exercises/practice/rna-transcription/.docs/instructions.append.md +++ b/exercises/practice/rna-transcription/.docs/instructions.append.md @@ -1,4 +1,6 @@ # Instructions append +## Implementation + For more help on how to solve this exercise, please refer to the tutorial provided as part of the hello world exercise: [instructions.append.md](https://github.com/exercism/java/blob/main/exercises/practice/hello-world/.docs/instructions.append.md#tutorial) diff --git a/exercises/practice/simple-linked-list/.meta/src/reference/java/SimpleLinkedList.java b/exercises/practice/simple-linked-list/.meta/src/reference/java/SimpleLinkedList.java index a5e82d1bf..60f85c94b 100644 --- a/exercises/practice/simple-linked-list/.meta/src/reference/java/SimpleLinkedList.java +++ b/exercises/practice/simple-linked-list/.meta/src/reference/java/SimpleLinkedList.java @@ -1,20 +1,16 @@ - -import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; class SimpleLinkedList { - private static class Element { - final T value; Element next; - Element(T value) { this.value = value; } } - private Element head; private int size; @@ -22,8 +18,8 @@ private static class Element { } SimpleLinkedList(T[] values) { - for (int i = values.length - 1; i >= 0; i--) { - push(values[i]); + for (T value : values) { + push(value); } } @@ -48,6 +44,13 @@ T pop() { return value; } + T peek() { + if (Objects.isNull(head)) { + throw new NoSuchElementException(); + } + return head.value; + } + void reverse() { Element current = head; Element next; @@ -61,24 +64,16 @@ void reverse() { head = previous; } - T[] asArray(Class clazz) { - T[] result = newArray(clazz, size); - int index = 0; + List toList() { + List result = new ArrayList<>(); Element current = head; while (Objects.nonNull(current)) { - result[index++] = current.value; + result.add(current.value); current = current.next; } return result; } - private T[] newArray(Class clazz, int size) { - @SuppressWarnings("unchecked") - T[] arr = (T[]) Array.newInstance(clazz, size); - - return arr; - } - int size() { return this.size; } diff --git a/exercises/practice/simple-linked-list/.meta/tests.toml b/exercises/practice/simple-linked-list/.meta/tests.toml new file mode 100644 index 000000000..cbf51c34e --- /dev/null +++ b/exercises/practice/simple-linked-list/.meta/tests.toml @@ -0,0 +1,104 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[962d998c-c203-41e2-8fbd-85a7b98b79b9] +description = "count -> Empty list has length of zero" + +[9760262e-d7e4-4639-9840-87e2e2fbb115] +description = "count -> Singleton list has length of one" + +[d9955c90-637c-441b-b41d-8cfb48e924a8] +description = "count -> Non-empty list has correct length" + +[0c3966db-58f9-4632-b94c-8ea13e54c2c8] +description = "pop -> Pop from empty list is an error" + +[a4f9d2e1-7425-49ef-9ee8-6c0cb3407cf0] +description = "pop -> Can pop from singleton list" + +[6dcbb2c9-d98a-47bc-a010-9c19703d3ea2] +description = "pop -> Can pop from non-empty list" + +[e83aade9-f030-4096-aaf0-f9dc6491e6cf] +description = "pop -> Can pop multiple items" + +[5c46bcf2-c0a9-4654-ae17-f3192436fcf1] +description = "pop -> Pop updates the count" + +[70d747a1-2e84-4ebc-bc3f-dcbee6a05f6b] +description = "push -> Can push to an empty list" +include = false + +[f3197f0a-1fea-45a5-939f-4a5ea60387ec] +description = "push -> Can push to an empty list" +reimplements = "70d747a1-2e84-4ebc-bc3f-dcbee6a05f6b" + +[391e332e-1f91-4033-b1e0-0e0c17812fa7] +description = "push -> Can push to a non-empty list" + +[ed4b0e01-3bbd-4895-af25-152b5914b3da] +description = "push -> Push updates count" + +[41666790-b932-4e5a-b323-e848a83d12d5] +description = "push -> Push and pop" + +[930a4a5c-76f6-47ec-9be3-4e70993173a1] +description = "peek -> Peek on empty list is an error" + +[43255a50-d919-4e81-afce-e4a271eaedbd] +description = "peek -> Can peek on singleton list" + +[48353020-e25d-4621-a854-e35fb1e15fa7] +description = "peek -> Can peek on non-empty list" + +[96fcead9-a713-46c2-8005-3f246c873851] +description = "peek -> Peek does not change the count" + +[7576ed05-7ff7-4b84-8efb-d34d62c110f5] +description = "peek -> Can peek after a pop and push" + +[b97d00b6-2fab-435d-ae74-3233dcc13698] +description = "toList LIFO -> Empty linked list to list is empty" + +[eedeb95f-b5cf-431d-8ad6-5854ba6b251c] +description = "toList LIFO -> To list with multiple values" + +[838678de-eaf3-4c14-b34e-7e35b6d851e8] +description = "toList LIFO -> To list after a pop" + +[03fc83a5-48a8-470b-a2d2-a286c5e8365f] +description = "toList FIFO -> Empty linked list to list is empty" +include = false + +[1282484e-a58c-426a-972e-90746bda61fc] +description = "toList FIFO -> To list with multiple values" +include = false + +[05ca3109-1249-4c0c-a567-a3b2f8352a7c] +description = "toList FIFO -> To list after a pop" +include = false + +[5e6c1a3d-e34b-46d3-be59-3f132a820ed5] +description = "reverse -> Reversed empty list has same values" + +[93c87ed3-862a-474f-820b-ba3fd6b6daf6] +description = "reverse -> Reversed singleton list is same list" + +[92851ebe-9f52-4406-b92e-0718c441a2ab] +description = "reverse -> Reversed non-empty list is reversed" +include = false + +[1210eeda-b23f-4790-930c-7ac6d0c8e723] +description = "reverse -> Reversed non-empty list is reversed" +reimplements = "92851ebe-9f52-4406-b92e-0718c441a2ab" + +[9b53af96-7494-4cfa-9b77-b7366fed5c4c] +description = "reverse -> Double reverse" diff --git a/exercises/practice/simple-linked-list/src/main/java/SimpleLinkedList.java b/exercises/practice/simple-linked-list/src/main/java/SimpleLinkedList.java index 9cff1bdc7..64d388d8f 100644 --- a/exercises/practice/simple-linked-list/src/main/java/SimpleLinkedList.java +++ b/exercises/practice/simple-linked-list/src/main/java/SimpleLinkedList.java @@ -1,28 +1,27 @@ +import java.util.List; + class SimpleLinkedList { SimpleLinkedList() { throw new UnsupportedOperationException("Please implement the SimpleLinkedList() constructor."); } - SimpleLinkedList(T[] values) { throw new UnsupportedOperationException("Please implement the SimpleLinkedList(T[]) constructor."); } - void push(T value) { throw new UnsupportedOperationException("Please implement the SimpleLinkedList.push() method."); } - T pop() { throw new UnsupportedOperationException("Please implement the SimpleLinkedList.pop() method."); } - + T peek() { + throw new UnsupportedOperationException("Please implement the SimpleLinkedList.peek() method."); + } void reverse() { throw new UnsupportedOperationException("Please implement the SimpleLinkedList.reverse() method."); } - - T[] asArray(Class clazz) { - throw new UnsupportedOperationException("Please implement the SimpleLinkedList.asArray() method."); + List toList() { + throw new UnsupportedOperationException("Please implement the SimpleLinkedList.toList() method."); } - int size() { throw new UnsupportedOperationException("Please implement the SimpleLinkedList.size() method."); } diff --git a/exercises/practice/simple-linked-list/src/test/java/SimpleLinkedListTest.java b/exercises/practice/simple-linked-list/src/test/java/SimpleLinkedListTest.java index 109d3b3a7..c885893d3 100644 --- a/exercises/practice/simple-linked-list/src/test/java/SimpleLinkedListTest.java +++ b/exercises/practice/simple-linked-list/src/test/java/SimpleLinkedListTest.java @@ -1,91 +1,246 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; - import java.util.NoSuchElementException; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; public class SimpleLinkedListTest { @Test - @DisplayName("A new list is empty") - public void aNewListIsEmpty() { + @DisplayName("count -> Empty list has length of zero") + public void countEmptyListHasLengthOfZero() { SimpleLinkedList list = new SimpleLinkedList<>(); assertThat(list.size()).isEqualTo(0); } @Disabled("Remove to run test") @Test - @DisplayName("Create list from array") - public void canCreateFromArray() { - Character[] values = new Character[]{'1', '2', '3'}; - SimpleLinkedList list = new SimpleLinkedList(values); - assertThat(list.size()).isEqualTo(3); + @DisplayName("count -> Singleton list has length of one") + public void countSingletonListHasLengthOfOne() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1}); + assertThat(list.size()).isEqualTo(1); } @Disabled("Remove to run test") @Test - @DisplayName("Popping an empty list throws NoSuchElementException") - public void popOnEmptyListWillThrow() { - SimpleLinkedList list = new SimpleLinkedList(); + @DisplayName("count -> Non-empty list has correct length") + public void countNonEmptyListHasCorrectLength() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2, 3}); + assertThat(list.size()).isEqualTo(3); + } + @Disabled("Remove to run test") + @Test + @DisplayName("pop -> Pop from empty list is an error") + public void popFromEmptyListIsAnError() { + SimpleLinkedList list = new SimpleLinkedList<>(); assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(list::pop); } @Disabled("Remove to run test") @Test - @DisplayName("Pop returns last added element (LIFO)") - public void popReturnsLastAddedElement() { - SimpleLinkedList list = new SimpleLinkedList(); - list.push(9); - list.push(8); + @DisplayName("pop -> Can pop from singleton list") + public void canPopFromSingletonList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1}); + assertThat(list.pop()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("pop -> Can pop from non-empty list") + public void canPopFromNonEmptyList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + assertThat(list.pop()).isEqualTo(2); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("pop -> Can pop multiple items") + public void canPopMultipleItems() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + assertThat(list.pop()).isEqualTo(2); + assertThat(list.pop()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("pop -> Pop updates the count") + public void popUpdatesTheCount() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); assertThat(list.size()).isEqualTo(2); - assertThat(list.pop()).isEqualTo(8); - assertThat(list.pop()).isEqualTo(9); + assertThat(list.pop()).isEqualTo(2); + assertThat(list.size()).isEqualTo(1); + assertThat(list.pop()).isEqualTo(1); assertThat(list.size()).isEqualTo(0); } @Disabled("Remove to run test") @Test - @DisplayName("Reverse reverses the list order") - public void reverseReversesList() { - SimpleLinkedList list = new SimpleLinkedList(); - list.push("9"); - list.push("8"); - list.push("7"); - list.push("6"); - list.push("5"); + @DisplayName("push -> Can push to an empty list") + public void canPushToAnEmptyList() { + SimpleLinkedList list = new SimpleLinkedList<>(); + list.push(1); + assertThat(list.size()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("push -> Can push to a non-empty list") + public void canPushToANonEmptyList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + list.push(3); + assertThat(list.size()).isEqualTo(3); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("push -> Push updates count") + public void pushUpdatesCount() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + list.push(3); + assertThat(list.size()).isEqualTo(3); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("push -> Push and pop") + public void pushAndPop() { + SimpleLinkedList list = new SimpleLinkedList<>(); + list.push(1); + list.push(2); + assertThat(list.pop()).isEqualTo(2); + list.push(3); + assertThat(list.size()).isEqualTo(2); + assertThat(list.pop()).isEqualTo(3); + assertThat(list.pop()).isEqualTo(1); + assertThat(list.size()).isEqualTo(0); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("peek -> Peek on empty list is an error") + public void peekOnEmptyListIsAnError() { + SimpleLinkedList list = new SimpleLinkedList<>(); + assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(list::peek); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("peek -> Can peek on singleton list") + public void canPeekOnSingletonList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1}); + assertThat(list.peek()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("peek -> Can peek on non-empty list") + public void canPeekOnNonEmptyList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + assertThat(list.peek()).isEqualTo(2); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("peek -> Peek does not change the count") + public void peekDoesNotChangeTheCount() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2}); + assertThat(list.peek()).isEqualTo(2); + assertThat(list.size()).isEqualTo(2); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("peek -> Can peek after a pop and push") + public void canPeekAfterAPopAndPush() { + SimpleLinkedList list = new SimpleLinkedList<>(); + list.push(1); + list.push(2); + assertThat(list.peek()).isEqualTo(2); + assertThat(list.pop()).isEqualTo(2); + assertThat(list.peek()).isEqualTo(1); + list.push(3); + assertThat(list.peek()).isEqualTo(3); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("toList LIFO -> Empty linked list to list is empty") + public void toListLifoEmptyLinkedListToListIsEmpty() { + SimpleLinkedList list = new SimpleLinkedList<>(); + assertThat(list.toList()).isEmpty(); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("toList LIFO -> To list with multiple values") + public void toListLifoToListWithMultipleValues() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2, 3}); + assertThat(list.toList()).containsExactly(3, 2, 1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("toList LIFO -> To list after a pop") + public void toListLifoToListAfterAPop() { + SimpleLinkedList list = new SimpleLinkedList<>(); + list.push(1); + list.push(2); + list.push(3); + assertThat(list.pop()).isEqualTo(3); + list.push(4); + assertThat(list.toList()).containsExactly(4, 2, 1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("reverse -> Reversed empty list has same values") + public void reversedEmptyListHasSameValues() { + SimpleLinkedList list = new SimpleLinkedList<>(); list.reverse(); - assertThat(list.pop()).isEqualTo("9"); - assertThat(list.pop()).isEqualTo("8"); - assertThat(list.pop()).isEqualTo("7"); - assertThat(list.pop()).isEqualTo("6"); - assertThat(list.pop()).isEqualTo("5"); + assertThat(list.toList()).isEmpty(); } @Disabled("Remove to run test") @Test - @DisplayName("Can return list as an array") - public void canReturnListAsArray() { - SimpleLinkedList list = new SimpleLinkedList(); - list.push('9'); - list.push('8'); - list.push('7'); - list.push('6'); - list.push('5'); - Character[] expected = {'5', '6', '7', '8', '9'}; - assertThat(list.asArray(Character.class)).isEqualTo(expected); + @DisplayName("reverse -> Reversed singleton list is same list") + public void reversedSingletonListIsSameList() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1}); + list.reverse(); + assertThat(list.toList()).containsExactly(1); } @Disabled("Remove to run test") @Test - @DisplayName("Can return empty list as an empty array") - public void canReturnEmptyListAsEmptyArray() { - SimpleLinkedList list = new SimpleLinkedList(); - Object[] expected = {}; - assertThat(list.asArray(Object.class)).isEqualTo(expected); + @DisplayName("reverse -> Reversed non-empty list is reversed") + public void reversedNonEmptyListIsReversed() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2, 3}); + list.reverse(); + assertThat(list.size()).isEqualTo(3); + assertThat(list.pop()).isEqualTo(1); + assertThat(list.pop()).isEqualTo(2); + assertThat(list.pop()).isEqualTo(3); } + @Disabled("Remove to run test") + @Test + @DisplayName("reverse -> Double reverse") + public void doubleReverse() { + SimpleLinkedList list = new SimpleLinkedList<>(new Integer[]{1, 2, 3}); + list.reverse(); + list.reverse(); + assertThat(list.pop()).isEqualTo(3); + assertThat(list.pop()).isEqualTo(2); + assertThat(list.pop()).isEqualTo(1); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Create list from array") + public void canCreateFromArray() { + Character[] values = new Character[]{'1', '2', '3'}; + SimpleLinkedList list = new SimpleLinkedList(values); + assertThat(list.size()).isEqualTo(3); + } } diff --git a/exercises/practice/square-root/.docs/instructions.append.md b/exercises/practice/square-root/.docs/instructions.append.md index 97a502567..e1da715ff 100644 --- a/exercises/practice/square-root/.docs/instructions.append.md +++ b/exercises/practice/square-root/.docs/instructions.append.md @@ -1,4 +1,6 @@ -# Instructions (appended) +# Instructions append + +## Implementation The goal of this exercise is to practice working with numbers, so stay away from `java.lang.Math`! diff --git a/exercises/practice/state-of-tic-tac-toe/.meta/src/reference/java/StateOfTicTacToe.java b/exercises/practice/state-of-tic-tac-toe/.meta/src/reference/java/StateOfTicTacToe.java index 1fcee86d2..d3ed3ab82 100644 --- a/exercises/practice/state-of-tic-tac-toe/.meta/src/reference/java/StateOfTicTacToe.java +++ b/exercises/practice/state-of-tic-tac-toe/.meta/src/reference/java/StateOfTicTacToe.java @@ -51,6 +51,18 @@ public GameState determineState(String[] board) { } } + if (xWin > 0 && xCount != oCount + 1) { + throw new IllegalArgumentException( + "Impossible board: game should have ended after the game was won" + ); + } + + if (oWin > 0 && xCount != oCount) { + throw new IllegalArgumentException( + "Impossible board: game should have ended after the game was won" + ); + } + if (xWin > 0 || oWin > 0) { return GameState.WIN; } @@ -82,7 +94,6 @@ private List getDiagonals(String[] board) { String[] diags = new String[2]; for (int i = 0; i < 3; i++) { - if (diags[0] == null) { diags[0] = String.valueOf(board[i].charAt(i)); } else { diff --git a/exercises/practice/state-of-tic-tac-toe/.meta/tests.toml b/exercises/practice/state-of-tic-tac-toe/.meta/tests.toml index 8fc25e211..5f574b2a1 100644 --- a/exercises/practice/state-of-tic-tac-toe/.meta/tests.toml +++ b/exercises/practice/state-of-tic-tac-toe/.meta/tests.toml @@ -99,3 +99,9 @@ reimplements = "b1dc8b13-46c4-47db-a96d-aa90eedc4e8d" [4801cda2-f5b7-4c36-8317-3cdd167ac22c] description = "Invalid boards -> Invalid board: players kept playing after a win" + +[5a84757a-fc86-4328-aec9-a5759e6ed35d] +description = "Invalid boards -> Invalid board: O kept playing after X wins" + +[cf25543d-583a-4656-b9ab-f82dc00a4a02] +description = "Invalid boards -> Invalid board: X kept playing after O wins" diff --git a/exercises/practice/state-of-tic-tac-toe/src/test/java/StateOfTicTacToeTest.java b/exercises/practice/state-of-tic-tac-toe/src/test/java/StateOfTicTacToeTest.java index d264db005..5ae93502b 100644 --- a/exercises/practice/state-of-tic-tac-toe/src/test/java/StateOfTicTacToeTest.java +++ b/exercises/practice/state-of-tic-tac-toe/src/test/java/StateOfTicTacToeTest.java @@ -95,7 +95,7 @@ public void testFinishedGameWhereXWonViaMiddleRowVictory() { @Disabled("Remove to run test") @Test - @DisplayName("Finished game where X won via middle row victory") + @DisplayName("Finished game where X won via bottom row victory") public void testFinishedGameWhereXWonViaBottomRowVictory() { assertThat( @@ -207,7 +207,7 @@ public void testDraw() { @Test @DisplayName("Another draw") public void testAnotherDraw() { - + assertThat( stateOfTicTacToe.determineState(new String[]{"XXO", "OXX", "XOO"}) ).isEqualTo(GameState.DRAW); @@ -282,4 +282,24 @@ public void testInvalidBoardPlayersKeptPlayingAfterAWin() { .isThrownBy(() -> stateOfTicTacToe.determineState(new String[]{"XXX", "OOO", "XOX"})) .withMessage("Impossible board: game should have ended after the game was won"); } + + @Disabled("Remove to run test") + @Test + @DisplayName("Invalid board: O kept playing after X wins") + public void testInvalidBoardOKeptPlayingAfterXWins() { + + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> stateOfTicTacToe.determineState(new String[]{"OO ", "XXX", " O "})) + .withMessage("Impossible board: game should have ended after the game was won"); + } + + @Disabled("Remove to run test") + @Test + @DisplayName("Invalid board: X kept playing after O wins") + public void testInvalidBoardXKeptPlayingAfterOWins() { + + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> stateOfTicTacToe.determineState(new String[]{"XX ", "OOO", " XX"})) + .withMessage("Impossible board: game should have ended after the game was won"); + } } diff --git a/exercises/practice/sublist/.meta/config.json b/exercises/practice/sublist/.meta/config.json index 21d624fe6..3b6117ef0 100644 --- a/exercises/practice/sublist/.meta/config.json +++ b/exercises/practice/sublist/.meta/config.json @@ -38,5 +38,5 @@ "build.gradle" ] }, - "blurb": "Write a function to determine if a list is a sublist of another list." + "blurb": "Determine if a list is a sublist of another list." } diff --git a/exercises/practice/two-fer/.docs/instructions.append.md b/exercises/practice/two-fer/.docs/instructions.append.md index 1005e7e9d..8c1f0c710 100644 --- a/exercises/practice/two-fer/.docs/instructions.append.md +++ b/exercises/practice/two-fer/.docs/instructions.append.md @@ -1,5 +1,7 @@ # Instructions append +## Implementation + Before you start, make sure you understand how to write code that can pass the test cases. For more context, check out this [tutorial].