Skip to content

Commit d920e7f

Browse files
vil02appgurueu
andauthored
refactor: reduce code duplication in FloodFill (TheAlgorithms#1645)
* tests: add tests checking if floodFill funtions throw when location is outside * refactor: reduce code duplication by adding `checkLocation` to `FloodFill` * refactor: add and use `isInside` Co-authored-by: appgurueu <34514239+appgurueu@users.noreply.github.com> * Deduplicate further --------- Co-authored-by: appgurueu <34514239+appgurueu@users.noreply.github.com>
1 parent d02e402 commit d920e7f

File tree

2 files changed

+41
-31
lines changed

2 files changed

+41
-31
lines changed

Recursive/FloodFill.js

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* @see https://www.techiedelight.com/flood-fill-algorithm/
1010
*/
1111

12-
const neighbors = [
12+
const neighborOffsets = [
1313
[-1, -1],
1414
[-1, 0],
1515
[-1, 1],
@@ -20,6 +20,27 @@ const neighbors = [
2020
[1, 1]
2121
]
2222

23+
function isInside(rgbData, location) {
24+
const x = location[0]
25+
const y = location[1]
26+
return x >= 0 && x < rgbData.length && y >= 0 && y < rgbData[0].length
27+
}
28+
29+
function checkLocation(rgbData, location) {
30+
if (!isInside(rgbData, location)) {
31+
throw new Error('location should point to a pixel within the rgbData')
32+
}
33+
}
34+
35+
function* neighbors(rgbData, location) {
36+
for (const offset of neighborOffsets) {
37+
const neighborLocation = [location[0] + offset[0], location[1] + offset[1]]
38+
if (isInside(rgbData, neighborLocation)) {
39+
yield neighborLocation
40+
}
41+
}
42+
}
43+
2344
/**
2445
* Implements the flood fill algorithm through a breadth-first approach using a queue.
2546
*
@@ -34,14 +55,7 @@ export function breadthFirstSearch(
3455
targetColor,
3556
replacementColor
3657
) {
37-
if (
38-
location[0] < 0 ||
39-
location[0] >= rgbData.length ||
40-
location[1] < 0 ||
41-
location[1] >= rgbData[0].length
42-
) {
43-
throw new Error('location should point to a pixel within the rgbData')
44-
}
58+
checkLocation(rgbData, location)
4559

4660
const queue = []
4761
queue.push(location)
@@ -65,14 +79,7 @@ export function depthFirstSearch(
6579
targetColor,
6680
replacementColor
6781
) {
68-
if (
69-
location[0] < 0 ||
70-
location[0] >= rgbData.length ||
71-
location[1] < 0 ||
72-
location[1] >= rgbData[0].length
73-
) {
74-
throw new Error('location should point to a pixel within the rgbData')
75-
}
82+
checkLocation(rgbData, location)
7683

7784
depthFirstFill(rgbData, location, targetColor, replacementColor)
7885
}
@@ -98,13 +105,8 @@ function breadthFirstFill(
98105

99106
if (rgbData[currentLocation[0]][currentLocation[1]] === targetColor) {
100107
rgbData[currentLocation[0]][currentLocation[1]] = replacementColor
101-
102-
for (let i = 0; i < neighbors.length; i++) {
103-
const x = currentLocation[0] + neighbors[i][0]
104-
const y = currentLocation[1] + neighbors[i][1]
105-
if (x >= 0 && x < rgbData.length && y >= 0 && y < rgbData[0].length) {
106-
queue.push([x, y])
107-
}
108+
for (const neighborLocation of neighbors(rgbData, currentLocation)) {
109+
queue.push(neighborLocation)
108110
}
109111
}
110112
}
@@ -120,13 +122,8 @@ function breadthFirstFill(
120122
function depthFirstFill(rgbData, location, targetColor, replacementColor) {
121123
if (rgbData[location[0]][location[1]] === targetColor) {
122124
rgbData[location[0]][location[1]] = replacementColor
123-
124-
for (let i = 0; i < neighbors.length; i++) {
125-
const x = location[0] + neighbors[i][0]
126-
const y = location[1] + neighbors[i][1]
127-
if (x >= 0 && x < rgbData.length && y >= 0 && y < rgbData[0].length) {
128-
depthFirstFill(rgbData, [x, y], targetColor, replacementColor)
129-
}
125+
for (const neighborLocation of neighbors(rgbData, location)) {
126+
depthFirstFill(rgbData, neighborLocation, targetColor, replacementColor)
130127
}
131128
}
132129
}

Recursive/test/FloodFill.test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ describe('FloodFill', () => {
2121
})
2222
})
2323

24+
describe.each([breadthFirstSearch, depthFirstSearch])('%o', (floodFillFun) => {
25+
it.each([
26+
[1, -1],
27+
[-1, 1],
28+
[0, 7],
29+
[7, 0]
30+
])('throws for start position [%i, %i]', (location) => {
31+
expect(() =>
32+
floodFillFun(generateTestRgbData(), location, green, orange)
33+
).toThrowError()
34+
})
35+
})
36+
2437
/**
2538
* Utility-function to test the function "breadthFirstSearch".
2639
*

0 commit comments

Comments
 (0)
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