From d03751b3ac6ce1e784627bb9728fc06e571f5ef4 Mon Sep 17 00:00:00 2001 From: glaxxie <86179463+glaxxie@users.noreply.github.com> Date: Wed, 27 Sep 2023 19:34:21 -0500 Subject: [PATCH] [New Exercise]: Saddle Points --- config.json | 8 ++ .../saddle-points/.docs/instructions.md | 26 ++++ .../saddle-points/.docs/introduction.md | 11 ++ .../.meta/SaddlePoints.example.ps1 | 91 ++++++++++++++ .../practice/saddle-points/.meta/config.json | 19 +++ .../practice/saddle-points/.meta/tests.toml | 37 ++++++ .../practice/saddle-points/SaddlePoints.ps1 | 48 ++++++++ .../saddle-points/SaddlePoints.tests.ps1 | 114 ++++++++++++++++++ 8 files changed, 354 insertions(+) create mode 100644 exercises/practice/saddle-points/.docs/instructions.md create mode 100644 exercises/practice/saddle-points/.docs/introduction.md create mode 100644 exercises/practice/saddle-points/.meta/SaddlePoints.example.ps1 create mode 100644 exercises/practice/saddle-points/.meta/config.json create mode 100644 exercises/practice/saddle-points/.meta/tests.toml create mode 100644 exercises/practice/saddle-points/SaddlePoints.ps1 create mode 100644 exercises/practice/saddle-points/SaddlePoints.tests.ps1 diff --git a/config.json b/config.json index d12a3d52..a4d9a0a0 100644 --- a/config.json +++ b/config.json @@ -649,6 +649,14 @@ "prerequisites": [], "difficulty": 3 }, + { + "slug": "saddle-points", + "name": "Saddle Points", + "uuid": "512f0d92-57c1-403c-a96a-82b5066fd047", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "clock", "name": "Clock", diff --git a/exercises/practice/saddle-points/.docs/instructions.md b/exercises/practice/saddle-points/.docs/instructions.md new file mode 100644 index 00000000..c585568b --- /dev/null +++ b/exercises/practice/saddle-points/.docs/instructions.md @@ -0,0 +1,26 @@ +# Instructions + +Your task is to find the potential trees where you could build your tree house. + +The data company provides the data as grids that show the heights of the trees. +The rows of the grid represent the east-west direction, and the columns represent the north-south direction. + +An acceptable tree will be the largest in its row, while being the smallest in its column. + +A grid might not have any good trees at all. +Or it might have one, or even several. + +Here is a grid that has exactly one candidate tree. + +```text + 1 2 3 4 + |----------- +1 | 9 8 7 8 +2 | 5 3 2 4 <--- potential tree house at row 2, column 1, for tree with height 5 +3 | 6 6 7 1 +``` + +- Row 2 has values 5, 3, 2, and 4. The largest value is 5. +- Column 1 has values 9, 5, and 6. The smallest value is 5. + +So the point at `[2, 1]` (row: 2, column: 1) is a great spot for a tree house. diff --git a/exercises/practice/saddle-points/.docs/introduction.md b/exercises/practice/saddle-points/.docs/introduction.md new file mode 100644 index 00000000..34b2c77e --- /dev/null +++ b/exercises/practice/saddle-points/.docs/introduction.md @@ -0,0 +1,11 @@ +# Introduction + +You plan to build a tree house in the woods near your house so that you can watch the sun rise and set. + +You've obtained data from a local survey company that show the height of every tree in each rectangular section of the map. +You need to analyze each grid on the map to find good trees for your tree house. + +A good tree is both: + +- taller than every tree to the east and west, so that you have the best possible view of the sunrises and sunsets. +- shorter than every tree to the north and south, to minimize the amount of tree climbing. diff --git a/exercises/practice/saddle-points/.meta/SaddlePoints.example.ps1 b/exercises/practice/saddle-points/.meta/SaddlePoints.example.ps1 new file mode 100644 index 00000000..8900431f --- /dev/null +++ b/exercises/practice/saddle-points/.meta/SaddlePoints.example.ps1 @@ -0,0 +1,91 @@ +<# +.DESCRIPTION + A helper class act as a data structure for the saddle point. + It has a two properties: Row and Column, their indexes should be offset by 1 to reflect normal counting. + It also has an Equals method for comparison in tests. + Please don't delete or change this class. +#> +Class SaddlePoint { + [int]$Row + [int]$Column + + SaddlePoint($row, $col) { + $this.Row = $row + $this.Column = $col + } + + [bool] Equals($other) { + return $this.Row -eq $other.Row -and $this.Column -eq $other.Column + } +} + +Function Get-SaddlePoints() { + <# + .SYNOPSIS + Find all the available saddle points in a given matrix. + + .DESCRIPTION + Given a matrix (jagged arrays), return all the available saddle points found. + The matrix can have a different number of rows and columns (non square), and it may have zero or more saddle points. + + It's called a "saddle point" because it is greater than or equal to every element in its row and less than or equal to every element in its column. + + Your code should be able to provide the (possibly empty) list of all the saddle points for any given matrix. + + .PARAMETER Matrix + An array of arrays, each inner array contains number that could be a saddle point. + + .EXAMPLE + Get-SaddlePoints -Matrix @( ,@(1, 2, 3)) + Returns: [SaddlePoint]::new(1, 3) + #> + [CmdletBinding()] + Param( + [int[][]]$Matrix + ) + #check for valid matrix + $lenCount = ($Matrix | Select-Object {$_.Count} -Unique).Count + if ($lenCount -gt 1) { Throw "Irregular matrix"} + + #got total rows and column + $rows = $Matrix.Count + $columns = $Matrix[0].Count + + $maxValues, $minValues = Get-MaxMinValues $Matrix $rows $columns + + #saddle found when max of row is the same as min of column + $saddlePoints = @() + for ($row = 0; $row -lt $rows; $row++) { + for ($col = 0; $col -lt $columns; $col++) { + $value = $Matrix[$row][$col] + if ($maxValues[$row] -eq $value -and $minValues[$col] -eq $value) { + $saddlePoints += [SaddlePoint]::new($row+1, $col+1) + } + + } + } + $saddlePoints +} + +function Get-MaxMinValues($matrix, $rows, $columns) { + <# + .DESCRIPTION + Helper function to find max value for each row and min value for each col + #> + $maxValues = @([int]::MinValue) * $rows + $minValues = @([int]::MaxValue) * $columns + + for ($row = 0; $row -lt $rows; $row++) { + for ($col = 0; $col -lt $columns; $col++) { + $value = $Matrix[$row][$col] + if ($value -ge $maxValues[$row]) { + $maxValues[$row] = $value + } + + if ($value -le $minValues[$col]) { + $minValues[$col] = $value + } + } + } + $maxValues, $minValues +} \ No newline at end of file diff --git a/exercises/practice/saddle-points/.meta/config.json b/exercises/practice/saddle-points/.meta/config.json new file mode 100644 index 00000000..d5522fcc --- /dev/null +++ b/exercises/practice/saddle-points/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glaxxie" + ], + "files": { + "solution": [ + "SaddlePoints.ps1" + ], + "test": [ + "SaddlePoints.tests.ps1" + ], + "example": [ + ".meta/SaddlePoints.example.ps1" + ] + }, + "blurb": "Detect saddle points in a matrix.", + "source": "J Dalbey's Programming Practice problems", + "source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html" +} diff --git a/exercises/practice/saddle-points/.meta/tests.toml b/exercises/practice/saddle-points/.meta/tests.toml new file mode 100644 index 00000000..ca008520 --- /dev/null +++ b/exercises/practice/saddle-points/.meta/tests.toml @@ -0,0 +1,37 @@ +# 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. + +[3e374e63-a2e0-4530-a39a-d53c560382bd] +description = "Can identify single saddle point" + +[6b501e2b-6c1f-491f-b1bb-7f278f760534] +description = "Can identify that empty matrix has no saddle points" + +[8c27cc64-e573-4fcb-a099-f0ae863fb02f] +description = "Can identify lack of saddle points when there are none" + +[6d1399bd-e105-40fd-a2c9-c6609507d7a3] +description = "Can identify multiple saddle points in a column" + +[3e81dce9-53b3-44e6-bf26-e328885fd5d1] +description = "Can identify multiple saddle points in a row" + +[88868621-b6f4-4837-bb8b-3fad8b25d46b] +description = "Can identify saddle point in bottom right corner" + +[5b9499ca-fcea-4195-830a-9c4584a0ee79] +description = "Can identify saddle points in a non square matrix" + +[ee99ccd2-a1f1-4283-ad39-f8c70f0cf594] +description = "Can identify that saddle points in a single column matrix are those with the minimum value" + +[63abf709-a84b-407f-a1b3-456638689713] +description = "Can identify that saddle points in a single row matrix are those with the maximum value" diff --git a/exercises/practice/saddle-points/SaddlePoints.ps1 b/exercises/practice/saddle-points/SaddlePoints.ps1 new file mode 100644 index 00000000..971d2c7d --- /dev/null +++ b/exercises/practice/saddle-points/SaddlePoints.ps1 @@ -0,0 +1,48 @@ +<# +.DESCRIPTION + A helper class act as a data structure for the saddle point. + It has a two properties: Row and Column, their indexes should be offset by 1 to reflect normal counting. + It also has an Equals method for comparison in tests. + Please don't delete or change this class. +#> +Class SaddlePoint { + [int]$Row + [int]$Column + + SaddlePoint($row, $col) { + $this.Row = $row + $this.Column = $col + } + + [bool] Equals($other) { + return $this.Row -eq $other.Row -and $this.Column -eq $other.Column + } +} + +Function Get-SaddlePoints() { + <# + .SYNOPSIS + Find all the available saddle points in a given matrix. + + .DESCRIPTION + Given a matrix (jagged arrays), return all the available saddle points found. + The matrix can have a different number of rows and columns (non square), and it may have zero or more saddle points. + + It's called a "saddle point" because it is greater than or equal to every element in its row and less than or equal to every element in its column. + + Your code should be able to provide the (possibly empty) list of all the saddle points for any given matrix. + + .PARAMETER Matrix + An array of arrays, each inner array contains number that could be a saddle point. + + .EXAMPLE + Get-SaddlePoints -Matrix @( ,@(1, 2, 3)) + Returns: [SaddlePoint]::new(1, 3) + #> + [CmdletBinding()] + Param( + [int[][]]$Matrix + ) + + Throw "Please implement this function" +} \ No newline at end of file diff --git a/exercises/practice/saddle-points/SaddlePoints.tests.ps1 b/exercises/practice/saddle-points/SaddlePoints.tests.ps1 new file mode 100644 index 00000000..9ce59f84 --- /dev/null +++ b/exercises/practice/saddle-points/SaddlePoints.tests.ps1 @@ -0,0 +1,114 @@ +BeforeAll { + . "./SaddlePoints.ps1" +} + +Describe "SaddlePoints test cases" { + Context "Can identify saddle" { + It "single saddle point" { + $got = Get-SaddlePoints -Matrix @( + @(9, 8, 7), + @(5, 3, 2), + @(6, 6, 7) + ) + $want = @([SaddlePoint]::new(2, 1)) + + $got | Should -BeExactly $want + } + + It "empty matrix has no saddle points" { + $got = Get-SaddlePoints -Matrix @() + + $got | Should -BeNullOrEmpty + } + + It "lack of saddle points when there are none" { + $got = Get-SaddlePoints -Matrix @( + @(1, 2, 3), + @(3, 1, 2), + @(2, 3, 1) + ) + + $got | Should -BeNullOrEmpty + } + + It "multiple saddle points in a column" { + $got = Get-SaddlePoints -Matrix @( + @(4, 5, 4), + @(3, 5, 5), + @(1, 5, 4) + ) + $want = @( + [SaddlePoint]::new(1, 2), + [SaddlePoint]::new(2, 2), + [SaddlePoint]::new(3, 2) + ) + + $got | Should -BeExactly $want + } + + It "multiple saddle points in a row" { + $got = Get-SaddlePoints -Matrix @( + @(6, 7, 8), + @(5, 5, 5), + @(7, 5, 6) + ) + $want = @( + [SaddlePoint]::new(2, 1), + [SaddlePoint]::new(2, 2), + [SaddlePoint]::new(2, 3) + ) + + $got | Should -BeExactly $want + } + + It "saddle point in bottom right corner" { + $got = Get-SaddlePoints -Matrix @( + @(8, 7, 9), + @(6, 7, 6), + @(3, 2, 5) + ) + $want = @([SaddlePoint]::new(3, 3)) + + $got | Should -BeExactly $want + } + + It "saddle points in a non square matrix" { + $got = Get-SaddlePoints -Matrix @( + @(3, 1, 3), + @(3, 2, 4) + ) + $want = @([SaddlePoint]::new(1, 1), [SaddlePoint]::new(1, 3)) + + $got | Should -BeExactly $want + } + + It "saddle points in a single column matrix are those with the minimum value" { + $got = Get-SaddlePoints -Matrix @( + @(2), + @(1), + @(4), + @(1) + ) + $want = @([SaddlePoint]::new(2, 1), [SaddlePoint]::new(4, 1)) + + $got | Should -BeExactly $want + } + + It "saddle points in a single row matrix are those with the maximum value" { + $got = Get-SaddlePoints -Matrix @( ,@(2, 5, 3, 5)) + $want = @([SaddlePoint]::new(1, 2), [SaddlePoint]::new(1, 4)) + + $got | Should -BeExactly $want + } + } + + Context "invalid input" { + It "irregular_matrix" { + {Get-SaddlePoints -Matrix @( + @(3, 2, 1), + @(0, 1), + @(2, 1, 0) + )} | Should -Throw "Irregular matrix" + } + } +}