Add draw_shape and draw_shapes with tests

draw_shape turns 360 divided by the number of sides after each side and rejects
fewer than 3 sides. draw_shapes draws a triangle up to a decagon, each in a color
from the palette.

Task: MIL-003#3
Task: MIL-003#4
Task: MIL-003#5
This commit is contained in:
2026-10-07 23:59:05 +08:00
parent 9318a07fa0
commit 32861fc58f
5 changed files with 173 additions and 2 deletions
+6 -2
View File
@@ -3,17 +3,21 @@
@brief Solutions to the turtle graphics challenges of day 18 of Udemy's
100 Days of Code.
The challenges so far are @ref turtle_challenges.square.draw_square and
@ref turtle_challenges.dashed_line.draw_dashed_line. Each takes the turtle as its
The challenges so far are @ref turtle_challenges.square.draw_square,
@ref turtle_challenges.dashed_line.draw_dashed_line and
@ref turtle_challenges.shapes.draw_shape. Each takes the turtle as its
first argument, so it can be tested without a window.
"""
from turtle_challenges.colors import random_color, random_palette_color
from turtle_challenges.dashed_line import draw_dashed_line
from turtle_challenges.shapes import draw_shape, draw_shapes
from turtle_challenges.square import draw_square
__all__ = [
"draw_dashed_line",
"draw_shape",
"draw_shapes",
"draw_square",
"random_color",
"random_palette_color",
+12
View File
@@ -20,6 +20,9 @@ COLOR_CHANNEL_MIN = 0
## Largest value of one color channel.
COLOR_CHANNEL_MAX = COLOR_MODE
## Degrees in a full turn.
FULL_TURN_DEGREES = 360
## Degrees in a right angle.
RIGHT_ANGLE_DEGREES = 90
@@ -38,6 +41,15 @@ DASH_LENGTH = 10
## Challenge 2: length of the gap after each dash, in turtle units.
GAP_LENGTH = 10
## Challenge 3: fewest sides of a polygon (a triangle).
MIN_POLYGON_SIDES = 3
## Challenge 3: most sides of a polygon drawn in a row (a decagon).
MAX_POLYGON_SIDES = 10
## Challenge 3: length of one side of a polygon, in turtle units.
POLYGON_SIDE_LENGTH = 100
## Challenge 3: named colors a polygon is drawn in.
COLOR_PALETTE: tuple[str, ...] = (
"CornflowerBlue",
+56
View File
@@ -0,0 +1,56 @@
"""!
@file shapes.py
@brief Turtle Challenge 3: draw different shapes, each in a random color.
"""
import random
from turtle_challenges.colors import random_palette_color
from turtle_challenges.constants import (
FULL_TURN_DEGREES,
MAX_POLYGON_SIDES,
MIN_POLYGON_SIDES,
POLYGON_SIDE_LENGTH,
)
from turtle_challenges.pen import Pen
def draw_shape(
pen: Pen, num_sides: int, side_length: float = POLYGON_SIDE_LENGTH
) -> None:
"""!
@brief Draw a regular polygon.
The turtle turns 360 divided by the number of sides after each side, so
five sides turn 72 degrees and the shape closes after one lap.
@param pen The turtle that draws.
@param num_sides Number of sides; at least 3.
@param side_length Length of each side, in turtle units.
@exception ValueError If @p num_sides is below 3, or @p side_length is not
positive.
"""
if num_sides < MIN_POLYGON_SIDES:
raise ValueError(
f"num_sides must be at least {MIN_POLYGON_SIDES}, got {num_sides}"
)
if side_length <= 0:
raise ValueError(f"side_length must be positive, got {side_length}")
angle = FULL_TURN_DEGREES / num_sides
for _ in range(num_sides):
pen.forward(side_length)
pen.right(angle)
def draw_shapes(pen: Pen, rng: random.Random | None = None) -> None:
"""!
@brief Draw a triangle, square, pentagon and so on up to a decagon.
Each shape gets a random color from the palette.
@param pen The turtle that draws.
@param rng Random generator for the colors; a shared one is used if omitted.
"""
for num_sides in range(MIN_POLYGON_SIDES, MAX_POLYGON_SIDES + 1):
pen.color(random_palette_color(rng))
draw_shape(pen, num_sides)