From fc89d595eb89235fd47c7866284be6a2aacd860c Mon Sep 17 00:00:00 2001 From: glaxxie <86179463+glaxxie@users.noreply.github.com> Date: Mon, 28 Aug 2023 05:55:07 -0500 Subject: [PATCH 1/5] [New Exercise]: Clock (#250) * add clock * update to example description --- config.json | 11 + .../practice/clock/.docs/instructions.md | 7 + .../practice/clock/.meta/Clock.example.ps1 | 56 +++ exercises/practice/clock/.meta/config.json | 17 + exercises/practice/clock/.meta/tests.toml | 166 +++++++ exercises/practice/clock/Clock.ps1 | 36 ++ exercises/practice/clock/Clock.tests.ps1 | 411 ++++++++++++++++++ 7 files changed, 704 insertions(+) create mode 100644 exercises/practice/clock/.docs/instructions.md create mode 100644 exercises/practice/clock/.meta/Clock.example.ps1 create mode 100644 exercises/practice/clock/.meta/config.json create mode 100644 exercises/practice/clock/.meta/tests.toml create mode 100644 exercises/practice/clock/Clock.ps1 create mode 100644 exercises/practice/clock/Clock.tests.ps1 diff --git a/config.json b/config.json index 9bad021b..e1241d3f 100644 --- a/config.json +++ b/config.json @@ -537,6 +537,17 @@ "prerequisites": [], "difficulty": 3 }, + { + "slug": "clock", + "name": "Clock", + "uuid": "31a5ba31-3f86-4957-87cd-8200eee0a0f4", + "practices": [ + "classes", + "string" + ], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "pascals-triangle", "name": "Pascals Triangle", diff --git a/exercises/practice/clock/.docs/instructions.md b/exercises/practice/clock/.docs/instructions.md new file mode 100644 index 00000000..a1efc789 --- /dev/null +++ b/exercises/practice/clock/.docs/instructions.md @@ -0,0 +1,7 @@ +# Instructions + +Implement a clock that handles times without dates. + +You should be able to add and subtract minutes to it. + +Two clocks that represent the same time should be equal to each other. diff --git a/exercises/practice/clock/.meta/Clock.example.ps1 b/exercises/practice/clock/.meta/Clock.example.ps1 new file mode 100644 index 00000000..0429a21e --- /dev/null +++ b/exercises/practice/clock/.meta/Clock.example.ps1 @@ -0,0 +1,56 @@ +<# +.SYNOPSIS + Implement a clock that handles times without dates. + +.DESCRIPTION + Implement a clock that handles times without dates in 24 hours format. + You should be able to add and subtract minutes to it. + Two clocks that represent the same time should be equal to each other. + Note: Please try to implement the class and its method instead of using built-in module Datetime. + +.EXAMPLE + $clock1 = [Clock]::new(5,0) + $clock1.ToString() + Return: "05:00" + + $clock2 = [Clock]::new(6,-120) + $clock2.Add(60).ToString() + Return: "05:00" + + $clock1 -eq $clock2 + Return: $true +#> + +class Clock { + [int]$Hour + [int]$Minute + + Clock([int]$hour, [int]$minute) { + $this.NormalizeTime($hour, $minute) + } + + hidden [void] NormalizeTime([int]$hour, [int]$minute) { + $minsPerDay = 60 * 24 + $totalMinutes = ($hour * 60 + $minute) % $minsPerDay + if ($totalMinutes -lt 0) { + $totalMinutes += $minsPerDay + } + $this.Minute = $totalMinutes % 60 + $this.Hour = [Math]::Floor($totalMinutes / 60) + } + + [Clock] Add([int]$minutes = 0) { + $this.NormalizeTime($this.Hour, $this.Minute + $minutes) + return $this + } + + [string] ToString() { + $formatHour = '{0:D2}' -f $this.Hour + $formatMin = '{0:D2}' -f $this.Minute + return "${formatHour}:${formatMin}" + } + + [bool] Equals($otherClock) { + return $this.ToString() -eq $otherClock.ToString() + } +} \ No newline at end of file diff --git a/exercises/practice/clock/.meta/config.json b/exercises/practice/clock/.meta/config.json new file mode 100644 index 00000000..3fbc5137 --- /dev/null +++ b/exercises/practice/clock/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": ["glaxxie"], + "files": { + "solution": [ + "Clock.ps1" + ], + "test": [ + "Clock.tests.ps1" + ], + "example": [ + ".meta/Clock.example.ps1" + ] + }, + "blurb": "Implement a clock that handles times without dates.", + "source": "Pairing session with Erin Drummond", + "source_url": "https://twitter.com/ebdrummond" +} diff --git a/exercises/practice/clock/.meta/tests.toml b/exercises/practice/clock/.meta/tests.toml new file mode 100644 index 00000000..712c87bc --- /dev/null +++ b/exercises/practice/clock/.meta/tests.toml @@ -0,0 +1,166 @@ +# 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. + +[a577bacc-106b-496e-9792-b3083ea8705e] +description = "Create a new clock with an initial time -> on the hour" + +[b5d0c360-3b88-489b-8e84-68a1c7a4fa23] +description = "Create a new clock with an initial time -> past the hour" + +[473223f4-65f3-46ff-a9f7-7663c7e59440] +description = "Create a new clock with an initial time -> midnight is zero hours" + +[ca95d24a-5924-447d-9a96-b91c8334725c] +description = "Create a new clock with an initial time -> hour rolls over" + +[f3826de0-0925-4d69-8ac8-89aea7e52b78] +description = "Create a new clock with an initial time -> hour rolls over continuously" + +[a02f7edf-dfd4-4b11-b21a-86de3cc6a95c] +description = "Create a new clock with an initial time -> sixty minutes is next hour" + +[8f520df6-b816-444d-b90f-8a477789beb5] +description = "Create a new clock with an initial time -> minutes roll over" + +[c75c091b-47ac-4655-8d40-643767fc4eed] +description = "Create a new clock with an initial time -> minutes roll over continuously" + +[06343ecb-cf39-419d-a3f5-dcbae0cc4c57] +description = "Create a new clock with an initial time -> hour and minutes roll over" + +[be60810e-f5d9-4b58-9351-a9d1e90e660c] +description = "Create a new clock with an initial time -> hour and minutes roll over continuously" + +[1689107b-0b5c-4bea-aad3-65ec9859368a] +description = "Create a new clock with an initial time -> hour and minutes roll over to exactly midnight" + +[d3088ee8-91b7-4446-9e9d-5e2ad6219d91] +description = "Create a new clock with an initial time -> negative hour" + +[77ef6921-f120-4d29-bade-80d54aa43b54] +description = "Create a new clock with an initial time -> negative hour rolls over" + +[359294b5-972f-4546-bb9a-a85559065234] +description = "Create a new clock with an initial time -> negative hour rolls over continuously" + +[509db8b7-ac19-47cc-bd3a-a9d2f30b03c0] +description = "Create a new clock with an initial time -> negative minutes" + +[5d6bb225-130f-4084-84fd-9e0df8996f2a] +description = "Create a new clock with an initial time -> negative minutes roll over" + +[d483ceef-b520-4f0c-b94a-8d2d58cf0484] +description = "Create a new clock with an initial time -> negative minutes roll over continuously" + +[1cd19447-19c6-44bf-9d04-9f8305ccb9ea] +description = "Create a new clock with an initial time -> negative sixty minutes is previous hour" + +[9d3053aa-4f47-4afc-bd45-d67a72cef4dc] +description = "Create a new clock with an initial time -> negative hour and minutes both roll over" + +[51d41fcf-491e-4ca0-9cae-2aa4f0163ad4] +description = "Create a new clock with an initial time -> negative hour and minutes both roll over continuously" + +[d098e723-ad29-4ef9-997a-2693c4c9d89a] +description = "Add minutes -> add minutes" + +[b6ec8f38-e53e-4b22-92a7-60dab1f485f4] +description = "Add minutes -> add no minutes" + +[efd349dd-0785-453e-9ff8-d7452a8e7269] +description = "Add minutes -> add to next hour" + +[749890f7-aba9-4702-acce-87becf4ef9fe] +description = "Add minutes -> add more than one hour" + +[da63e4c1-1584-46e3-8d18-c9dc802c1713] +description = "Add minutes -> add more than two hours with carry" + +[be167a32-3d33-4cec-a8bc-accd47ddbb71] +description = "Add minutes -> add across midnight" + +[6672541e-cdae-46e4-8be7-a820cc3be2a8] +description = "Add minutes -> add more than one day (1500 min = 25 hrs)" + +[1918050d-c79b-4cb7-b707-b607e2745c7e] +description = "Add minutes -> add more than two days" + +[37336cac-5ede-43a5-9026-d426cbe40354] +description = "Subtract minutes -> subtract minutes" + +[0aafa4d0-3b5f-4b12-b3af-e3a9e09c047b] +description = "Subtract minutes -> subtract to previous hour" + +[9b4e809c-612f-4b15-aae0-1df0acb801b9] +description = "Subtract minutes -> subtract more than an hour" + +[8b04bb6a-3d33-4e6c-8de9-f5de6d2c70d6] +description = "Subtract minutes -> subtract across midnight" + +[07c3bbf7-ce4d-4658-86e8-4a77b7a5ccd9] +description = "Subtract minutes -> subtract more than two hours" + +[90ac8a1b-761c-4342-9c9c-cdc3ed5db097] +description = "Subtract minutes -> subtract more than two hours with borrow" + +[2149f985-7136-44ad-9b29-ec023a97a2b7] +description = "Subtract minutes -> subtract more than one day (1500 min = 25 hrs)" + +[ba11dbf0-ac27-4acb-ada9-3b853ec08c97] +description = "Subtract minutes -> subtract more than two days" + +[f2fdad51-499f-4c9b-a791-b28c9282e311] +description = "Compare two clocks for equality -> clocks with same time" + +[5d409d4b-f862-4960-901e-ec430160b768] +description = "Compare two clocks for equality -> clocks a minute apart" + +[a6045fcf-2b52-4a47-8bb2-ef10a064cba5] +description = "Compare two clocks for equality -> clocks an hour apart" + +[66b12758-0be5-448b-a13c-6a44bce83527] +description = "Compare two clocks for equality -> clocks with hour overflow" + +[2b19960c-212e-4a71-9aac-c581592f8111] +description = "Compare two clocks for equality -> clocks with hour overflow by several days" + +[6f8c6541-afac-4a92-b0c2-b10d4e50269f] +description = "Compare two clocks for equality -> clocks with negative hour" + +[bb9d5a68-e324-4bf5-a75e-0e9b1f97a90d] +description = "Compare two clocks for equality -> clocks with negative hour that wraps" + +[56c0326d-565b-4d19-a26f-63b3205778b7] +description = "Compare two clocks for equality -> clocks with negative hour that wraps multiple times" + +[c90b9de8-ddff-4ffe-9858-da44a40fdbc2] +description = "Compare two clocks for equality -> clocks with minute overflow" + +[533a3dc5-59a7-491b-b728-a7a34fe325de] +description = "Compare two clocks for equality -> clocks with minute overflow by several days" + +[fff49e15-f7b7-4692-a204-0f6052d62636] +description = "Compare two clocks for equality -> clocks with negative minute" + +[605c65bb-21bd-43eb-8f04-878edf508366] +description = "Compare two clocks for equality -> clocks with negative minute that wraps" + +[b87e64ed-212a-4335-91fd-56da8421d077] +description = "Compare two clocks for equality -> clocks with negative minute that wraps multiple times" + +[822fbf26-1f3b-4b13-b9bf-c914816b53dd] +description = "Compare two clocks for equality -> clocks with negative hours and minutes" + +[e787bccd-cf58-4a1d-841c-ff80eaaccfaa] +description = "Compare two clocks for equality -> clocks with negative hours and minutes that wrap" + +[96969ca8-875a-48a1-86ae-257a528c44f5] +description = "Compare two clocks for equality -> full clock and zeroed clock" diff --git a/exercises/practice/clock/Clock.ps1 b/exercises/practice/clock/Clock.ps1 new file mode 100644 index 00000000..2cda649e --- /dev/null +++ b/exercises/practice/clock/Clock.ps1 @@ -0,0 +1,36 @@ +<# +.SYNOPSIS + Implement a clock that handles times without dates. + +.DESCRIPTION + Implement a clock that handles times without dates in 24 hours format. + You should be able to add and subtract minutes to it. + Two clocks that represent the same time should be equal to each other. + Note: Please try to implement the class and its method instead of using built-in module Datetime. + +.EXAMPLE + $clock1 = [Clock]::new(5,0) + $clock1.ToString() + Return: "05:00" + + $clock2 = [Clock]::new(6,-120) + $clock2.Add(60).ToString() + Return: "05:00" + + $clock1 -eq $clock2 + Return: $true +#> + +class Clock { + Clock() { + Throw "Please implement this class" + } + + [string] ToString() { + Throw "Please implement this function" + } + + [bool] Equals() { + Throw "Please implement this function" + } +} \ No newline at end of file diff --git a/exercises/practice/clock/Clock.tests.ps1 b/exercises/practice/clock/Clock.tests.ps1 new file mode 100644 index 00000000..365429ba --- /dev/null +++ b/exercises/practice/clock/Clock.tests.ps1 @@ -0,0 +1,411 @@ +BeforeAll { + . "./Clock.ps1" +} + +Describe "Clock test cases" { + Context "create clock" { + It "on the hour" { + $clock = [Clock]::new(9, 0) + $got = $clock.ToString() + $want = '09:00' + + $got | Should -BeExactly $want + } + + It "past the hour" { + $clock = [Clock]::new(10, 23) + $got = $clock.ToString() + $want = '10:23' + + $got | Should -BeExactly $want + } + + It "midnight is zero hours" { + $clock = [Clock]::new(24, 0) + $got = $clock.ToString() + $want = '00:00' + + $got | Should -BeExactly $want + } + + It "hour rolls over" { + $clock = [Clock]::new(25, 0) + $got = $clock.ToString() + $want = '01:00' + + $got | Should -BeExactly $want + } + + It "hour rolls over continuously" { + $clock = [Clock]::new(100, 0) + $got = $clock.ToString() + $want = '04:00' + + $got | Should -BeExactly $want + } + + It "sixty minutes is next hour" { + $clock = [Clock]::new(2, 60) + $got = $clock.ToString() + $want = '03:00' + + $got | Should -BeExactly $want + } + + It "minutes roll over" { + $clock = [Clock]::new(0, 175) + $got = $clock.ToString() + $want = '02:55' + + $got | Should -BeExactly $want + } + + It "minutes roll over continuously" { + $clock = [Clock]::new(0, 1723) + $got = $clock.ToString() + $want = '04:43' + + $got | Should -BeExactly $want + } + + It "hour and minutes roll over" { + $clock = [Clock]::new(25, 160) + $got = $clock.ToString() + $want = '03:40' + + $got | Should -BeExactly $want + } + + It "hour and minutes roll over continuously" { + $clock = [Clock]::new(200, 3015) + $got = $clock.ToString() + $want = '10:15' + + $got | Should -BeExactly $want + } + + It "hour and minutes roll over to exactly midnight" { + $clock = [Clock]::new(96, 10080) + $got = $clock.ToString() + $want = '00:00' + + $got | Should -BeExactly $want + } + + It "negative hour" { + $clock = [Clock]::new(-2,25) + $got = $clock.ToString() + $want = '22:25' + + $got | Should -BeExactly $want + } + + It "negative hour rolls over" { + $clock = [Clock]::new(-27, 0) + $got = $clock.ToString() + $want = '21:00' + + $got | Should -BeExactly $want + } + + It "negative hour rolls over continuously" { + $clock = [Clock]::new(-91, 0) + $got = $clock.ToString() + $want = '05:00' + + $got | Should -BeExactly $want + } + + It "negative minutes" { + $clock = [Clock]::new(5, -35) + $got = $clock.ToString() + $want = '04:25' + + $got | Should -BeExactly $want + } + + It "negative minutes roll over" { + $clock = [Clock]::new(2, -160) + $got = $clock.ToString() + $want = '23:20' + + $got | Should -BeExactly $want + } + + It "negative minutes roll over continuously" { + $clock = [Clock]::new(1, -4820) + $got = $clock.ToString() + $want = '16:40' + + $got | Should -BeExactly $want + } + + It "negative sixty minutes is previous hour" { + $clock = [Clock]::new(14, -60) + $got = $clock.ToString() + $want = '13:00' + + $got | Should -BeExactly $want + } + + It "negative hour and minutes roll over" { + $clock = [Clock]::new(-25, -160) + $got = $clock.ToString() + $want = '20:20' + + $got | Should -BeExactly $want + } + + It "negative hour and minutes roll over continuously" { + $clock = [Clock]::new(-121, -5810) + $got = $clock.ToString() + $want = '22:10' + + $got | Should -BeExactly $want + } + } + + Context "add and subtract" { + It "add minutes" { + $clock = [Clock]::new(11, 0) + $got = $clock.Add(8).ToString() + $want = '11:08' + + $got | Should -BeExactly $want + } + + It "add no minutes" { + $clock = [Clock]::new(12, 34) + $got = $clock.Add(0).ToString() + $want = '12:34' + + $got | Should -BeExactly $want + } + + It "add to next hour" { + $clock = [Clock]::new(12, 45) + $got = $clock.Add(37).ToString() + $want = '13:22' + + $got | Should -BeExactly $want + } + + It "add more than one hour" { + $clock = [Clock]::new(7, 0) + $got = $clock.Add(75).ToString() + $want = '08:15' + + $got | Should -BeExactly $want + } + + It "add more than two hours with carry" { + $clock = [Clock]::new(0, 50) + $got = $clock.Add(170).ToString() + $want = '03:40' + + $got | Should -BeExactly $want + } + + It "add across midnight" { + $clock = [Clock]::new(23, 57) + $got = $clock.Add(10).ToString() + $want = '00:07' + + $got | Should -BeExactly $want + } + + It "add more than one day (1500 min = 25 hrs)" { + $clock = [Clock]::new(6, 48) + $got = $clock.Add(1500).ToString() + $want = '07:48' + + $got | Should -BeExactly $want + } + + It "add more than two days" { + $clock = [Clock]::new(2, 3) + $got = $clock.Add(3500).ToString() + $want = '12:23' + + $got | Should -BeExactly $want + } + + It "subtract minutes" { + $clock = [Clock]::new(8, 45) + $got = $clock.Add(-5).ToString() + $want = '08:40' + + $got | Should -BeExactly $want + } + + It "subtract to previous hour" { + $clock = [Clock]::new(11, 12) + $got = $clock.Add(-25).ToString() + $want = '10:47' + + $got | Should -BeExactly $want + } + + It "subtract more than an hour" { + $clock = [Clock]::new(12, 20) + $got = $clock.Add(-70).ToString() + $want = '11:10' + + $got | Should -BeExactly $want + } + + It "subtract across midnight" { + $clock = [Clock]::new(0, 7) + $got = $clock.Add(-9).ToString() + $want = '23:58' + + $got | Should -BeExactly $want + } + + It "subtract more than two hours" { + $clock = [Clock]::new(0, 0) + $got = $clock.Add(-150).ToString() + $want = '21:30' + + $got | Should -BeExactly $want + } + + It "subtract more than two hours with borrow" { + $clock = [Clock]::new(6, 15) + $got = $clock.Add(-160).ToString() + $want = '03:35' + + $got | Should -BeExactly $want + } + + It "subtract more than one day (1500 min = 25 hrs)" { + $clock = [Clock]::new(3, 30) + $got = $clock.Add(-1500).ToString() + $want = '02:30' + + $got | Should -BeExactly $want + } + + It "subtract more than two days" { + $clock = [Clock]::new(7, 49) + $got = $clock.Add(-3000).ToString() + $want = '05:49' + + $got | Should -BeExactly $want + } + } + + Context "equality test" { + It "clocks with same time" { + $got = [Clock]::new(12, 34) -eq [Clock]::new(12, 34) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks a minute apart" { + $got = [Clock]::new(12, 34) -eq [Clock]::new(12, 35) + $want = $false + + $got | Should -BeExactly $want + } + + It "clocks an hour apart" { + $got = [Clock]::new(12, 34) -eq [Clock]::new(11, 34) + $want = $false + + $got | Should -BeExactly $want + } + + It "clocks with hour overflow" { + $got = [Clock]::new(11, 26) -eq [Clock]::new(35, 26) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with hour overflow by several days" { + $got = [Clock]::new(3, 15) -eq [Clock]::new(99, 15) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with negative hour" { + $got = [Clock]::new(21, 40) -eq [Clock]::new(-3, 40) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with negative hour that wraps" { + $got = [Clock]::new(17, 3) -eq [Clock]::new(-31, 3) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with negative hour that wraps multiple times" { + $got = [Clock]::new(13, 49) -eq [Clock]::new(-83, 49) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with minute overflow" { + $got = [Clock]::new(0, 11) -eq [Clock]::new(0, 1451) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with minute overflow by several days" { + $got = [Clock]::new(2, 2) -eq [Clock]::new(2, 4322) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with negative minute" { + $got = [Clock]::new(5, 30) -eq [Clock]::new(6, -30) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with negative minute that wraps" { + $got = [Clock]::new(4, 10) -eq [Clock]::new(5, -1490) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with negative minute that wraps multiple times" { + $got = [Clock]::new(6, 15) -eq [Clock]::new(6, -4305) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with negative hours and minutes" { + $got = [Clock]::new(4, 10) -eq [Clock]::new(5, -1490) + $want = $true + + $got | Should -BeExactly $want + } + + It "clocks with negative hours and minutes that wrap" { + $got = [Clock]::new(7, 32) -eq [Clock]::new(-12, -268) + $want = $true + + $got | Should -BeExactly $want + } + + It "full clock and zeroed clock" { + $got = [Clock]::new(18, 7) -eq [Clock]::new(-54, -11513) + $want = $true + + $got | Should -BeExactly $want + } + } +} \ No newline at end of file From f05e3a8c558de822fc3f0cabde58aab69be82fca Mon Sep 17 00:00:00 2001 From: glaxxie <86179463+glaxxie@users.noreply.github.com> Date: Tue, 29 Aug 2023 15:45:27 -0500 Subject: [PATCH 2/5] [New Exercise]: State of Tic-tac-toe (#254) --- config.json | 8 + .../.docs/instructions.append.md | 4 + .../.docs/instructions.md | 101 +++++++ .../.meta/StateOfTicTacToe.example.ps1 | 123 ++++++++ .../state-of-tic-tac-toe/.meta/config.json | 19 ++ .../state-of-tic-tac-toe/.meta/tests.toml | 101 +++++++ .../state-of-tic-tac-toe/StateOfTicTacToe.ps1 | 32 ++ .../StateOfTicTacToe.tests.ps1 | 275 ++++++++++++++++++ 8 files changed, 663 insertions(+) create mode 100644 exercises/practice/state-of-tic-tac-toe/.docs/instructions.append.md create mode 100644 exercises/practice/state-of-tic-tac-toe/.docs/instructions.md create mode 100644 exercises/practice/state-of-tic-tac-toe/.meta/StateOfTicTacToe.example.ps1 create mode 100644 exercises/practice/state-of-tic-tac-toe/.meta/config.json create mode 100644 exercises/practice/state-of-tic-tac-toe/.meta/tests.toml create mode 100644 exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.ps1 create mode 100644 exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.tests.ps1 diff --git a/config.json b/config.json index e1241d3f..8013a334 100644 --- a/config.json +++ b/config.json @@ -592,6 +592,14 @@ "practices": [], "prerequisites": [], "difficulty": 4 + }, + { + "slug": "state-of-tic-tac-toe", + "name": "State of Tic-Tac-Toe", + "uuid": "c07e6ad9-9172-4dc8-871d-7d0581e1504f", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/state-of-tic-tac-toe/.docs/instructions.append.md b/exercises/practice/state-of-tic-tac-toe/.docs/instructions.append.md new file mode 100644 index 00000000..4f8cf9bf --- /dev/null +++ b/exercises/practice/state-of-tic-tac-toe/.docs/instructions.append.md @@ -0,0 +1,4 @@ +# About Enum +Use Enum values to show the game state, e.g. ONGOING + +To know more about Enum in powershell please check out [Enum module.](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_enum) \ No newline at end of file diff --git a/exercises/practice/state-of-tic-tac-toe/.docs/instructions.md b/exercises/practice/state-of-tic-tac-toe/.docs/instructions.md new file mode 100644 index 00000000..f525d358 --- /dev/null +++ b/exercises/practice/state-of-tic-tac-toe/.docs/instructions.md @@ -0,0 +1,101 @@ +# Instructions + +In this exercise, you're going to implement a program that determines the state of a [tic-tac-toe][] game. +(_You may also know the game as "noughts and crosses" or "Xs and Os"._) + +The games is played on a 3×3 grid. +Players take turns to place `X`s and `O`s on the grid. +The game ends when one player has won by placing three of marks in a row, column, or along a diagonal of the grid, or when the entire grid is filled up. + +In this exercise, we will assume that `X` starts. + +It's your job to determine which state a given game is in. + +There are 3 potential game states: + +- The game is **ongoing**. +- The game ended in a **draw**. +- The game ended in a **win**. + +If the given board is invalid, throw an appropriate error. + +If a board meets the following conditions, it is invalid: + +- The given board cannot be reached when turns are taken in the correct order (remember that `X` starts). +- The game was played after it already ended. + +## Examples + +### Ongoing game + +```text + | | + X | | +___|___|___ + | | + | X | O +___|___|___ + | | + O | X | + | | +``` + +### Draw + +```text + | | + X | O | X +___|___|___ + | | + X | X | O +___|___|___ + | | + O | X | O + | | +``` + +### Win + +```text + | | + X | X | X +___|___|___ + | | + | O | O +___|___|___ + | | + | | + | | +``` + +### Invalid + +#### Wrong turn order + +```text + | | + O | O | X +___|___|___ + | | + | | +___|___|___ + | | + | | + | | +``` + +#### Continued playing after win + +```text + | | + X | X | X +___|___|___ + | | + O | O | O +___|___|___ + | | + | | + | | +``` + +[tic-tac-toe]: https://en.wikipedia.org/wiki/Tic-tac-toe diff --git a/exercises/practice/state-of-tic-tac-toe/.meta/StateOfTicTacToe.example.ps1 b/exercises/practice/state-of-tic-tac-toe/.meta/StateOfTicTacToe.example.ps1 new file mode 100644 index 00000000..0208de1f --- /dev/null +++ b/exercises/practice/state-of-tic-tac-toe/.meta/StateOfTicTacToe.example.ps1 @@ -0,0 +1,123 @@ +Enum GameStatus { + WIN + DRAW + ONGOING +} + +Function Get-StateOfTicTacToe() { + <# + .SYNOPSIS + Implement a program that determines the state of a tic-tac-toe game. + + .DESCRIPTION + The games is played on a 3×3 grid represent by an array of 3 strings. + Players take turns to place `X`s and `O`s on the grid. + The game ends: + - when one player has won by placing three of marks in a row, column, or along a diagonal of the grid + - when the entire grid is filled up + + In this exercise, we will assume that `X` always starts first. + + .PARAMETER Board + An array of 3 strings represeting the board in the form of 3x3 grid. + + .EXAMPLE + $grid = @( + "XXO", + "X ", + "X " + ) + Get-StateOfTicTacToe -Board $grid + Returns: [GameStatus]::WIN + #> + [CmdletBinding()] + Param( + [string[]]$Board + ) + + $combinedString = (-join $Board).ToCharArray() | Group-Object -AsHashTable -AsString + $Xs = $combinedString.X.Count + $Os = $combinedString.O.Count + $empty = $combinedString.' '.Count + + Test-ValidBoard $Xs $Os + + if (Test-Winner $Board $Xs $Os) { + $gameState = [GameStatus]::WIN + }else { + $gameState = $empty ? [GameStatus]::ONGOING : [GameStatus]::DRAW + } + $gameState +} + +Function Test-ValidBoard($Xcount, $Ocount) { + <# + .DESCRIPTION + A helper function to test if the board is valid based on count of X and O + #> + if (($Xcount - $Ocount) -gt 1) { + Throw "Wrong turn order: X went twice" + } + if ($Ocount -gt $Xcount) { + Throw "Wrong turn order: O started" + } +} + +Function Test-Winner($board, $Xcount, $Ocount) { + <# + .DESCRIPTION + A helper function to check if there is a winner, and if the winner is in a valid state + Winner validation logic based on the fact that X goes first + - If X win, then X count - O count must be equal 1 + - If X win, then X count and O count must be equal + #> + $hasWinner = $false + $wholeBoard = $board + (Get-Columns $board) + (Get-Diagonals $board) + + $wincon = @{ + 'XXX' = {param($x,$o) ($x - $o) -eq 1 } + 'OOO' = {param($x,$o) $x -eq $o } + } + + foreach ($pattern in $wincon.Keys) { + if ($wholeBoard -contains $pattern) { + $validCheck = $wincon[$pattern] + if (& $validCheck $Xcount $Ocount) { + $hasWinner = $true + } else { + Throw "Impossible board: game should have ended after the game was won" + } + } + } + $hasWinner +} + +Function Get-Columns($board) { + <# + .DESCRIPTION + A helper function get all the columns string, this work for any square NxN size grid + #> + $columns = 0..($board.Count-1) | ForEach-Object { + $index = $_ + $col = -join ($board | ForEach-Object {$_[$index]}) + $col + } + $columns +} + +Function Get-Diagonals($board) { + <# + .DESCRIPTION + A helper function get the 2 diagonals string, this work for any square NxN size grid + #> + $size = $board.Count + + $risingDiagonal = @() + $fallingDiagonal = @() + + for ($i = 0; $i -lt $size; $i++) { + $risingDiagonal += $board[$i][$i] + $fallingDiagonal += $board[$i][$size - 1 - $i] + } + -join $risingDiagonal, -join $fallingDiagonal +} \ No newline at end of file diff --git a/exercises/practice/state-of-tic-tac-toe/.meta/config.json b/exercises/practice/state-of-tic-tac-toe/.meta/config.json new file mode 100644 index 00000000..53a2acf1 --- /dev/null +++ b/exercises/practice/state-of-tic-tac-toe/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glaxxie" + ], + "files": { + "solution": [ + "StateOfTicTacToe.ps1" + ], + "test": [ + "StateOfTicTacToe.tests.ps1" + ], + "example": [ + ".meta/StateOfTicTacToe.example.ps1" + ] + }, + "blurb": "Determine the game state of a match of Tic-Tac-Toe.", + "source": "Created by Sascha Mann for the Julia track of the Exercism Research Experiment.", + "source_url": "https://github.com/exercism/research_experiment_1/tree/julia-dev/exercises/julia-1-a" +} diff --git a/exercises/practice/state-of-tic-tac-toe/.meta/tests.toml b/exercises/practice/state-of-tic-tac-toe/.meta/tests.toml new file mode 100644 index 00000000..8fc25e21 --- /dev/null +++ b/exercises/practice/state-of-tic-tac-toe/.meta/tests.toml @@ -0,0 +1,101 @@ +# 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. + +[fe8e9fa9-37af-4d7e-aa24-2f4b8517161a] +description = "Won games -> Finished game where X won via left column victory" + +[96c30df5-ae23-4cf6-bf09-5ef056dddea1] +description = "Won games -> Finished game where X won via middle column victory" + +[0d7a4b0a-2afd-4a75-8389-5fb88ab05eda] +description = "Won games -> Finished game where X won via right column victory" + +[bd1007c0-ec5d-4c60-bb9f-1a4f22177d51] +description = "Won games -> Finished game where O won via left column victory" + +[c032f800-5735-4354-b1b9-46f14d4ee955] +description = "Won games -> Finished game where O won via middle column victory" + +[662c8902-c94a-4c4c-9d9c-e8ca513db2b4] +description = "Won games -> Finished game where O won via right column victory" + +[2d62121f-7e3a-44a0-9032-0d73e3494941] +description = "Won games -> Finished game where X won via top row victory" + +[108a5e82-cc61-409f-aece-d7a18c1beceb] +description = "Won games -> Finished game where X won via middle row victory" +include = false + +[346527db-4db9-4a96-b262-d7023dc022b0] +description = "Won games -> Finished game where X won via middle row victory" +reimplements = "108a5e82-cc61-409f-aece-d7a18c1beceb" + +[a013c583-75f8-4ab2-8d68-57688ff04574] +description = "Won games -> Finished game where X won via bottom row victory" + +[2c08e7d7-7d00-487f-9442-e7398c8f1727] +description = "Won games -> Finished game where O won via top row victory" + +[bb1d6c62-3e3f-4d1a-9766-f8803c8ed70f] +description = "Won games -> Finished game where O won via middle row victory" + +[6ef641e9-12ec-44f5-a21c-660ea93907af] +description = "Won games -> Finished game where O won via bottom row victory" + +[ab145b7b-26a7-426c-ab71-bf418cd07f81] +description = "Won games -> Finished game where X won via falling diagonal victory" + +[7450caab-08f5-4f03-a74b-99b98c4b7a4b] +description = "Won games -> Finished game where X won via rising diagonal victory" + +[c2a652ee-2f93-48aa-a710-a70cd2edce61] +description = "Won games -> Finished game where O won via falling diagonal victory" + +[5b20ceea-494d-4f0c-a986-b99efc163bcf] +description = "Won games -> Finished game where O won via rising diagonal victory" + +[035a49b9-dc35-47d3-9d7c-de197161b9d4] +description = "Won games -> Finished game where X won via a row and a column victory" + +[e5dfdeb0-d2bf-4b5a-b307-e673f69d4a53] +description = "Won games -> Finished game where X won via two diagonal victories" + +[b42ed767-194c-4364-b36e-efbfb3de8788] +description = "Drawn games -> Draw" + +[227a76b2-0fef-4e16-a4bd-8f9d7e4c3b13] +description = "Drawn games -> Another draw" + +[4d93f15c-0c40-43d6-b966-418b040012a9] +description = "Ongoing games -> Ongoing game: one move in" + +[c407ae32-4c44-4989-b124-2890cf531f19] +description = "Ongoing games -> Ongoing game: two moves in" + +[199b7a8d-e2b6-4526-a85e-78b416e7a8a9] +description = "Ongoing games -> Ongoing game: five moves in" + +[1670145b-1e3d-4269-a7eb-53cd327b302e] +description = "Invalid boards -> Invalid board: X went twice" + +[47c048e8-b404-4bcf-9e51-8acbb3253f3b] +description = "Invalid boards -> Invalid board: O started" + +[b1dc8b13-46c4-47db-a96d-aa90eedc4e8d] +description = "Invalid boards -> Invalid board" +include = false + +[6c1920f2-ab5c-4648-a0c9-997414dda5eb] +description = "Invalid boards -> Invalid board: X won and O kept playing" +reimplements = "b1dc8b13-46c4-47db-a96d-aa90eedc4e8d" + +[4801cda2-f5b7-4c36-8317-3cdd167ac22c] +description = "Invalid boards -> Invalid board: players kept playing after a win" diff --git a/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.ps1 b/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.ps1 new file mode 100644 index 00000000..e213d14e --- /dev/null +++ b/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.ps1 @@ -0,0 +1,32 @@ +Function Get-StateOfTicTacToe() { + <# + .SYNOPSIS + Implement a program that determines the state of a tic-tac-toe game. + + .DESCRIPTION + The games is played on a 3×3 grid represent by an array of 3 strings. + Players take turns to place `X`s and `O`s on the grid. + The game ends: + - when one player has won by placing three of marks in a row, column, or along a diagonal of the grid + - when the entire grid is filled up + + In this exercise, we will assume that `X` always starts first. + + .PARAMETER Board + An array of 3 strings represeting the board in the form of 3x3 grid. + + .EXAMPLE + $board = @( + "XXO", + "X ", + "X " + ) + Get-StateOfTicTacToe -Board $board + Returns: [GameStatus]::WIN + #> + [CmdletBinding()] + Param( + [string[]]$Board + ) + Throw "Please implement this function" +} \ No newline at end of file diff --git a/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.tests.ps1 b/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.tests.ps1 new file mode 100644 index 00000000..18c31596 --- /dev/null +++ b/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.tests.ps1 @@ -0,0 +1,275 @@ +BeforeAll { + . "./StateOfTicTacToe.ps1" +} + +Describe "StateOfTicTacToe test cases" { + Context "won games" { + It "Finished game where X won via left column victory" { + $grid = @("XOO", + "X ", + "X ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where X won via middle column victory" { + $grid = @("OXO", + " X ", + " X ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where X won via right column victory" { + $grid = @("OOX", + " X", + " X") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where O won via left column victory" { + $grid = @("OXX", + "OX ", + "O ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where O won via middle column victory" { + $grid = @("XOX", + " OX", + " O ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where O won via right column victory" { + $grid = @("XXO", + " XO", + " O") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where X won via top row victory" { + $grid = @("XXX", + "XOO", + "O ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where X won via middle row victory" { + $grid = @("O ", + "XXX", + " O ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where X won via bottom row victory" { + $grid = @(" OO", + "O X", + "XXX") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where O won via top row victory" { + $grid = @("OOO", + "XXO", + "XX ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where O won via middle row victory" { + $grid = @("XX ", + "OOO", + "X ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where O won via bottom row victory" { + $grid = @("XOX", + " XX", + "OOO") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where X won via falling diagonal victory" { + $grid = @("XOO", + " X ", + " X") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where X won via rising diagonal victory" { + $grid = @("O X", + "OX ", + "X ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where O won via falling diagonal victory" { + $grid = @("OXX", + "OOX", + "X O") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where O won via rising diagonal victory" { + $grid = @(" O", + " OX", + "OXX") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where X won via a row and a column victory" { + $grid = @("XXX", + "XOO", + "XOO") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + + It "Finished game where X won via two diagonal victories" { + $grid = @("XOX", + "OXO", + "XOX") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::WIN + + $got | Should -BeExactly $want + } + } + + Context "drawn games" { + It "draw game" { + $grid = @("XOX", + "XXO", + "OXO") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::DRAW + + $got | Should -BeExactly $want + } + + It "Another draw" { + $grid = @("XXO", + "OXX", + "XOO") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::DRAW + + $got | Should -BeExactly $want + } + } + + Context "ongoing games" { + It "Ongoing game: one move in" { + $grid = @(" ", + "X ", + " ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::ONGOING + + $got | Should -BeExactly $want + } + + It "Ongoing game: two moves in" { + $grid = @("O ", + " X ", + " ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::ONGOING + + $got | Should -BeExactly $want + } + + It "Ongoing game: five moves in" { + $grid = @("X ", + " XO", + "OX ") + $got = Get-StateOfTicTacToe -Board $grid + $want = [GameStatus]::ONGOING + + $got | Should -BeExactly $want + } + } + + Context "invalud boards" { + It "Invalid board: X went twice" { + $grid = @("XX ", + " ", + " ") + + {Get-StateOfTicTacToe -Board $grid} | Should -Throw "Wrong turn order: X went twice" + } + + It "Invalid board: O started" { + $grid = @("OOX", + " ", + " ") + + {Get-StateOfTicTacToe -Board $grid} | Should -Throw "Wrong turn order: O started" + } + + It "Invalid board: X won and O kept playing" { + $grid = @("XXX", + "OOO", + " ") + + {Get-StateOfTicTacToe -Board $grid} | Should -Throw "Impossible board: game should have ended after the game was won" + } + + It "Invalid board: players kept playing after a win" { + $grid = @("XXX", + "OOO", + "XOX") + + {Get-StateOfTicTacToe -Board $grid} | Should -Throw "Impossible board: game should have ended after the game was won" + } + } +} From 9d66f4d9b1337274d947bb19b31d7ce47e9edbae Mon Sep 17 00:00:00 2001 From: glaxxie <86179463+glaxxie@users.noreply.github.com> Date: Thu, 31 Aug 2023 07:11:40 -0500 Subject: [PATCH 3/5] [New Exercise]: Secret Handshake (#255) * add secret handshake * update description --- config.json | 8 ++ .../secret-handshake/.docs/instructions.md | 48 +++++++++++ .../secret-handshake/.docs/introduction.md | 7 ++ .../.meta/SecretHandshake.example.ps1 | 47 +++++++++++ .../secret-handshake/.meta/config.json | 19 +++++ .../secret-handshake/.meta/tests.toml | 43 ++++++++++ .../secret-handshake/SecretHandshake.ps1 | 29 +++++++ .../SecretHandshake.tests.ps1 | 83 +++++++++++++++++++ 8 files changed, 284 insertions(+) create mode 100644 exercises/practice/secret-handshake/.docs/instructions.md create mode 100644 exercises/practice/secret-handshake/.docs/introduction.md create mode 100644 exercises/practice/secret-handshake/.meta/SecretHandshake.example.ps1 create mode 100644 exercises/practice/secret-handshake/.meta/config.json create mode 100644 exercises/practice/secret-handshake/.meta/tests.toml create mode 100644 exercises/practice/secret-handshake/SecretHandshake.ps1 create mode 100644 exercises/practice/secret-handshake/SecretHandshake.tests.ps1 diff --git a/config.json b/config.json index 8013a334..375bb1c6 100644 --- a/config.json +++ b/config.json @@ -105,6 +105,14 @@ "transforming" ] }, + { + "slug": "secret-handshake", + "name": "Secret Handshake", + "uuid": "d2378d74-bfb7-4f80-ad3e-dc0db0d90352", + "practices": [], + "prerequisites": [], + "difficulty": 1 + }, { "slug": "raindrops", "name": "Raindrops", diff --git a/exercises/practice/secret-handshake/.docs/instructions.md b/exercises/practice/secret-handshake/.docs/instructions.md new file mode 100644 index 00000000..d2120b9b --- /dev/null +++ b/exercises/practice/secret-handshake/.docs/instructions.md @@ -0,0 +1,48 @@ +# Instructions + +Your task is to convert a number between 1 and 31 to a sequence of actions in the secret handshake. + +The sequence of actions is chosen by looking at the rightmost five digits of the number once it's been converted to binary. +Start at the right-most digit and move left. + +The actions for each number place are: + +```plaintext +00001 = wink +00010 = double blink +00100 = close your eyes +01000 = jump +10000 = Reverse the order of the operations in the secret handshake. +``` + +Let's use the number `9` as an example: + +- 9 in binary is `1001`. +- The digit that is farthest to the right is 1, so the first action is `wink`. +- Going left, the next digit is 0, so there is no double-blink. +- Going left again, the next digit is 0, so you leave your eyes open. +- Going left again, the next digit is 1, so you jump. + +That was the last digit, so the final code is: + +```plaintext +wink, jump +``` + +Given the number 26, which is `11010` in binary, we get the following actions: + +- double blink +- jump +- reverse actions + +The secret handshake for 26 is therefore: + +```plaintext +jump, double blink +``` + +~~~~exercism/note +If you aren't sure what binary is or how it works, check out [this binary tutorial][intro-to-binary]. + +[intro-to-binary]: https://medium.com/basecs/bits-bytes-building-with-binary-13cb4289aafa +~~~~ diff --git a/exercises/practice/secret-handshake/.docs/introduction.md b/exercises/practice/secret-handshake/.docs/introduction.md new file mode 100644 index 00000000..176b92e8 --- /dev/null +++ b/exercises/practice/secret-handshake/.docs/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +You are starting a secret coding club with some friends and friends-of-friends. +Not everyone knows each other, so you and your friends have decided to create a secret handshake that you can use to recognize that someone is a member. +You don't want anyone who isn't in the know to be able to crack the code. + +You've designed the code so that one person says a number between 1 and 31, and the other person turns it into a series of actions. diff --git a/exercises/practice/secret-handshake/.meta/SecretHandshake.example.ps1 b/exercises/practice/secret-handshake/.meta/SecretHandshake.example.ps1 new file mode 100644 index 00000000..56de06bf --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/SecretHandshake.example.ps1 @@ -0,0 +1,47 @@ +Function Invoke-SecretHandshake() { + <# + .SYNOPSIS + Convert a number between 1 and 31 to a sequence of actions in the secret handshake. + + .DESCRIPTION + The sequence of actions is chosen by looking at the rightmost five digits of the number once it's been converted to binary. + Start at the right-most digit and move left. + + The actions for each number place are: + 00001 = wink + 00010 = double blink + 00100 = close your eyes + 01000 = jump + 10000 = Reverse the order of the operations in the secret handshake. + + .PARAMETER Number + The value to be converted into a sequence of actions. + + .EXAMPLE + Invoke-SecretHandshake -Number 2 + Returns: @("double blink") + #> + [CmdletBinding()] + Param( + [int]$Number + ) + + if ($Number -lt 1 -or $Number -gt 31) { + return @() + } + + $actions = @{ + 1 = "wink" + 2 = "double blink" + 4 = "close your eyes" + 8 = "jump" + } + + $sequence = $actions.Keys | Where-Object { $Number -band $_ } | ForEach-Object { $actions.$_ } + + if (-not ($Number -band 16)) { + [Array]::Reverse($sequence) + } + + $sequence +} \ No newline at end of file diff --git a/exercises/practice/secret-handshake/.meta/config.json b/exercises/practice/secret-handshake/.meta/config.json new file mode 100644 index 00000000..2243ea3d --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glaxxie" + ], + "files": { + "solution": [ + "SecretHandshake.ps1" + ], + "test": [ + "SecretHandshake.tests.ps1" + ], + "example": [ + ".meta/SecretHandshake.example.ps1" + ] + }, + "blurb": "Given a decimal number, convert it to the appropriate sequence of events for a secret handshake.", + "source": "Bert, in Mary Poppins", + "source_url": "https://www.imdb.com/title/tt0058331/quotes/?item=qt0437047" +} diff --git a/exercises/practice/secret-handshake/.meta/tests.toml b/exercises/practice/secret-handshake/.meta/tests.toml new file mode 100644 index 00000000..f318e528 --- /dev/null +++ b/exercises/practice/secret-handshake/.meta/tests.toml @@ -0,0 +1,43 @@ +# 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. + +[b8496fbd-6778-468c-8054-648d03c4bb23] +description = "wink for 1" + +[83ec6c58-81a9-4fd1-bfaf-0160514fc0e3] +description = "double blink for 10" + +[0e20e466-3519-4134-8082-5639d85fef71] +description = "close your eyes for 100" + +[b339ddbb-88b7-4b7d-9b19-4134030d9ac0] +description = "jump for 1000" + +[40499fb4-e60c-43d7-8b98-0de3ca44e0eb] +description = "combine two actions" + +[9730cdd5-ef27-494b-afd3-5c91ad6c3d9d] +description = "reverse two actions" + +[0b828205-51ca-45cd-90d5-f2506013f25f] +description = "reversing one action gives the same action" + +[9949e2ac-6c9c-4330-b685-2089ab28b05f] +description = "reversing no actions still gives no actions" + +[23fdca98-676b-4848-970d-cfed7be39f81] +description = "all possible actions" + +[ae8fe006-d910-4d6f-be00-54b7c3799e79] +description = "reverse all possible actions" + +[3d36da37-b31f-4cdb-a396-d93a2ee1c4a5] +description = "do nothing for zero" diff --git a/exercises/practice/secret-handshake/SecretHandshake.ps1 b/exercises/practice/secret-handshake/SecretHandshake.ps1 new file mode 100644 index 00000000..c0e58ead --- /dev/null +++ b/exercises/practice/secret-handshake/SecretHandshake.ps1 @@ -0,0 +1,29 @@ +Function Invoke-SecretHandshake() { + <# + .SYNOPSIS + Convert a number between 1 and 31 to a sequence of actions in the secret handshake. + + .DESCRIPTION + The sequence of actions is chosen by looking at the rightmost five digits of the number once it's been converted to binary. + Start at the right-most digit and move left. + + The actions for each number place are: + 00001 = wink + 00010 = double blink + 00100 = close your eyes + 01000 = jump + 10000 = Reverse the order of the operations in the secret handshake. + + .PARAMETER Number + The value to be converted into a sequence of actions. + + .EXAMPLE + Invoke-SecretHandshake -Number 2 + Returns: @("double blink") + #> + [CmdletBinding()] + Param( + [int]$Number + ) + Throw "Please implement this function" +} \ No newline at end of file diff --git a/exercises/practice/secret-handshake/SecretHandshake.tests.ps1 b/exercises/practice/secret-handshake/SecretHandshake.tests.ps1 new file mode 100644 index 00000000..724bc35e --- /dev/null +++ b/exercises/practice/secret-handshake/SecretHandshake.tests.ps1 @@ -0,0 +1,83 @@ +BeforeAll { + . "./SecretHandshake.ps1" +} + +Describe "SecretHandshake test cases" { + It "wink for 1" { + $got = Invoke-SecretHandshake -Number 1 + $want = @("wink") + + $got | Should -BeExactly $want + } + + It "double blink for 10" { + $got = Invoke-SecretHandshake -Number 2 + $want = @("double blink") + + $got | Should -BeExactly $want + } + + It "close your eyes for 100" { + $got = Invoke-SecretHandshake -Number 4 + $want = @("close your eyes") + + $got | Should -BeExactly $want + } + + It "jump for 1000" { + $got = Invoke-SecretHandshake -Number 8 + $want = @("jump") + + $got | Should -BeExactly $want + } + + It "combine two actions" { + $got = Invoke-SecretHandshake -Number 3 + $want = @("wink", "double blink") + + $got | Should -BeExactly $want + } + + It "reverse two actions" { + $got = Invoke-SecretHandshake -Number 19 + $want = @("double blink", "wink") + + $got | Should -BeExactly $want + } + + It "reversing one action gives the same action" { + $got = Invoke-SecretHandshake -Number 24 + $want = @("jump") + + $got | Should -BeExactly $want + } + + It "reversing no actions still gives no actions" { + $got = Invoke-SecretHandshake -Number 16 + $want = @() + + $got | Should -BeExactly $want + } + + It "all possible actions" { + $got = Invoke-SecretHandshake -Number 15 + $want = @("wink", "double blink", "close your eyes", "jump") + + $got | Should -BeExactly $want + } + + It "reverse all possible actions" { + $got = Invoke-SecretHandshake -Number 31 + $want = @("jump", "close your eyes", "double blink", "wink") + + $got | Should -BeExactly $want + } + + It "do nothing for zero" { + $got = Invoke-SecretHandshake -Number 0 + $want = @() + + $got | Should -BeExactly $want + } + +} From 2ab8ae876276b623260c3afc13fe0b2c0f373599 Mon Sep 17 00:00:00 2001 From: glaxxie <86179463+glaxxie@users.noreply.github.com> Date: Thu, 31 Aug 2023 07:11:58 -0500 Subject: [PATCH 4/5] add flatten array (#256) --- config.json | 8 ++ .../flatten-array/.docs/instructions.md | 11 +++ .../.meta/FlattenArray.example.ps1 | 28 +++++++ .../practice/flatten-array/.meta/config.json | 17 ++++ .../practice/flatten-array/.meta/tests.toml | 43 ++++++++++ .../practice/flatten-array/FlattenArray.ps1 | 21 +++++ .../flatten-array/FlattenArray.tests.ps1 | 82 +++++++++++++++++++ 7 files changed, 210 insertions(+) create mode 100644 exercises/practice/flatten-array/.docs/instructions.md create mode 100644 exercises/practice/flatten-array/.meta/FlattenArray.example.ps1 create mode 100644 exercises/practice/flatten-array/.meta/config.json create mode 100644 exercises/practice/flatten-array/.meta/tests.toml create mode 100644 exercises/practice/flatten-array/FlattenArray.ps1 create mode 100644 exercises/practice/flatten-array/FlattenArray.tests.ps1 diff --git a/config.json b/config.json index 375bb1c6..9c83e8e9 100644 --- a/config.json +++ b/config.json @@ -92,6 +92,14 @@ "prerequisites": [], "difficulty": 1 }, + { + "slug": "flatten-array", + "name": "Flatten Array", + "uuid": "5edb37eb-2903-48de-9f0e-83d8aceae03b", + "practices": [], + "prerequisites": [], + "difficulty": 1 + }, { "slug": "sum-of-multiples", "name": "Sum Of Multiples", diff --git a/exercises/practice/flatten-array/.docs/instructions.md b/exercises/practice/flatten-array/.docs/instructions.md new file mode 100644 index 00000000..51bea679 --- /dev/null +++ b/exercises/practice/flatten-array/.docs/instructions.md @@ -0,0 +1,11 @@ +# Instructions + +Take a nested list and return a single flattened list with all values except nil/null. + +The challenge is to write a function that accepts an arbitrarily-deep nested list-like structure and returns a flattened structure without any nil/null values. + +For example: + +input: [1,[2,3,null,4],[null],5] + +output: [1,2,3,4,5] diff --git a/exercises/practice/flatten-array/.meta/FlattenArray.example.ps1 b/exercises/practice/flatten-array/.meta/FlattenArray.example.ps1 new file mode 100644 index 00000000..f2bcdfc3 --- /dev/null +++ b/exercises/practice/flatten-array/.meta/FlattenArray.example.ps1 @@ -0,0 +1,28 @@ +Function Invoke-FlattenArray() { + <# + .SYNOPSIS + Given an array, flatten it and keep all values execept null. + + .DESCRIPTION + Take a nested array and return a single flattened array with all values except null. + + .PARAMETER Array + The nested array to be flatten. + + .EXAMPLE + Invoke-FlattenArray -Array @(1, @(2, 3, $null, 4), @($null), 5) + Return: @(1, 2, 3, 4, 5) + #> + [CmdletBinding()] + Param( + [System.Object[]]$Array + ) + + $Array | ForEach-Object { + if ($_ -is [Array]) { + Invoke-FlattenArray $_ + } elseif ($null -ne $_) { + $_ + } + } +} \ No newline at end of file diff --git a/exercises/practice/flatten-array/.meta/config.json b/exercises/practice/flatten-array/.meta/config.json new file mode 100644 index 00000000..632015c8 --- /dev/null +++ b/exercises/practice/flatten-array/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": ["glaxxie"], + "files": { + "solution": [ + "FlattenArray.ps1" + ], + "test": [ + "FlattenArray.tests.ps1" + ], + "example": [ + ".meta/FlattenArray.example.ps1" + ] + }, + "blurb": "Take a nested list and return a single list with all values except nil/null.", + "source": "Interview Question", + "source_url": "https://reference.wolfram.com/language/ref/Flatten.html" +} diff --git a/exercises/practice/flatten-array/.meta/tests.toml b/exercises/practice/flatten-array/.meta/tests.toml new file mode 100644 index 00000000..6300219d --- /dev/null +++ b/exercises/practice/flatten-array/.meta/tests.toml @@ -0,0 +1,43 @@ +# 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. + +[8c71dabd-da60-422d-a290-4a571471fb14] +description = "empty" + +[d268b919-963c-442d-9f07-82b93f1b518c] +description = "no nesting" + +[3f15bede-c856-479e-bb71-1684b20c6a30] +description = "flattens a nested array" + +[c84440cc-bb3a-48a6-862c-94cf23f2815d] +description = "flattens array with just integers present" + +[d3d99d39-6be5-44f5-a31d-6037d92ba34f] +description = "5 level nesting" + +[d572bdba-c127-43ed-bdcd-6222ac83d9f7] +description = "6 level nesting" + +[0705a8e5-dc86-4cec-8909-150c5e54fa9c] +description = "null values are omitted from the final result" + +[c6cf26de-8ccd-4410-84bd-b9efd88fd2bc] +description = "consecutive null values at the front of the list are omitted from the final result" + +[382c5242-587e-4577-b8ce-a5fb51e385a1] +description = "consecutive null values in the middle of the list are omitted from the final result" + +[ef1d4790-1b1e-4939-a179-51ace0829dbd] +description = "6 level nest list with null values" + +[85721643-705a-4150-93ab-7ae398e2942d] +description = "all values in nested list are null" diff --git a/exercises/practice/flatten-array/FlattenArray.ps1 b/exercises/practice/flatten-array/FlattenArray.ps1 new file mode 100644 index 00000000..1e08edf7 --- /dev/null +++ b/exercises/practice/flatten-array/FlattenArray.ps1 @@ -0,0 +1,21 @@ +Function Invoke-FlattenArray() { + <# + .SYNOPSIS + Take a nested array and return a single flattened array with all values except null. + + .DESCRIPTION + Given an array, flatten it and keep all values execept null. + + .PARAMETER Array + The nested array to be flatten. + + .EXAMPLE + Invoke-FlattenArray -Array @(1, @(2, 3, $null, 4), @($null), 5) + Return: @(1, 2, 3, 4, 5) + #> + [CmdletBinding()] + Param( + [System.Object[]]$Array + ) + Throw "Please implement this function" +} \ No newline at end of file diff --git a/exercises/practice/flatten-array/FlattenArray.tests.ps1 b/exercises/practice/flatten-array/FlattenArray.tests.ps1 new file mode 100644 index 00000000..5d291482 --- /dev/null +++ b/exercises/practice/flatten-array/FlattenArray.tests.ps1 @@ -0,0 +1,82 @@ +BeforeAll { + . "./FlattenArray.ps1" +} + +Describe "flatten array test cases" { + It "empty" { + $got = Invoke-FlattenArray -Array @() + $want = @() + + $got | Should -BeExactly $want + } + + It "no nesting" { + $got = Invoke-FlattenArray -Array @(1, 2, 3) + $want = @(1, 2, 3) + + $got | Should -BeExactly $want + } + + It "flattens a nested array" { + $got = Invoke-FlattenArray -Array @(@(@())) + $want = @() + + $got | Should -BeExactly $want + } + + It "flattens array with just integers present" { + $got = Invoke-FlattenArray -Array @(1, @(2, 3, 4, 5, 6, 7), 8) + $want = @(1, 2, 3, 4, 5, 6, 7, 8) + + $got | Should -BeExactly $want + } + + It "5 level nesting" { + $got = Invoke-FlattenArray -Array @(0, 2, @(@(2, 3), 8, 100, 4, @(@(@(50)))), -2) + $want = @(0, 2, 2, 3, 8, 100, 4, 50, -2) + + $got | Should -BeExactly $want + } + + It "6 level nesting" { + $got = Invoke-FlattenArray -Array @(1, @(2, 3, 4, 5, 6, 7), 8) + $want = @(1, 2, 3, 4, 5, 6, 7, 8) + + $got | Should -BeExactly $want + } + + It "null values are omitted from the final result" { + $got = Invoke-FlattenArray -Array @(1, 2, $null) + $want = @(1, 2) + + $got | Should -BeExactly $want + } + + It "consecutive null values at the front of the list are omitted from the final result" { + $got = Invoke-FlattenArray -Array @($null, $null, 5) + $want = @(5) + + $got | Should -BeExactly $want + } + + It "consecutive null values in the middle of the list are omitted from the final result" { + $got = Invoke-FlattenArray -Array @(1, $null, $null, 4) + $want = @(1, 4) + + $got | Should -BeExactly $want + } + + It "6 level nest list with null values" { + $got = Invoke-FlattenArray -Array @(0, 2, @(@(2, 3), 8, @(@(100)), $null, @(@($null))), -2) + $want = @(0, 2, 2, 3, 8, 100, -2) + + $got | Should -BeExactly $want + } + + It "all values in nested list are null" { + $got = Invoke-FlattenArray -Array @($null, @(@(@($null))), $null, $null, @(@($null, $null), $null), $null) + $want = @() + + $got | Should -BeExactly $want + } +} \ No newline at end of file From 8f111147b94801914a1f3669f225bf0874eba2b4 Mon Sep 17 00:00:00 2001 From: glaxxie <86179463+glaxxie@users.noreply.github.com> Date: Thu, 31 Aug 2023 07:15:59 -0500 Subject: [PATCH 5/5] add strain (#257) --- config.json | 8 + .../practice/strain/.docs/instructions.md | 29 ++++ .../practice/strain/.meta/Strain.example.ps1 | 53 +++++++ exercises/practice/strain/.meta/config.json | 17 ++ exercises/practice/strain/.meta/tests.toml | 52 ++++++ exercises/practice/strain/Strain.ps1 | 53 +++++++ exercises/practice/strain/Strain.tests.ps1 | 149 ++++++++++++++++++ 7 files changed, 361 insertions(+) create mode 100644 exercises/practice/strain/.docs/instructions.md create mode 100644 exercises/practice/strain/.meta/Strain.example.ps1 create mode 100644 exercises/practice/strain/.meta/config.json create mode 100644 exercises/practice/strain/.meta/tests.toml create mode 100644 exercises/practice/strain/Strain.ps1 create mode 100644 exercises/practice/strain/Strain.tests.ps1 diff --git a/config.json b/config.json index 9c83e8e9..0d6cfe4d 100644 --- a/config.json +++ b/config.json @@ -72,6 +72,14 @@ "integers" ] }, + { + "slug": "strain", + "name": "Strain", + "uuid": "c142d262-ae74-4a41-9a99-e2a00194619d", + "practices": [], + "prerequisites": [], + "difficulty": 1 + }, { "slug": "resistor-color", "name": "Resistor Color", diff --git a/exercises/practice/strain/.docs/instructions.md b/exercises/practice/strain/.docs/instructions.md new file mode 100644 index 00000000..3469ae65 --- /dev/null +++ b/exercises/practice/strain/.docs/instructions.md @@ -0,0 +1,29 @@ +# Instructions + +Implement the `keep` and `discard` operation on collections. +Given a collection and a predicate on the collection's elements, `keep` returns a new collection containing those elements where the predicate is true, while `discard` returns a new collection containing those elements where the predicate is false. + +For example, given the collection of numbers: + +- 1, 2, 3, 4, 5 + +And the predicate: + +- is the number even? + +Then your keep operation should produce: + +- 2, 4 + +While your discard operation should produce: + +- 1, 3, 5 + +Note that the union of keep and discard is all the elements. + +The functions may be called `keep` and `discard`, or they may need different names in order to not clash with existing functions or concepts in your language. + +## Restrictions + +Keep your hands off that filter/reject/whatchamacallit functionality provided by your standard library! +Solve this one yourself using other basic tools instead. diff --git a/exercises/practice/strain/.meta/Strain.example.ps1 b/exercises/practice/strain/.meta/Strain.example.ps1 new file mode 100644 index 00000000..9696f651 --- /dev/null +++ b/exercises/practice/strain/.meta/Strain.example.ps1 @@ -0,0 +1,53 @@ +Function Invoke-Keep() { + <# + .SYNOPSIS + Implement the keep operation on collections. + + .DESCRIPTION + Given an array, apply the predicate on each element and return an array of elements where the predicate is true. + + .PARAMETER Data + Collection of data to filter through. + + .PARAMETER Predicate + The predicate to operate on the data. + + .EXAMPLE + $IsNegative = { param($num) $num -lt 0 } + Invoke-Keep -Data @(0, -2, 4, 8, -16) -Predicate $IsNegative + Return: @(-2, -16) + #> + [CmdletBinding()] + Param( + [Object[]]$Data, + [ScriptBlock]$Predicate + ) + $Data | Where-Object { & $Predicate $_ } +} + +Function Invoke-Discard() { + <# + .SYNOPSIS + Implement the discard operation on collections. + + .DESCRIPTION + Given an array, apply the predicate on each element and return an array of elements where the predicate is false. + + .PARAMETER Data + Collection of data to filter through. + + .PARAMETER Predicate + The predicate to operate on the data. + + .EXAMPLE + $IsNegative = { param($num) $num -lt 0 } + Invoke-Discard -Data @(0, -2, 4, 8, -16) -Predicate $IsNegative + Return: @(0, 4, 8) + #> + [CmdletBinding()] + Param( + [Object[]]$Data, + [ScriptBlock]$Predicate + ) + $Data | Where-Object { -not (& $Predicate $_) } +} \ No newline at end of file diff --git a/exercises/practice/strain/.meta/config.json b/exercises/practice/strain/.meta/config.json new file mode 100644 index 00000000..cbdd166d --- /dev/null +++ b/exercises/practice/strain/.meta/config.json @@ -0,0 +1,17 @@ +{ + "authors": ["glaxxie"], + "files": { + "solution": [ + "Strain.ps1" + ], + "test": [ + "Strain.tests.ps1" + ], + "example": [ + ".meta/Strain.example.ps1" + ] + }, + "blurb": "Implement the `keep` and `discard` operation on collections. Given a collection and a predicate on the collection's elements, `keep` returns a new collection containing those elements where the predicate is true, while `discard` returns a new collection containing those elements where the predicate is false.", + "source": "Conversation with James Edward Gray II", + "source_url": "https://twitter.com/jeg2" +} diff --git a/exercises/practice/strain/.meta/tests.toml b/exercises/practice/strain/.meta/tests.toml new file mode 100644 index 00000000..3a617b4a --- /dev/null +++ b/exercises/practice/strain/.meta/tests.toml @@ -0,0 +1,52 @@ +# 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. + +[26af8c32-ba6a-4eb3-aa0a-ebd8f136e003] +description = "keep on empty list returns empty list" + +[f535cb4d-e99b-472a-bd52-9fa0ffccf454] +description = "keeps everything" + +[950b8e8e-f628-42a8-85e2-9b30f09cde38] +description = "keeps nothing" + +[92694259-6e76-470c-af87-156bdf75018a] +description = "keeps first and last" + +[938f7867-bfc7-449e-a21b-7b00cbb56994] +description = "keeps neither first nor last" + +[8908e351-4437-4d2b-a0f7-770811e48816] +description = "keeps strings" + +[2728036b-102a-4f1e-a3ef-eac6160d876a] +description = "keeps lists" + +[ef16beb9-8d84-451a-996a-14e80607fce6] +description = "discard on empty list returns empty list" + +[2f42f9bc-8e06-4afe-a222-051b5d8cd12a] +description = "discards everything" + +[ca990fdd-08c2-4f95-aa50-e0f5e1d6802b] +description = "discards nothing" + +[71595dae-d283-48ca-a52b-45fa96819d2f] +description = "discards first and last" + +[ae141f79-f86d-4567-b407-919eaca0f3dd] +description = "discards neither first nor last" + +[daf25b36-a59f-4f29-bcfe-302eb4e43609] +description = "discards strings" + +[a38d03f9-95ad-4459-80d1-48e937e4acaf] +description = "discards lists" diff --git a/exercises/practice/strain/Strain.ps1 b/exercises/practice/strain/Strain.ps1 new file mode 100644 index 00000000..f1069a33 --- /dev/null +++ b/exercises/practice/strain/Strain.ps1 @@ -0,0 +1,53 @@ +Function Invoke-Keep() { + <# + .SYNOPSIS + Implement the keep operation on collections. + + .DESCRIPTION + Given an array, apply the predicate on each element and return an array of elements where the predicate is true. + + .PARAMETER Data + Collection of data to filter through. + + .PARAMETER Predicate + The predicate to operate on the data. + + .EXAMPLE + $IsNegative = { param($num) $num -lt 0 } + Invoke-Keep -Data @(0, -2, 4, 8, -16) -Predicate $IsNegative + Return: @(-2, -16) + #> + [CmdletBinding()] + Param( + [Object[]]$Data, + [ScriptBlock]$Predicate + ) + Throw "Please implement this function" +} + +Function Invoke-Discard() { + <# + .SYNOPSIS + Implement the discard operation on collections. + + .DESCRIPTION + Given an array, apply the predicate on each element and return an array of elements where the predicate is false. + + .PARAMETER Data + Collection of data to filter through. + + .PARAMETER Predicate + The predicate to operate on the data. + + .EXAMPLE + $IsNegative = { param($num) $num -lt 0 } + Invoke-Discard -Data @(0, -2, 4, 8, -16) -Predicate $IsNegative + Return: @(0, 4, 8) + #> + [CmdletBinding()] + Param( + [Object[]]$Data, + [ScriptBlock]$Predicate + ) + Throw "Please implement this function" +} \ No newline at end of file diff --git a/exercises/practice/strain/Strain.tests.ps1 b/exercises/practice/strain/Strain.tests.ps1 new file mode 100644 index 00000000..b250f030 --- /dev/null +++ b/exercises/practice/strain/Strain.tests.ps1 @@ -0,0 +1,149 @@ +BeforeAll { + . "./Strain.ps1" +} + +Describe "strain test cases" { + BeforeAll { + $global:AlwaysTrue = { $true } + $global:IsOdd = { param($num) $num % 2 -eq 1 } + $global:IsEven = { param($num) $num % 2 -eq 0 } + $global:LessThanFive = { param($num) $num -lt 5 } + $global:FiveLettersWord = { param($word) $word.Length -eq 5 } + $global:SumOverTen = { param($row) ($row | Measure-Object -Sum).Sum -gt 10 } + } + + Context "keep tests" { + It "keep on empty list returns empty list" { + $got = Invoke-Keep -Data @() -Predicate $global:AlwaysTrue + $want = @() + + $got | Should -BeExactly $want + + } + + It "keep everything" { + $got = Invoke-Keep -Data @(1, 2, 3) -Predicate $global:LessThanFive + $want = @(1, 2, 3) + + $got | Should -BeExactly $want + } + + It "keep nothing" { + $got = Invoke-Keep -Data @(6, 7, 8) -Predicate $global:LessThanFive + $want = @() + + $got | Should -BeExactly $want + } + + It "keep first and last" { + $got = Invoke-Keep -Data @(1, 2, 3) -Predicate $global:IsOdd + $want = @(1, 3) + + $got | Should -BeExactly $want + } + + It "keep neither first nor last" { + $got = Invoke-Keep -Data @(1, 2, 3) -Predicate $global:IsEven + $want = @(2) + + $got | Should -BeExactly $want + + } + + It "keep string" { + $data = @("apple", "zebra", "banana", "eagle", "dynamic", "nuts") + $got = Invoke-Keep -Data $data -Predicate $global:FiveLettersWord + $want = @("apple", "zebra", "eagle") + + $got | Should -BeExactly $want + } + + It "keep list" { + $data = @( + @(1, 2, 3), + @(5, 4, 2), + @(5, 1, 3), + @(2, 8, 7), + @(1, 5, 4), + @(2, 2, 9), + @(1, 1, 4) + ) + + $got = Invoke-Keep -Data $data -Predicate $global:SumOverTen + $want = @( + @(5, 4, 2), + @(2, 8, 7), + @(2, 2, 9) + ) + + $got | Should -Be $want + } + } + + Context "discard tests" { + It "discard on empty list returns empty list" { + $got = Invoke-Discard -Data @() -Predicate $global:AlwaysTrue + $want = @() + + $got | Should -BeExactly $want + } + + It "discard everything" { + $got = Invoke-Discard -Data @(1, 2, 3) -Predicate $global:LessThanFive + $want = @() + + $got | Should -BeExactly $want + } + + It "discard nothing" { + $got = Invoke-Discard -Data @(6, 7, 8) -Predicate $global:LessThanFive + $want = @(6, 7, 8) + + $got | Should -BeExactly $want + } + + It "discard first and last" { + $got = Invoke-Discard -Data @(1, 2, 3) -Predicate $global:IsOdd + $want = @(2) + + $got | Should -BeExactly $want + } + + It "discard neither first nor last" { + $got = Invoke-Discard -Data @(1, 2, 3) -Predicate $global:IsEven + $want = @(1, 3) + + $got | Should -BeExactly $want + } + + It "discard string" { + $data = @("apple", "zebra", "banana", "eagle", "dynamic", "nuts") + $got = Invoke-Discard -Data $data -Predicate $global:FiveLettersWord + $want = @("banana", "dynamic", "nuts") + + $got | Should -BeExactly $want + } + + It "discard list" { + $data = @( + @(1, 2, 3), + @(5, 4, 2), + @(5, 1, 3), + @(2, 8, 7), + @(1, 5, 4), + @(2, 2, 9), + @(1, 1, 4) + ) + + $got = Invoke-Discard -Data $data -Predicate $global:SumOverTen + $want = @( + @(1, 2, 3), + @(5, 1, 3), + @(1, 5, 4), + @(1, 1, 4) + ) + + $got | Should -Be $want + } + } +} \ No newline at end of file