Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
Trees
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Deploy
Model registry
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
1MAE002 - ALGORITHM AND COMPUTING
Advanced
Trees
Commits
a574dbf0
Unverified
Commit
a574dbf0
authored
Jun 27, 2024
by
STEVAN Antoine
Browse files
Options
Downloads
Patches
Plain Diff
add src.ui.maze and a README
parent
08acbeb8
No related branches found
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/README.md
+70
-0
70 additions, 0 deletions
src/README.md
src/ui/grid.py
+64
-0
64 additions, 0 deletions
src/ui/grid.py
src/ui/maze.py
+341
-0
341 additions, 0 deletions
src/ui/maze.py
with
475 additions
and
0 deletions
src/README.md
0 → 100644
+
70
−
0
View file @
a574dbf0
Below are snippets that show how to define a maze and use the
`src.ui.maze`
module:
-
import the library
```
python
from
src.ui.maze
import
Canva
```
-
define the maze, it should be a dictionary with the same keys as show below
```
python
maze
=
{
"
width
"
:
32
,
"
height
"
:
32
,
"
vertices
"
:
[],
"
edges
"
:
[],
"
size
"
:
25
,
}
```
-
create the canva that will hold the animation
```
python
canva
=
Canva
(
maze
[
"
size
"
]
*
maze
[
"
width
"
],
maze
[
"
size
"
]
*
maze
[
"
height
"
],
caption
=
""
,
frame_rate
=
60
,
)
canva
.
setup
()
```
-
your "_build_" function that will create the maze should take an optional
`callback`
argument which should be a function that takes a maze as input and
calls
`Canva.step`
```
python
lambda
m
:
canva
.
step
(
m
)
```
-
finally, run the main loop
```
python
# setup some variables
p
=
[]
complete
=
False
# loop 'til the end of time
while
True
:
# run the animation and get back a signal from the canva
res
=
canva
.
loop
(
maze
,
path
=
p
,
complete
=
complete
)
# if the signal is a _falsy_ boolean, then the _path_ and _complete_ should
# be reset
if
isinstance
(
res
,
bool
)
and
not
res
:
p
=
[]
complete
=
False
# continue to loop and wait for another input
continue
# otherwise, the canva just sent back the positions of the path to compute
(
i_s
,
j_s
),
(
i_e
,
j_e
)
=
res
p
=
path
(
...
callback
=
lambda
m
,
p
,
v
,
n
:
canva
.
step
(
m
,
p
,
v
,
n
,
complete
=
False
),
)
complete
=
True
```
## key bindings
-
_SPACE_ to pause and unpause the animation
-
_move the mouse_ to preselect a cell
-
_left click_ on two different maze cells to select them
-
_right click_ to unselect all the cells
-
_ENTER_ to run the path algorithm once the maze generation is done
This diff is collapsed.
Click to expand it.
src/ui/grid.py
0 → 100644
+
64
−
0
View file @
a574dbf0
import
pygame
import
logging
from
collections
import
namedtuple
from
typing
import
Tuple
_VALID_SQUARE_GRID_STYLES
=
[
"
lines
"
,
"
cells
"
]
SquareGridStyle
=
namedtuple
(
"
SquareGridStyle
"
,
[
"
type
"
,
'
m
'
,
'
r
'
,
'
w
'
],
defaults
=
[
"
lines
"
,
.
9
,
.
1
,
5
],
)
def
square
(
screen
:
pygame
.
surface
.
Surface
,
width
:
int
,
height
:
int
,
size
:
int
,
color
:
Tuple
[
int
,
int
,
int
],
style
:
SquareGridStyle
=
SquareGridStyle
(),
):
if
style
.
type
not
in
_VALID_SQUARE_GRID_STYLES
:
logging
.
error
(
f
"
invalid square grid style
'
{
style
}
'
, expected one of
{
_VALID_SQUARE_GRID_STYLES
}
"
)
return
if
style
.
type
==
"
lines
"
:
w
,
h
=
screen
.
get_size
()
for
i
in
range
(
1
,
height
):
pygame
.
draw
.
line
(
screen
,
color
,
(
0
,
i
*
size
),
(
w
,
i
*
size
),
width
=
style
.
w
)
for
j
in
range
(
1
,
width
):
pygame
.
draw
.
line
(
screen
,
color
,
(
j
*
size
,
0
),
(
j
*
size
,
h
),
width
=
style
.
w
)
elif
style
.
type
==
"
cells
"
:
d
=
(
style
.
m
*
size
)
//
2
s
=
int
(
size
*
style
.
m
)
for
i
in
range
(
height
):
for
j
in
range
(
width
):
cell
(
screen
,
i
,
j
,
size
,
color
,
d
,
style
.
r
,
s
)
def
cell
(
screen
:
pygame
.
surface
.
Surface
,
i
:
int
,
j
:
int
,
size
:
int
,
color
:
Tuple
[
int
,
int
,
int
],
d
:
int
,
r
:
int
,
s
:
int
,
):
c_x
,
c_y
=
int
((
j
+
.
5
)
*
size
),
int
((
i
+
.
5
)
*
size
)
pygame
.
draw
.
rect
(
screen
,
color
,
(
c_x
-
d
,
c_y
-
d
,
s
,
s
),
border_radius
=
int
(
size
*
r
),
)
This diff is collapsed.
Click to expand it.
src/ui/maze.py
0 → 100644
+
341
−
0
View file @
a574dbf0
from
dataclasses
import
dataclass
import
pygame
import
sys
import
itertools
from
typing
import
Tuple
,
List
,
Union
from
math
import
cos
,
sin
,
pi
from
src.ui
import
grid
StartEndPair
=
Tuple
[
Tuple
[
int
,
int
],
Tuple
[
int
,
int
]]
COLORS
=
{
"
background
"
:
(
0
,
0
,
0
),
"
empty cell
"
:
(
200
,
200
,
200
),
"
selected cell
"
:
(
200
,
200
,
0
),
"
cell under mouse
"
:
(
0
,
200
,
200
),
"
visited cell
"
:
(
50
,
50
,
50
),
"
visited cell link
"
:
(
25
,
25
,
25
),
"
next cell
"
:
(
0
,
255
,
0
),
"
cell
"
:
(
0
,
128
,
0
),
"
link
"
:
(
0
,
102
,
0
),
"
walls
"
:
(
200
,
200
,
200
),
"
path
"
:
(
100
,
0
,
0
),
"
path link
"
:
(
80
,
0
,
0
),
"
path ends
"
:
(
255
,
165
,
0
),
"
path ends link
"
:
(
255
*
0.7
,
165
*
0.7
,
0
),
"
path ends ends
"
:
(
255
,
0
,
255
),
"
pause
"
:
(
255
,
0
,
0
),
}
STYLE
=
{
"
link width
"
:
.
5
,
"
grid
"
:
grid
.
SquareGridStyle
(
type
=
"
cells
"
,
m
=
.
9
,
r
=
.
1
),
"
walls
"
:
.
15
,
}
def
_rotate_line
(
a
:
Tuple
[
float
,
float
],
b
:
Tuple
[
float
,
float
],
angle
:
float
,
)
->
Tuple
[
Tuple
[
float
,
float
],
Tuple
[
float
,
float
]]:
x_a
,
y_a
=
a
x_b
,
y_b
=
b
# middle
x_m
=
(
x_a
+
x_b
)
/
2
y_m
=
(
y_a
+
y_b
)
/
2
# shift
x_a
-=
x_m
y_a
-=
y_m
x_b
-=
x_m
y_b
-=
y_m
cos_a
,
sin_a
=
cos
(
angle
),
sin
(
angle
)
# rotate
x_a
,
y_a
=
cos_a
*
x_a
+
sin_a
*
y_a
,
-
sin_a
*
x_a
+
cos_a
*
y_a
x_b
,
y_b
=
cos_a
*
x_b
+
sin_a
*
y_b
,
-
sin_a
*
x_b
+
cos_a
*
y_b
# shift
x_a
+=
x_m
y_a
+=
y_m
x_b
+=
x_m
y_b
+=
y_m
return
(
x_a
,
y_a
),
(
x_b
,
y_b
)
@dataclass
class
Canva
:
width
:
int
height
:
int
caption
:
str
frame_rate
:
int
screen
:
pygame
.
surface
.
Surface
=
None
clock
:
pygame
.
time
.
Clock
=
None
def
setup
(
self
):
pygame
.
init
()
self
.
screen
=
pygame
.
display
.
set_mode
((
self
.
width
,
self
.
height
))
pygame
.
display
.
set_caption
(
self
.
caption
)
self
.
clock
=
pygame
.
time
.
Clock
()
self
.
mouse
=
None
self
.
selected
=
[]
def
__handle_events
(
self
,
s
:
int
)
->
Union
[
StartEndPair
,
bool
]:
selected_reset
=
False
for
event
in
pygame
.
event
.
get
():
if
event
.
type
==
pygame
.
QUIT
or
(
event
.
type
==
pygame
.
KEYDOWN
and
event
.
key
==
pygame
.
K_ESCAPE
):
pygame
.
quit
()
sys
.
exit
()
elif
event
.
type
==
pygame
.
MOUSEBUTTONUP
:
if
event
.
button
==
pygame
.
BUTTON_RIGHT
:
self
.
selected
=
[]
elif
event
.
button
==
pygame
.
BUTTON_LEFT
:
x
,
y
=
event
.
pos
i
,
j
=
y
//
s
,
x
//
s
if
len
(
self
.
selected
)
<
2
and
(
i
,
j
)
not
in
self
.
selected
:
if
len
(
self
.
selected
)
==
0
:
selected_reset
=
True
self
.
selected
.
append
((
i
,
j
))
elif
event
.
type
==
pygame
.
KEYDOWN
:
if
event
.
key
==
pygame
.
K_RETURN
:
if
len
(
self
.
selected
)
==
2
:
return
tuple
(
self
.
selected
)
elif
event
.
key
==
pygame
.
K_SPACE
:
w
,
h
=
self
.
screen
.
get_size
()
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
pause
"
],
(
0
,
0
,
w
,
h
),
width
=
5
)
pygame
.
display
.
flip
()
pause
=
True
while
pause
:
for
event
in
pygame
.
event
.
get
():
if
event
.
type
==
pygame
.
QUIT
or
(
event
.
type
==
pygame
.
KEYDOWN
and
event
.
key
==
pygame
.
K_ESCAPE
):
pygame
.
quit
()
sys
.
exit
()
elif
event
.
type
==
pygame
.
KEYDOWN
:
if
event
.
key
==
pygame
.
K_SPACE
:
pause
=
False
elif
event
.
type
==
pygame
.
MOUSEMOTION
:
self
.
mouse
=
event
.
pos
if
selected_reset
:
return
not
selected_reset
def
__render
(
self
,
maze
,
path
:
List
[
int
]
=
None
,
visited
:
List
[
int
]
=
None
,
next
:
List
[
int
]
=
None
,
complete
:
bool
=
False
,
):
self
.
screen
.
fill
(
COLORS
[
"
background
"
])
grid
.
square
(
self
.
screen
,
width
=
maze
[
"
width
"
],
height
=
maze
[
"
height
"
],
size
=
maze
[
"
size
"
],
color
=
COLORS
[
"
empty cell
"
],
style
=
STYLE
[
"
grid
"
],
)
# edges
for
a
,
b
in
maze
[
"
edges
"
]:
x_a
=
(.
5
+
a
%
maze
[
"
width
"
])
*
maze
[
"
size
"
]
y_a
=
(.
5
+
a
//
maze
[
"
width
"
])
*
maze
[
"
size
"
]
x_b
=
(.
5
+
b
%
maze
[
"
width
"
])
*
maze
[
"
size
"
]
y_b
=
(.
5
+
b
//
maze
[
"
width
"
])
*
maze
[
"
size
"
]
pygame
.
draw
.
line
(
self
.
screen
,
COLORS
[
"
link
"
],
(
x_a
,
y_a
),
(
x_b
,
y_b
),
width
=
int
(
maze
[
"
size
"
]
*
STYLE
[
"
link width
"
]),
)
d
=
int
(
maze
[
"
size
"
]
*
STYLE
[
"
grid
"
].
m
)
r
=
int
(
maze
[
"
size
"
]
*
STYLE
[
"
grid
"
].
r
)
a
=
(
x_a
-
d
//
2
,
y_a
-
d
//
2
,
d
,
d
)
b
=
(
x_b
-
d
//
2
,
y_b
-
d
//
2
,
d
,
d
)
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
cell
"
],
a
,
border_radius
=
r
)
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
cell
"
],
b
,
border_radius
=
r
)
if
visited
is
not
None
:
for
v
in
visited
:
grid
.
cell
(
self
.
screen
,
v
//
maze
[
"
width
"
],
v
%
maze
[
"
width
"
],
maze
[
"
size
"
],
COLORS
[
"
visited cell
"
],
(
STYLE
[
"
grid
"
].
m
*
maze
[
"
size
"
])
//
2
,
STYLE
[
"
grid
"
].
r
,
int
(
maze
[
"
size
"
]
*
STYLE
[
"
grid
"
].
m
),
)
if
next
is
not
None
:
for
v
in
next
:
grid
.
cell
(
self
.
screen
,
v
//
maze
[
"
width
"
],
v
%
maze
[
"
width
"
],
maze
[
"
size
"
],
COLORS
[
"
next cell
"
],
(
STYLE
[
"
grid
"
].
m
*
maze
[
"
size
"
])
//
2
,
STYLE
[
"
grid
"
].
r
,
int
(
maze
[
"
size
"
]
*
STYLE
[
"
grid
"
].
m
),
)
if
path
is
not
None
:
for
i
,
(
a
,
b
)
in
enumerate
(
itertools
.
pairwise
(
path
)):
x_a
=
(.
5
+
a
%
maze
[
"
width
"
])
*
maze
[
"
size
"
]
y_a
=
(.
5
+
a
//
maze
[
"
width
"
])
*
maze
[
"
size
"
]
x_b
=
(.
5
+
b
%
maze
[
"
width
"
])
*
maze
[
"
size
"
]
y_b
=
(.
5
+
b
//
maze
[
"
width
"
])
*
maze
[
"
size
"
]
if
complete
:
pygame
.
draw
.
line
(
self
.
screen
,
COLORS
[
"
path ends link
"
],
(
x_a
,
y_a
),
(
x_b
,
y_b
),
width
=
int
(
maze
[
"
size
"
]
*
STYLE
[
"
link width
"
]),
)
else
:
pygame
.
draw
.
line
(
self
.
screen
,
COLORS
[
"
path link
"
],
(
x_a
,
y_a
),
(
x_b
,
y_b
),
width
=
int
(
maze
[
"
size
"
]
*
STYLE
[
"
link width
"
]),
)
d
=
int
(
maze
[
"
size
"
]
*
STYLE
[
"
grid
"
].
m
)
r
=
int
(
maze
[
"
size
"
]
*
STYLE
[
"
grid
"
].
r
)
a
=
(
x_a
-
d
//
2
,
y_a
-
d
//
2
,
d
,
d
)
b
=
(
x_b
-
d
//
2
,
y_b
-
d
//
2
,
d
,
d
)
if
complete
:
if
i
==
0
:
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
path ends ends
"
],
a
,
border_radius
=
r
)
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
path ends
"
],
b
,
border_radius
=
r
)
elif
i
==
len
(
path
)
-
2
:
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
path ends
"
],
a
,
border_radius
=
r
)
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
path ends ends
"
],
b
,
border_radius
=
r
)
else
:
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
path ends
"
],
a
,
border_radius
=
r
)
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
path ends
"
],
b
,
border_radius
=
r
)
else
:
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
path
"
],
a
,
border_radius
=
r
)
pygame
.
draw
.
rect
(
self
.
screen
,
COLORS
[
"
path
"
],
b
,
border_radius
=
r
)
# walls
h
=
[
(
maze
[
"
width
"
]
*
j
+
i
,
maze
[
"
width
"
]
*
j
+
i
+
1
)
for
j
in
range
(
maze
[
"
height
"
])
for
i
in
range
(
maze
[
"
width
"
]
-
1
)
]
v
=
[
(
maze
[
"
width
"
]
*
j
+
i
,
maze
[
"
width
"
]
*
j
+
i
+
maze
[
"
width
"
])
for
j
in
range
(
maze
[
"
height
"
]
-
1
)
for
i
in
range
(
maze
[
"
width
"
])
]
walls
=
[
(
a
,
b
)
for
(
a
,
b
)
in
h
+
v
if
(
a
,
b
)
not
in
maze
[
"
edges
"
]
and
(
b
,
a
)
not
in
maze
[
"
edges
"
]
]
for
a
,
b
in
walls
:
x_a
=
(.
5
+
a
%
maze
[
"
width
"
])
*
maze
[
"
size
"
]
-
1
y_a
=
(.
5
+
a
//
maze
[
"
width
"
])
*
maze
[
"
size
"
]
-
1
x_b
=
(.
5
+
b
%
maze
[
"
width
"
])
*
maze
[
"
size
"
]
-
1
y_b
=
(.
5
+
b
//
maze
[
"
width
"
])
*
maze
[
"
size
"
]
-
1
a
,
b
=
_rotate_line
((
x_a
,
y_a
),
(
x_b
,
y_b
),
pi
/
2
)
pygame
.
draw
.
line
(
self
.
screen
,
COLORS
[
"
walls
"
],
a
,
b
,
width
=
int
(
maze
[
"
size
"
]
*
STYLE
[
"
walls
"
])
)
# borders
w
,
h
=
maze
[
"
width
"
]
*
maze
[
"
size
"
],
maze
[
"
height
"
]
*
maze
[
"
size
"
]
for
a
,
b
in
[
((
0
,
0
),
(
w
,
0
)),
((
0
,
h
-
1
),
(
w
-
1
,
h
-
1
)),
((
0
,
0
),
(
0
,
h
)),
((
w
-
1
,
0
),
(
w
-
1
,
h
-
1
)),
]:
pygame
.
draw
.
line
(
self
.
screen
,
COLORS
[
"
walls
"
],
a
,
b
,
width
=
int
(
maze
[
"
size
"
]
*
STYLE
[
"
walls
"
])
)
if
self
.
mouse
is
not
None
:
x
,
y
=
self
.
mouse
grid
.
cell
(
self
.
screen
,
y
//
maze
[
"
size
"
],
x
//
maze
[
"
size
"
],
maze
[
"
size
"
],
COLORS
[
"
cell under mouse
"
],
(
STYLE
[
"
grid
"
].
m
*
maze
[
"
size
"
])
//
2
,
STYLE
[
"
grid
"
].
r
,
int
(
maze
[
"
size
"
]
*
STYLE
[
"
grid
"
].
m
),
)
for
i
,
j
in
self
.
selected
:
grid
.
cell
(
self
.
screen
,
i
,
j
,
maze
[
"
size
"
],
COLORS
[
"
selected cell
"
],
(
STYLE
[
"
grid
"
].
m
*
maze
[
"
size
"
])
//
2
,
STYLE
[
"
grid
"
].
r
,
int
(
maze
[
"
size
"
]
*
STYLE
[
"
grid
"
].
m
),
)
pygame
.
display
.
flip
()
def
step
(
self
,
maze
,
path
:
List
[
int
]
=
None
,
visited
:
List
[
int
]
=
None
,
next
:
List
[
int
]
=
None
,
complete
:
bool
=
False
,
)
->
Union
[
StartEndPair
,
bool
]:
res
=
self
.
__handle_events
(
s
=
maze
[
"
size
"
])
if
res
is
not
None
:
return
res
self
.
__render
(
maze
,
path
,
visited
,
next
,
complete
)
self
.
clock
.
tick
(
self
.
frame_rate
)
def
loop
(
self
,
maze
,
path
:
List
[
int
]
=
None
,
visited
:
List
[
int
]
=
None
,
next
:
List
[
int
]
=
None
,
complete
:
bool
=
False
,
)
->
Union
[
StartEndPair
,
bool
]:
if
complete
:
self
.
selected
=
[]
while
True
:
res
=
self
.
step
(
maze
,
path
,
visited
,
next
,
complete
)
if
res
is
not
None
:
return
res
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment