From 5f143d94adf51b75e69f9d6d37cbd4701a4c749c Mon Sep 17 00:00:00 2001 From: Piotr Idzik Date: Mon, 25 Mar 2024 19:31:44 +0000 Subject: [PATCH 1/4] tests: add tests checking if floodFill funtions throw when location is outside --- Recursive/test/FloodFill.test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Recursive/test/FloodFill.test.js b/Recursive/test/FloodFill.test.js index 291788addd..618692dd97 100644 --- a/Recursive/test/FloodFill.test.js +++ b/Recursive/test/FloodFill.test.js @@ -21,6 +21,19 @@ describe('FloodFill', () => { }) }) +describe.each([breadthFirstSearch, depthFirstSearch])('%o', (floodFillFun) => { + it.each([ + [1, -1], + [-1, 1], + [0, 7], + [7, 0] + ])('throws for start position [%i, %i]', (location) => { + expect(() => + floodFillFun(generateTestRgbData(), location, green, orange) + ).toThrowError() + }) +}) + /** * Utility-function to test the function "breadthFirstSearch". * From 0e42fe02d89529f2626466c463cf5b986f8cc5cf Mon Sep 17 00:00:00 2001 From: Piotr Idzik Date: Mon, 25 Mar 2024 19:36:16 +0000 Subject: [PATCH 2/4] refactor: reduce code duplication by adding `checkLocation` to `FloodFill` --- Recursive/FloodFill.js | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/Recursive/FloodFill.js b/Recursive/FloodFill.js index 33ea6025ad..bddc2c1880 100644 --- a/Recursive/FloodFill.js +++ b/Recursive/FloodFill.js @@ -20,6 +20,17 @@ const neighbors = [ [1, 1] ] +function checkLocation(rgbData, location) { + if ( + location[0] < 0 || + location[0] >= rgbData.length || + location[1] < 0 || + location[1] >= rgbData[0].length + ) { + throw new Error('location should point to a pixel within the rgbData') + } +} + /** * Implements the flood fill algorithm through a breadth-first approach using a queue. * @@ -34,14 +45,7 @@ export function breadthFirstSearch( targetColor, replacementColor ) { - if ( - location[0] < 0 || - location[0] >= rgbData.length || - location[1] < 0 || - location[1] >= rgbData[0].length - ) { - throw new Error('location should point to a pixel within the rgbData') - } + checkLocation(rgbData, location) const queue = [] queue.push(location) @@ -65,14 +69,7 @@ export function depthFirstSearch( targetColor, replacementColor ) { - if ( - location[0] < 0 || - location[0] >= rgbData.length || - location[1] < 0 || - location[1] >= rgbData[0].length - ) { - throw new Error('location should point to a pixel within the rgbData') - } + checkLocation(rgbData, location) depthFirstFill(rgbData, location, targetColor, replacementColor) } From cf34946a21423a5f8a1c44aeca1191acd9d62d72 Mon Sep 17 00:00:00 2001 From: Piotr Idzik Date: Tue, 26 Mar 2024 22:16:03 +0000 Subject: [PATCH 3/4] refactor: add and use `isInside` Co-authored-by: appgurueu <34514239+appgurueu@users.noreply.github.com> --- Recursive/FloodFill.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Recursive/FloodFill.js b/Recursive/FloodFill.js index bddc2c1880..9a6e5e8af8 100644 --- a/Recursive/FloodFill.js +++ b/Recursive/FloodFill.js @@ -20,13 +20,14 @@ const neighbors = [ [1, 1] ] +function isInside(rgbData, location) { + const x = location[0] + const y = location[1] + return x >= 0 && x < rgbData.length && y >= 0 && y < rgbData[0].length +} + function checkLocation(rgbData, location) { - if ( - location[0] < 0 || - location[0] >= rgbData.length || - location[1] < 0 || - location[1] >= rgbData[0].length - ) { + if (!isInside(rgbData, location)) { throw new Error('location should point to a pixel within the rgbData') } } @@ -119,10 +120,12 @@ function depthFirstFill(rgbData, location, targetColor, replacementColor) { rgbData[location[0]][location[1]] = replacementColor for (let i = 0; i < neighbors.length; i++) { - const x = location[0] + neighbors[i][0] - const y = location[1] + neighbors[i][1] - if (x >= 0 && x < rgbData.length && y >= 0 && y < rgbData[0].length) { - depthFirstFill(rgbData, [x, y], targetColor, replacementColor) + const newLocation = [ + location[0] + neighbors[i][0], + location[1] + neighbors[i][1] + ] + if (isInside(rgbData, newLocation)) { + depthFirstFill(rgbData, newLocation, targetColor, replacementColor) } } } From 1be1853dd012718ec3b139ea3d1c48e29312fcdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Wed, 27 Mar 2024 10:50:59 +0100 Subject: [PATCH 4/4] Deduplicate further --- Recursive/FloodFill.js | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/Recursive/FloodFill.js b/Recursive/FloodFill.js index 9a6e5e8af8..5143b8f4ff 100644 --- a/Recursive/FloodFill.js +++ b/Recursive/FloodFill.js @@ -9,7 +9,7 @@ * @see https://www.techiedelight.com/flood-fill-algorithm/ */ -const neighbors = [ +const neighborOffsets = [ [-1, -1], [-1, 0], [-1, 1], @@ -32,6 +32,15 @@ function checkLocation(rgbData, location) { } } +function* neighbors(rgbData, location) { + for (const offset of neighborOffsets) { + const neighborLocation = [location[0] + offset[0], location[1] + offset[1]] + if (isInside(rgbData, neighborLocation)) { + yield neighborLocation + } + } +} + /** * Implements the flood fill algorithm through a breadth-first approach using a queue. * @@ -96,13 +105,8 @@ function breadthFirstFill( if (rgbData[currentLocation[0]][currentLocation[1]] === targetColor) { rgbData[currentLocation[0]][currentLocation[1]] = replacementColor - - for (let i = 0; i < neighbors.length; i++) { - const x = currentLocation[0] + neighbors[i][0] - const y = currentLocation[1] + neighbors[i][1] - if (x >= 0 && x < rgbData.length && y >= 0 && y < rgbData[0].length) { - queue.push([x, y]) - } + for (const neighborLocation of neighbors(rgbData, currentLocation)) { + queue.push(neighborLocation) } } } @@ -118,15 +122,8 @@ function breadthFirstFill( function depthFirstFill(rgbData, location, targetColor, replacementColor) { if (rgbData[location[0]][location[1]] === targetColor) { rgbData[location[0]][location[1]] = replacementColor - - for (let i = 0; i < neighbors.length; i++) { - const newLocation = [ - location[0] + neighbors[i][0], - location[1] + neighbors[i][1] - ] - if (isInside(rgbData, newLocation)) { - depthFirstFill(rgbData, newLocation, targetColor, replacementColor) - } + for (const neighborLocation of neighbors(rgbData, location)) { + depthFirstFill(rgbData, neighborLocation, targetColor, replacementColor) } } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy