-
-
Notifications
You must be signed in to change notification settings - Fork 360
Add Flood Fill in Python #753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
84c8fff
041bc04
22b96a5
7cf1641
7ea3e01
8d1b1c2
cd8f00f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
from collections import namedtuple | ||
from queue import Queue | ||
|
||
Point = namedtuple("Point", "x y") | ||
Canvas = namedtuple("Canvas", "max_x max_y data") | ||
|
||
def inbounds(canvas, p): | ||
if p.x < 0 or p.y < 0 or p.x >= canvas.max_x or p.y >= canvas.max_y: | ||
return False | ||
return True | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a simple return statement like def inbounds(canvas, p):
return min(p) >= 0 and p.x < canvas.max_x and p.y < canvas.max_y |
||
|
||
def color(canvas, p, new_val): | ||
canvas.data[p.x][p.y] = new_val | ||
|
||
def find_neighbors(canvas, p, old_val, new_val): | ||
# north, south, east, west neighbors | ||
possible_neighbors = [ | ||
Point(p.x, p.y+1), | ||
Point(p.x+1, p.y), | ||
Point(p.x-1, p.y), | ||
Point(p.x, p.y-1) | ||
] | ||
|
||
# exclude the neighbors that go out of bounds and should not be colored | ||
neighbors = [] | ||
for possible_neighbor in possible_neighbors: | ||
if inbounds(canvas, possible_neighbor): | ||
if canvas.data[possible_neighbor.x][possible_neighbor.y] == old_val: | ||
neighbors.append(possible_neighbor) | ||
return neighbors | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer if you would use a generator instead of returning a list, but it works well enough for 4 neighbours |
||
|
||
def stack_fill(canvas, p, old_val, new_val): | ||
if old_val == new_val: | ||
return | ||
|
||
S = list() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Python style guide recommends that variable names should be in |
||
S.append(p) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, you could just do |
||
|
||
while len(S) > 0: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Python has the capability of evaluating the "thruthiness" of an object. So the loop condition simplifies to: while s: |
||
cur_loc = S.pop() | ||
if canvas.data[cur_loc.x][cur_loc.y] == old_val: | ||
color(canvas, cur_loc, new_val) | ||
S+= find_neighbors(canvas, cur_loc, old_val, new_val) | ||
lazyprop marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def queue_fill(canvas, p, old_val, new_val): | ||
if old_val == new_val: | ||
return | ||
|
||
Q = Queue() | ||
Q.put(p) | ||
|
||
color(canvas, p, new_val) | ||
|
||
while not Q.empty(): | ||
cur_loc = Q.get() | ||
neighbors = find_neighbors(canvas, cur_loc, old_val, new_val) | ||
|
||
for neighbor in neighbors: | ||
color(canvas, neighbor, new_val) | ||
Q.put(neighbor) | ||
|
||
def recursive_fill(canvas, p, old_val, new_val): | ||
if old_val == new_val: | ||
return | ||
|
||
color(canvas, p, new_val) | ||
|
||
neighbors = find_neighbors(canvas, p, old_val, new_val) | ||
for neighbor in neighbors: | ||
recursive_fill(canvas, neighbor, old_val, new_val) | ||
|
||
def main(): | ||
grid = [ | ||
[0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 0], | ||
[1, 1, 1, 1, 1], | ||
[0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 0] | ||
] | ||
answer = [ | ||
[1, 1, 1, 1, 1], | ||
[1, 1, 1, 1, 1], | ||
[1, 1, 1, 1, 1], | ||
[0, 0, 0, 0, 0], | ||
[0, 0, 0, 0, 0] | ||
] | ||
|
||
c0 = Canvas(5, 5, grid) | ||
c1 = Canvas(5, 5, grid) | ||
c2 = Canvas(5, 5, grid) | ||
|
||
start_loc = Point(0, 0) | ||
|
||
recursive_fill(c0, start_loc, 0, 1) | ||
queue_fill(c1, start_loc, 0, 1) | ||
stack_fill(c2, start_loc, 0, 1) | ||
|
||
assert c0.data == answer | ||
assert c1.data == answer | ||
assert c2.data == answer | ||
|
||
print("Tests Passed") | ||
|
||
if __name__ == "__main__": | ||
main() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure this is possible at all. An element of a tuple should probably be immutable itself if you want to avoid errors, while the way you implemented the algorithm is using a list.
Maybe you should consider using a dataclass instead, which doesn't have this restriction.