cs110_ex5

   1## DON"T OPEN THIS FILE! USE THE PURPLE BUTTON ON THE ASSIGNMENT
   2##   to see what functions are available and what their inputs are!
   3
   4###################################################################
   5
   6## PROCEED AT YOUR OWN RISK! THERE BE DRAGONS!
   7
   8###################################################################
   9### IGNORE EVERYTHING THAT STARTS WITH A _
  10from random import randint
  11from math import sqrt, pi, radians, sin, cos, floor
  12from time import sleep
  13
  14__docformat__ = "google"
  15
  16_a_canvas = None
  17
  18
  19def _safe_color(color ):
  20    color = color.strip()
  21    # Could also do some other verifications here...
  22    return color
  23
  24
  25def rectangle(
  26    top_left=(0, 0), width=25, height=50, color="hot pink", outline="", tag="", 
  27):
  28    """
  29    A reporter function that draws a rectangle.
  30    Args:
  31        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
  32        width (`int`): How wide to draw the shape.
  33        height (`int`): How tall to draw the shape.
  34        color (`str`): What color to draw the shape.
  35        outline (`str`): What color should the border of the shape be.
  36        tag (`str`): The tag to assign to the shape.
  37
  38    Returns:
  39         `Shape`: The rectangle that was created.
  40    """
  41    point_0 = top_left
  42    point_1 = (top_left[0] + width, top_left[1])
  43    point_2 = (top_left[0] + width, top_left[1] + height)
  44    point_3 = (top_left[0], top_left[1] + height)
  45    return _a_canvas.create_polygon(
  46        point_0, point_1, point_2, point_3, fill=_safe_color(color), tags=tag, 
  47    )
  48
  49
  50def square(top_left=(0, 0), size=25, color="hot pink", outline="", tag="", ):
  51    """
  52    A reporter function that draws a square.
  53    Args:
  54        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
  55        size (`int`): How big to draw the shape.
  56        color (`str`): What color to draw the shape.
  57        outline (`str`): What color should the border of the shape be.
  58        tag (`str`): The tag to assign to the shape.
  59
  60    Returns:
  61         `Shape`: The square that was created.
  62    """
  63    return rectangle(
  64        top_left=top_left, width=size, height=size, color=color, tag=tag, 
  65    )
  66
  67
  68def oval(
  69    center=(0, 0),
  70    radius_x=25,
  71    radius_y=50,
  72    color="hot pink",
  73    outline="",
  74    tag="",
  75    ,
  76):
  77    """
  78    A reporter function that draws an oval.
  79    Args:
  80        center (`tuple`): A coordinate representing the center of the shape.
  81        radius_x (`int`): Specifies the oval"s radius on the x-axis.
  82        radius_y (`int`): Specifies the oval"s radius on the y-axis.
  83        color (`str`): What color to draw the shape.
  84        outline (`str`): What color should the border of the shape be.
  85        tag (`str`): The tag to assign to the shape.
  86
  87    Returns:
  88         `Shape`: The oval that was created.
  89    """
  90    x = center[0]
  91    y = center[1]
  92    x0, y0, x1, y1 = (x - radius_x, y - radius_y, x + radius_x, y + radius_y)
  93    steps = 100
  94    # major and minor axes
  95    a = (x1 - x0) / 2.0
  96    b = (y1 - y0) / 2.0
  97    # center
  98    xc = x0 + a
  99    yc = y0 + b
 100    point_list = []
 101    # create the oval as a list of points
 102    for i in range(steps):
 103        # Calculate the angle for this step
 104        theta = (pi * 2) * (float(i) / steps)
 105        x = a * cos(theta)
 106        y = b * sin(theta)
 107        point_list.append(round(x + xc))
 108        point_list.append(round(y + yc))
 109
 110    return _a_canvas.create_polygon(
 111        point_list, fill=_safe_color(color), tags=tag, 
 112    )
 113
 114
 115def cloud(center=(0, 0), size=30, color="white", tag=""):
 116    """
 117    Reporter function that draws a cloud to the screen.
 118    Args:
 119        center (`tuple`): the point on which to center the cloud
 120        size (`int`): how big (roughly) the cloud is drawn
 121        color (`str`): which determines the color of the cloud
 122        tag (`str`): to give the cloud a name
 123
 124    Returns:
 125        `Shape`: The cloud that was created.
 126    """
 127    for i in range(10):
 128        x_offset = randint((-1 * size * 1.333), (size * 1.333))
 129        y_offset = randint(0, (size * 0.667))
 130        circle(
 131            center=(center[0] + x_offset, center[1] + y_offset),
 132            radius=randint((size * 0.667), (size * 1.667)),
 133            color=color,
 134            tag=tag,
 135        )
 136    return tag
 137
 138
 139def circle(center=(0, 0), radius=25, color="hot pink", outline="", tag="", ):
 140    """
 141    A reporter function that draws a circle.
 142    Args:
 143        center (`tuple`): A coordinate representing the center of the shape.
 144        radius (`int`): Specifies the circle"s radius.
 145        color (`str`): What color to draw the shape.
 146        outline (`str`): What color should the border of the shape be.
 147        tag (`str`): The tag to assign to the shape.
 148
 149    Returns:
 150         `Shape`: The circle that was created.
 151    """
 152    return oval(
 153        center=center, radius_x=radius, radius_y=radius, color=color, tag=tag, 
 154    )
 155
 156
 157def wedge(
 158    center=(0, 0), radius=25, angle=180, color="hot pink", outline="", tag="", 
 159):
 160    """
 161    A reporter function that draws a circle.
 162    Args:
 163        center (`tuple`): A coordinate representing the center of the shape.
 164        radius (`int`): Specifies the circle"s radius.
 165        angle (`int`): A number between 0 and 360 that specifies how much of the circle to draw.
 166        color (`str`): What color to draw the shape.
 167        outline (`str`): What color should the border of the shape be.
 168        tag (`str`): The tag to assign to the shape.
 169
 170    Returns:
 171         `Shape`: The wedge that was created.
 172    """
 173    point_list = [center[0], center[1]]
 174    for i in range(0, 0 + angle):
 175        x1 = center[0] + radius * cos(radians(i))
 176        point_list.append(x1)
 177        y1 = center[1] + radius * sin(radians(i))
 178        point_list.append(y1)
 179
 180    point_list.append(center[0])
 181    point_list.append(center[1])
 182
 183    return _a_canvas.create_polygon(
 184        point_list, fill=_safe_color(color), outline=outline, tags=tag, 
 185    )
 186
 187
 188def triangle(
 189    bottom_center=(0, 0),
 190    width=25,
 191    top_shift=0,
 192    height=0,
 193    color="hot pink",
 194    outline="",
 195    tag="",
 196    ,
 197):
 198    """
 199    A reporter function that draws a triangle.
 200    Args:
 201        bottom_center (`tuple`): A coordinate representing the bottom center of the shape.
 202        width (`int`): Specifies the width of the base of the triangle.
 203        top_shift (`int`): Specifies the how far to the left or right to shift the top of
 204            the triangle from the bottom center.
 205        height (`int`): Specifies the triangle"s height.
 206        color (`str`): What color to draw the shape.
 207        outline (`str`): What color should the border of the shape be.
 208        tag (`str`): The tag to assign to the shape.
 209
 210    Returns:
 211         `Shape`: The triangle that was created.
 212    """
 213    if height == 0
 214        height = width * sqrt(3) / 2
 215    point_0 = (bottom_center[0] - width / 2, bottom_center[1])
 216    point_1 = (bottom_center[0] + width / 2, bottom_center[1])
 217    point_2 = (bottom_center[0] + top_shift, bottom_center[1] - height)
 218
 219    return _a_canvas.create_polygon(
 220        point_0, point_1, point_2, fill=_safe_color(color), tags=tag, 
 221    )
 222
 223
 224def line(points=[], curvy=False, color="hot pink", tag="", ):
 225    """
 226    A reporter function that draws a line given a list of points.
 227    Args:
 228        points (`list`): The points that define the line; this should be a list of tuples (coordinates).
 229        curvy (`bool`): Makes a curvy line instead.
 230        color (`str`): What color to make the shape.
 231        tag (`str`): The tag to assign to the shape.
 232
 233    Returns:
 234        `Shape`: The line that was created.
 235    """
 236    return _a_canvas.create_line(points, fill=color, smooth=curvy, tags=tag, )
 237
 238
 239def arc(points=[], width=5, color="hot pink", line_steps=15, tag="", ):
 240    """
 241    A reporter function that draws an arc ("curve") given a list of points.
 242    Args:
 243        points (`list`): The points outlining the curve; this should be a list of tuples (coordinates).
 244            Make sure to give it at least 3 (x,y) coordinates that aren"t a straight line!
 245        color (`str`): What color to make the shape.
 246        tag (`str`): The tag to assign to the shape.
 247
 248    Returns:
 249        `Shape`: The arc that was created.
 250    """
 251    return _a_canvas.create_line(
 252        points,
 253        width=width,
 254        fill=color,
 255        splinesteps=line_steps,
 256        smooth=True,
 257        tags=tag,
 258        ,
 259    )
 260
 261
 262def diamond(
 263    center=(0, 0), width=25, height=50, color="hot pink", outline="", tag="", 
 264):
 265    """
 266    A reporter function that draws a rectangle.
 267    Args:
 268        center (`tuple`): A coordinate representing the center of the shape.
 269        width (`int`): How wide to draw the shape.
 270        height (`int`): How tall to draw the shape.
 271        color (`str`): What color to draw the shape.
 272        outline (`str`): What color should the border of the shape be.
 273        tag (`str`): The tag to assign to the shape.
 274
 275    Returns:
 276         `Shape`: The shape that was created.
 277    """
 278    point_0 = (center[0] - width / 2, center[1])
 279    point_1 = (center[0], center[1] - height / 2)
 280    point_2 = (center[0] + width / 2, center[1])
 281    point_3 = (center[0], center[1] + height / 2)
 282    return _a_canvas.create_polygon(
 283        point_0,
 284        point_1,
 285        point_2,
 286        point_3,
 287        fill=_safe_color(color),
 288        tags=tag,
 289        outline=outline,
 290        ,
 291    )
 292
 293
 294def star(
 295    center=(0, 0),
 296    radius=50,
 297    color="hot pink",
 298    outer_radius=75,
 299    points=5,
 300    outline="",
 301    tag="",
 302    ,
 303):
 304    """
 305    A reporter function that draws a star.
 306    Args:
 307        center (`tuple`): A coordinate representing the center of the shape.
 308        radius (`int`): Specifies the radius of the inside part of the star.
 309        color (`str`): Specifies the color of the star.
 310        outer_radius (`int`): Specifies the radius of the outside part of the star.
 311        points (`int`): Specifies the number of points for the star.
 312        outline (`str`): What color should the border of the shape be.
 313        tag (`str`): The tag to assign to the shape.
 314
 315    Returns:
 316         `Shape`: The star that was created.
 317    """
 318    arc_segment = 360 / points
 319    vertices = []
 320    for i in range(points):
 321        inner_point = (
 322            radius * cos(radians(arc_segment * i)) + center[0],
 323            -1 * radius * sin(radians(arc_segment * i)) + center[1],
 324        )
 325        vertices.append(inner_point)
 326        outer_point = (
 327            outer_radius * cos(radians(arc_segment * i + arc_segment / 2)) + center[0],
 328            -1 * outer_radius * sin(radians(arc_segment * i + arc_segment / 2))
 329            + center[1],
 330        )
 331        vertices.append(outer_point)
 332    return polygon(vertices, color=color, tag=tag, )
 333
 334
 335def polygon(points=[], color="hot pink", outline="", tag="", ):
 336    """
 337    A reporter function that draws a polygon given a list of points.
 338    Args:
 339        points (`list`): The points outlining the polygon; this should be a list of tuples (coordinates).
 340            defaults to an empty list.
 341        outline (`str`): What color should the border of the shape be.
 342        color (`str`): What color to make the shape.
 343
 344    Returns:
 345        `Shape`: The polygon that was created.
 346    """
 347    return _a_canvas.create_polygon(points, fill=_safe_color(color), tags=tag, )
 348
 349
 350def _polar_to_cartesian(r, theta):
 351    return (r * cos(theta)), (r * sin(theta))
 352
 353
 354def spiral(
 355    center=(0, 0), width=100, roughness=0.01, start=0, spirals=5, line_width=1, 
 356):
 357    """
 358    A reporter function that draws a spiral.
 359    Args:
 360        center (`tuple`): A coordinate representing the center of the shape.
 361        width (`int`): Specifies the total width of the spiral.
 362        roughness (`float`): Controls how spiral-y the shape is (lower is less spiral-y)
 363        start (`int`): Where on the spiral to start drawing.
 364        spirals (`int`): How many loops to draw.
 365        line_width (`int`): How wide for the line to be drawn.
 366        tag (`str`): The tag to assign to the shape.
 367
 368    Returns:
 369         `Shape`: The spiral that was created.
 370    """
 371    theta = 0.0
 372    r = start
 373    all_points = []
 374    prev_pos = _polar_to_cartesian(r, theta)
 375    distance = width / 4 / pi / spirals
 376    all_points.append((prev_pos[0] + center[0], prev_pos[1] + center[1]))
 377    while theta < 2 * spirals * pi
 378        theta += roughness
 379        r = start + distance * theta
 380        pos = _polar_to_cartesian(r, theta)
 381        all_points.append((pos[0] + center[0], pos[1] + center[1]))
 382
 383    return arc(points=all_points, width=line_width, )
 384
 385
 386def _draw_row(row, top_left, colors, pixel=25, tag=""):
 387    """
 388    Draws a single row of some pixel art.
 389
 390    Args:
 391        row (sequence): the row of artwork to draw
 392        top_left (`tuple`): the top left coordinate of the pixel art
 393        color (sequence): the colors to use for each square
 394        pixel (`int`, optional): how big each individual pixel should be
 395        tag (`str`, optional): the tag to assign to every square in the row
 396    """
 397    x = top_left[0]
 398    y = top_left[1]
 399    for cell in row
 400        if cell != 0
 401            square((x, y), pixel, color=colors[cell], tag=tag)
 402        x += pixel
 403
 404
 405def pixel_art(top_left, artwork, palette, pixel=10, tag=""):
 406    """
 407    Draws a pixel art design!
 408
 409    Args:
 410        top_left (`tuple`): the top left coordinate of the pixel art
 411        artwork (sequence of sequences): the art to draw
 412        palette (sequence): the palette of colors to use for each different square
 413        pixel (`int`, optional): how big each individual pixel should be
 414        tag (`str`, optional): the tag to assign to every square in the row
 415
 416    Note: this doesn"t return anything so make sure to use a tag if you want to animate / modify.
 417    """
 418    x = top_left[0]
 419    y = top_left[1]
 420    for row in artwork
 421        # draw each row at the specified (x, y) position:
 422        _draw_row(row, (x, y), colors=palette, pixel=pixel, tag=tag)
 423        # ...and don"t forget to shift the y-value down by the proper
 424        #  amount so that the next row won"t draw on top of the first one:
 425        y += pixel
 426
 427
 428def move(shape, x_shift=0, y_shift=0):
 429    """
 430    Purpose: Move the x and y position of all shapes that have been tagged
 431    with the tag argument
 432
 433    Args:
 434        shape (`Shape` or Tag): The shape in question.
 435        x_shift (`int`; optional): amount to move in the x direction
 436        y_shift (`int`; optional): amount to move in the y direction
 437    """
 438    shape_ids = _a_canvas.find_withtag(shape)
 439    for id in shape_ids
 440        _a_canvas.move(id, x_shift, y_shift)
 441
 442
 443def portion(shape, start=0, end=0.5):
 444    """
 445    Purpose: Take a slice or portion of some already created shape.
 446
 447    Args:
 448        shape (`Shape` or Tag): The shape to take a portion of
 449        start (`float`): A number between 0 and 1 representing where to start the slice.
 450        end (`float`): A number between 0 and 1 representing where to end the slice.
 451
 452    For example, taking a portion from 0 to 0.5 of a circle would result in a semi-circle.
 453
 454    Note: this function is experimental. It might produce unexpected results!
 455    """
 456    all_shapes = _a_canvas.find_withtag(shape)
 457
 458    for a_shape in all_shapes
 459        coords = _a_canvas.coords(a_shape)
 460
 461        start_coord = floor(start * len(coords))
 462        if start_coord % 2 == 1
 463            start_coord = start_coord - 1  # need to start with an x,y pair
 464        end_coord = floor(end * len(coords))
 465        if end_coord % 2 == 1
 466            end_coord = end_coord - 1  # need to end with an x,y pair
 467
 468        # slice is up to not including so get the last x,y pair
 469        new_coords = coords[start_coord  end_coord + 2]
 470
 471        # loop shape back in on itself
 472        new_coords.append(new_coords[0])
 473        new_coords.append(new_coords[1])
 474
 475        # set the coordinates:
 476        _a_canvas.coords(a_shape, new_coords)
 477
 478
 479def put_in_front(shape):
 480    """
 481    A function that "raises" a shape to the "top" of the screen."
 482
 483    Args:
 484        shape (`Shape` or Tag): The shape in question.
 485    """
 486    _a_canvas.tag_raise(shape)
 487
 488
 489def put_in_back(shape):
 490    """
 491    A function that "lowers" a shape to the "bottom" of the screen."
 492
 493    Args:
 494        shape (`Shape` or Tag): The shape in question.
 495    """
 496    _a_canvas.tag_lower(shape)
 497
 498
 499def _get_outline(shape):
 500    """
 501    A reporter function that takes in a shape and calls the various helper functions to generate
 502    a sort of "summary" of that particular shape and returns it in the form of a dictionary.
 503
 504    Args:
 505        shape (`Shape` or Tag): The shape in question.
 506
 507    Returns:
 508        a `Dictionary` with the various properties of the shape
 509    """
 510
 511    return {
 512        "center" get_center(shape),
 513        "left" get_left(shape),
 514        "right" get_right(shape),
 515        "top" get_top(shape),
 516        "bottom" get_bottom(shape),
 517    }
 518
 519
 520def align(shape1, shape2, via="middle", offset_x=0, offset_y=0):
 521    """
 522    A reporter function that aligns `shape1` with `shape2`. It does this by moving `shape1` to align with
 523    whatever property of `shape2` is selected with the `via` input.
 524
 525    Args:
 526        shape1 (`Shape` or Tag): The first shape to use.
 527        shape2 (`Shape` or Tag): The second shape to use.
 528        via (`str`): Has to be one of, the following options: `"center"` (horizontal center),
 529            `"middle"` (vertical center), `"top"`, `"bottom"`, `"left"`, or `"right"`
 530        offset_x (`int`): How much to shift in the x-axis after alignment
 531        offset_y (`int`): How much to shift in the y-axis after alignment
 532
 533    Returns:
 534        `Shape`: The modified shape1.
 535    """
 536    via_options = ["center", "middle", "top", "bottom", "left", "right"]
 537    if via not in via_options
 538        raise ValueError(
 539            "The via input must be one of "
 540            + (via_options)
 541            + " but instead we found "
 542            + (via)
 543        )
 544
 545    outline1 = _get_outline(shape1)
 546    outline2 = _get_outline(shape2)
 547
 548    if via == "center"
 549        _a_canvas.move(
 550            shape1, (outline2["center"][0] - outline1["center"][0]) + offset_x, offset_y
 551        )
 552
 553    elif via == "middle"
 554        _a_canvas.move(
 555            shape1, offset_x, (outline2["center"][1] - outline1["center"][1]) + offset_y
 556        )
 557
 558    elif via == "top"
 559        _a_canvas.move(shape1, offset_x, (outline2["top"] - outline1["top"]) + offset_y)
 560
 561    elif via == "bottom"
 562        _a_canvas.move(
 563            shape1, offset_x, (outline2["bottom"] - outline1["bottom"]) + offset_y
 564        )
 565
 566    elif via == "left"
 567        _a_canvas.move(
 568            shape1, (outline2["left"] - outline1["left"]) + offset_x, offset_y
 569        )
 570
 571    elif via == "right"
 572        _a_canvas.move(
 573            shape1, (outline2["right"] - outline1["right"]) + offset_x, offset_y
 574        )
 575
 576    return shape1
 577
 578
 579def overlay(shape1, shape2, offset_x=0, offset_y=0):
 580    """
 581    A reporter function that overlays shape1 onto shape2. It does this by moving shape 1"s center
 582    to shape 2"s center, and then applying any specified offset.
 583    Args:
 584        shape1 (`Shape` or Tag): The first shape to use.
 585        shape2 (`Shape` or Tag): The second shape to use.
 586        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
 587        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
 588
 589    Returns:
 590        `Shape`: The modified shape1.
 591    """
 592    center1 = get_center(shape1)
 593    center2 = get_center(shape2)
 594    _a_canvas.move(
 595        shape1,
 596        (center2[0] - center1[0]) + offset_x,
 597        (center2[1] - center1[1]) + offset_y,
 598    )
 599    _a_canvas.tag_raise(shape1, shape2)
 600    return shape1
 601
 602
 603def underlay(shape1, shape2, offset_x=0, offset_y=0):
 604    """
 605    A reporter function that underlays shape1 beneath shape2. It does this by moving shape 1"s center
 606    to shape 2"s center, and then applying any specified offset.
 607    Args:
 608        shape1 (`Shape` or Tag): The first shape to use.
 609        shape2 (`Shape` or Tag): The second shape to use.
 610        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
 611        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
 612
 613    Returns:
 614        `Shape`: The modified shape1.
 615    """
 616    center1 = get_center(shape1)
 617    center2 = get_center(shape2)
 618    _a_canvas.move(
 619        shape1,
 620        (center2[0] - center1[0]) + offset_x,
 621        (center2[1] - center1[1]) + offset_y,
 622    )
 623    _a_canvas.tag_lower(shape1, shape2)
 624    return shape1
 625
 626
 627def above(shape1, shape2, offset_x=0, offset_y=0):
 628    """
 629    A reporter function that places shape1 above shape2 (vertically). It does this by moving shape 1"s center
 630    to shape 2"s center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
 631    specified offset.
 632
 633    Args:
 634        shape1 (`Shape` or Tag): The first shape to use.
 635        shape2 (`Shape` or Tag): The second shape to use.
 636        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
 637        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
 638
 639    Returns:
 640        `Shape`: The modified shape1.
 641    """
 642    overlay(shape1, shape2)
 643    _a_canvas.move(
 644        shape1,
 645        0 + offset_x,
 646        -1 * (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
 647    )
 648    return shape1
 649
 650
 651def beside(shape1, shape2, offset_x=0, offset_y=0):
 652    """
 653    A reporter function that places shape1 beside shape2 (horizontally). It does this by moving shape 1"s center
 654    to shape 2"s center, moving shape 1 in the x-direction the exact width of shape 2, and then applying any
 655    specified offset.
 656
 657    Args:
 658        shape1 (`Shape` or Tag): The first shape to use.
 659        shape2 (`Shape` or Tag): The second shape to use.
 660        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
 661        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
 662
 663    Returns:
 664        `Shape`: The modified shape1.
 665    """
 666    overlay(shape1, shape2)
 667    _a_canvas.move(
 668        shape1,
 669        (get_width(shape2) + get_width(shape1)) / 2 + offset_x,
 670        0 + offset_y,
 671    )
 672    return shape1
 673
 674
 675def below(shape1, shape2, offset_x=0, offset_y=0):
 676    """
 677    A reporter function that places shape1 below shape2 (vertically). It does this by moving shape 1"s center
 678    to shape 2"s center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
 679    specified offset.
 680
 681    Args:
 682        shape1 (`Shape` or Tag): The first shape to use.
 683        shape2 (`Shape` or Tag): The second shape to use.
 684        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
 685        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
 686
 687    Returns:
 688        `Shape`: The modified shape1.
 689    """
 690    overlay(shape1, shape2)
 691    _a_canvas.move(
 692        shape1,
 693        0 + offset_x,
 694        (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
 695    )
 696    return shape1
 697
 698
 699def delete(shape):
 700    """
 701    A function that deletes a shape from our screen.
 702
 703    Args:
 704        shape (`Shape` or Tag): The shape to delete.
 705    """
 706    _a_canvas.delete(shape)
 707
 708
 709def clear_window(keep_grid=True):
 710    """
 711    A function that deletes everything from the window.
 712
 713    Args:
 714        keep_grid (`bool`): Whether or not to keep the grid.
 715    """
 716    all_shapes = _a_canvas.find_all()
 717
 718    for shape in all_shapes
 719        tags = _a_canvas.gettags(shape)
 720        if "grid" in tags and keep_grid
 721            continue
 722        _a_canvas.delete(shape)
 723
 724
 725def duplicate(shape, color=None):
 726    """
 727    A reporter function that perfectly copies a shape and returns that copy.
 728
 729    Args:
 730        shape (`Shape` or Tag): The shape to duplicate.
 731        color (`str`): A new color to use with the duplicated shape.
 732
 733    Returns:
 734        `Shape`: The new duplicated shape.
 735    """
 736    shape_type = _a_canvas.type(shape)
 737    shape_config = _a_canvas.itemconfig(shape)
 738    shape_coords = _a_canvas.coords(shape)
 739    the_copy = None
 740    if shape_type == "polygon"
 741        new_config = {key shape_config[key][-1] for key in shape_config.keys()}
 742        if color != None
 743            new_config["fill"] = color
 744        the_copy = _a_canvas.create_polygon(shape_coords, new_config)
 745        return the_copy
 746
 747
 748def mirror(shape):
 749    """
 750    A function that takes a shape and flips it across its vertical
 751    axis, returning the modified shape.
 752
 753    Args:
 754        shape (`Shape` or Tag): The shape in question.
 755
 756    """
 757    center = get_center(shape)[0]
 758    shape_ids = _a_canvas.find_withtag(shape)
 759    for shape_id in shape_ids
 760        flipped_coordinates = []
 761        shape_coords = _a_canvas.coords(shape_id)
 762        counter = 0
 763        for num in shape_coords
 764            if counter % 2 == 0
 765                if num < center
 766                    flipped_coordinates.append(num + 2 * (center - num))
 767                elif num > center
 768                    flipped_coordinates.append(num - 2 * (num - center))
 769                else
 770                    flipped_coordinates.append(num)
 771            else
 772                flipped_coordinates.append(num)
 773            counter += 1
 774        _a_canvas.coords(shape_id, flipped_coordinates)
 775
 776
 777def rotate(shape, degrees=5, origin=None):
 778    """
 779    A reporter function that takes a shape and rotates it by a specified amount around a specified point.
 780    It does this by interpolating a polygon around the shape and calculating the shifts of individual
 781    points on the edge of the polygon.
 782
 783    Args:
 784        shape (`Shape` or Tag): The shape to rotate.
 785        degrees (`int`): The number of degrees to rotate the shape.
 786        origin (`tuple`): An `(x,y)` coordinate about which to perform the rotation. Defaults to the center
 787            of the given shape.
 788
 789    Returns:
 790        `Shape`: The modified shape.
 791    """
 792    if origin is None
 793        origin = get_center(shape)
 794
 795    theta = radians(degrees)
 796    ox, oy = origin
 797
 798    all_shapes = _a_canvas.find_withtag(shape)
 799
 800    for a_shape in all_shapes
 801        coords = _a_canvas.coords(a_shape)
 802        # update coordinates:
 803        for i in range(0, len(coords), 2):
 804            px, py = coords[i], coords[i + 1]
 805            qx = cos(theta) * (px - ox) - sin(theta) * (py - oy) + ox
 806            qy = sin(theta) * (px - ox) + cos(theta) * (py - oy) + oy
 807            coords[i] = qx
 808            coords[i + 1] = qy
 809        # set the coordinates:
 810        _a_canvas.coords(a_shape, coords)
 811
 812    return shape
 813
 814
 815def distance(point1, point2):
 816    """
 817    A reporter function calculates the distance between two `(x, y)` coordinates.
 818
 819    Args:
 820        point1 (`tuple`): The first `(x, y)` coordinate.
 821        point2 (`tuple`): The second `(x, y)` coordinate.
 822
 823    Returns:
 824         A `float` representing the distance between the two points.
 825    """
 826    return sqrt(((point1[0] - point2[0])  2) + ((point1[1] - point2[1])  2))
 827
 828
 829def scale(shape, x_scale=1.0, y_scale=1.0):
 830    """
 831    A function that takes a given `Shape` or tag and scales it on either/both the x and y-axis.
 832
 833    The two optional inputs accept floats between 0.0 and 1.0. Values greater than 1 will cause
 834    the shape to grow along that access. Values less than 1.0 will cause the shape to shrink.
 835
 836    Args:
 837        shape (`Shape` or Tag): The shape or tag to re-fill.
 838        x_scale (`float`): How much to scale in the x-axis.
 839        y_scale (`float`): How much to scale in the y-axis.
 840    """
 841    ids = _a_canvas.find_withtag(shape)
 842
 843    coord = get_center(shape)
 844
 845    for i in ids
 846        _a_canvas.scale(i, coord[0], coord[1], x_scale, y_scale)
 847
 848
 849def update_color(shape, color):
 850    """
 851    Change the fill color of a tagged object.
 852
 853    Args:
 854        shape (`Shape` or Tag): The shape or tag to re-fill.
 855        color (`str`): A color name or hex code to re-fill with.
 856    """
 857    ids = _a_canvas.find_withtag(shape)
 858    for id in ids
 859        _a_canvas.itemconfig(id, fill=color)
 860
 861
 862def interpolate_colors(color1, color2, frac):
 863    """
 864    A reporter function that generates a new color between two given colors.
 865    Args:
 866        color1 (`str`): The path of the file to wrap
 867        color2 (`str`): The path of the file to wrap
 868        frac (`float`): What fraction of each color to take. An input of 0 returns
 869            color1, an input of 1 returns color2, an input of 0.5 returns a color
 870            perfectly between the two.
 871
 872    Returns:
 873         A color (as a hex `str`) to be used elsewhere
 874    """
 875    if "#" not in color1
 876        color1 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color1)))
 877    else
 878        color1 = _tupelize_color(color1)
 879    if "#" not in color2
 880        color2 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color2)))
 881    else
 882        color2 = _tupelize_color(color2)
 883    return _interpolate_tuple(color1, color2, frac)
 884
 885
 886def get_colors(shape_or_shapes):
 887    """
 888    A reporter function that returns all the colors associated with a tag or list of tags.
 889
 890    Args:
 891        shape_or_shapes (`str`/`Shape` or `List`): the shape/tag or list of shapes/tags you"d like to find the colors of
 892
 893    Returns:
 894        A `List` containing all unique colors associated with that tag(s)
 895    """
 896    all_shapes = []
 897    if not isinstance(shape_or_shapes, ):
 898        shape_or_shapes = [shape_or_shapes]
 899    for shape in shape_or_shapes
 900        all_shapes += _a_canvas.find_withtag(shape)
 901
 902    all_colors = []
 903    for shape in all_shapes
 904        color = _a_canvas.itemcget(shape, "fill")
 905        if color not in all_colors
 906            all_colors.append(color)
 907
 908    return all_colors
 909
 910
 911def get_center(shape):
 912    """
 913    A reporter function calculates the a coordinate at the center of some shape.
 914
 915    Args:
 916        shape (`Shape` or Tag): The shape in question.
 917
 918    Returns:
 919         A `tuple` representing center of the given shape.
 920    """
 921    bbox = _safe_bbox(shape)
 922
 923    if bbox is None
 924        raise Exception(
 925            f"We couldn"t find the shape with id/tag {shape}. Make sure it exists!"
 926        )
 927
 928    return (((bbox[2] + bbox[0]) / 2), ((bbox[1] + bbox[3]) / 2))
 929
 930
 931def get_top(shape):
 932    """
 933    A reporter function calculates the minimum y-value of a given shape (since the y-axis is flipped).
 934
 935    Args:
 936        shape (`Shape` or Tag): The shape in question.
 937
 938    Returns:
 939         A `int` representing the minimum y-coordinate of the shape.
 940    """
 941    bbox = _safe_bbox(shape)
 942    return bbox[1]
 943
 944
 945def get_bottom(shape):
 946    """
 947    A reporter function calculates the maximum y-value of a given shape (since the y-axis is flipped).
 948
 949    Args:
 950        shape (`Shape` or Tag): The shape in question.
 951
 952    Returns:
 953         A `int` representing the maximum y-coordinate of the shape.
 954    """
 955    bbox = _safe_bbox(shape)
 956    return bbox[3]
 957
 958
 959def get_left(shape):
 960    """
 961    A reporter function calculates the minimum x-value of a given shape.
 962
 963    Args:
 964        shape (`Shape` or Tag): The shape in question.
 965
 966    Returns:
 967         A `int` representing the minimum x-coordinate of the shape.
 968    """
 969    bbox = _safe_bbox(shape)
 970    return bbox[0]
 971
 972
 973def get_right(shape):
 974    """
 975    A reporter function calculates the maximum x-value of a given shape.
 976
 977    Args:
 978        shape (`Shape` or Tag): The shape in question.
 979
 980    Returns:
 981         A `int` representing the maximum x-coordinate of the shape.
 982    """
 983    bbox = _safe_bbox(shape)
 984    return bbox[2]
 985
 986
 987def get_height(shape):
 988    """
 989    A reporter function calculates the height of some given shape.
 990
 991    Args:
 992        shape (`Shape` or Tag): The shape in question.
 993
 994    Returns:
 995         A `int` representing the height of the shape.
 996    """
 997    bbox = _safe_bbox(shape)
 998    return bbox[3] - bbox[1] - 1
 999
1000
1001def get_width(shape):
1002    """
1003    A reporter function calculates the width of some given shape.
1004
1005    Args:
1006        shape (`Shape` or Tag): The shape in question.
1007
1008    Returns:
1009         An `int` representing width of the shape.
1010    """
1011    bbox = _safe_bbox(shape)
1012    return bbox[2] - bbox[0] - 1
1013
1014
1015def make_grid(c, w, h, interval=100):
1016    """
1017    Draws a grid on a screen with intervals of 100.
1018
1019    Args:
1020        w (`int`): The width of the grid to draw
1021        h (`int`): The height of the grid to draw
1022    """
1023    # Creates all vertical lines at intervals of 100
1024    for i in range(0, w, interval):
1025        _a_canvas.create_line(i, 0, i, h, tag="grid", fill="black")
1026    # Creates all horizontal lines at intervals of 100
1027    for i in range(0, h, interval):
1028        _a_canvas.create_line(0, i, w, i, tag="grid", fill="black")
1029    # Creates axis labels
1030    offset = 2
1031    for y in range(0, h, interval):
1032        for x in range(0, w, interval):
1033            _a_canvas.create_oval(
1034                x - offset, y - offset, x + offset, y + offset, fill="black", tag="grid"
1035            )
1036            _a_canvas.create_text(
1037                x + offset,
1038                y + offset,
1039                text="({0}, {1})".format(x, y),
1040                anchor="nw",
1041                font=("Purisa", 8),
1042                fill="black",
1043                tag="grid",
1044            )
1045
1046
1047def _safe_bbox(shape):
1048    try
1049        bbox = _a_canvas.bbox(shape)
1050        if bbox is None
1051            Exception(
1052                f"We couldn"t find the shape with tag/id: {shape}. Make sure this shape exists!"
1053            )
1054        return bbox
1055    except
1056        raise Exception(
1057            f"We couldn"t find the shape with tag/id: {shape}. Make sure this shape exists!"
1058        )
1059
1060
1061def _tupelize_color(color):
1062    R = (color[13], 16)
1063    G = (color[35], 16)
1064    B = (color[57], 16)
1065    return R, G, B
1066
1067
1068def _interpolate_tuple(startcolor, goalcolor, frac):
1069    R = startcolor[0]
1070    G = startcolor[1]
1071    B = startcolor[2]
1072
1073    targetR = goalcolor[0]
1074    targetG = goalcolor[1]
1075    targetB = goalcolor[2]
1076
1077    DiffR = targetR - R
1078    DiffG = targetG - G
1079    DiffB = targetB - B
1080
1081    iR = (R + (DiffR * frac))
1082    iG = (G + (DiffG * frac))
1083    iB = (B + (DiffB * frac))
1084
1085    hR = hex(iR).replace("0x", "")
1086    hG = hex(iG).replace("0x", "")
1087    hB = hex(iB).replace("0x", "")
1088
1089    if len(hR) == 1
1090        hR = "0" + hR
1091    if len(hB) == 1
1092        hB = "0" + hB
1093    if len(hG) == 1
1094        hG = "0" + hG
1095
1096    color = ("#" + hR + hG + hB).upper()
1097
1098    return color
1099
1100
1101def does_tag_exist(tag):
1102    """
1103    Returns `True` if a given tag exists otherwise returns `False`.
1104
1105    Args:
1106        `tag` (`str`): [Required] The tag of the object to lookup.
1107
1108    """
1109    result = _a_canvas.find_withtag(tag)
1110
1111    if result
1112        return True
1113    else
1114        return False
1115
1116
1117def random_color():
1118    """
1119    Returns a random color as a `string` to be used.
1120    It does not accept any inputs.
1121    """
1122    r = lambda randint(0, 255)
1123    return "#%02X%02X%02X" % (r(), r(), r())
1124
1125
1126from tkinter import Tk, Canvas
1127
1128
1129def setup_shapes(title, background="white", grid=True, width=600, height=600):
1130    """
1131    A static function that sets up the pop-up window. DO NOT USE THIS FUNCTION.
1132    """
1133    global _a_canvas
1134    gui = Tk()
1135    gui.title(title)
1136    _a_canvas = Canvas(gui, background=background, width=width, height=width)
1137    _a_canvas.pack()
1138    if grid
1139        make_grid(_a_canvas, width, height)
1140    return _a_canvas
def rectangle( top_left=(0, 0), width=25, height=50, color="hot pink", outline="", tag="",):
26def rectangle(
27    top_left=(0, 0), width=25, height=50, color="hot pink", outline="", tag="", 
28):
29    """
30    A reporter function that draws a rectangle.
31    Args:
32        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
33        width (`int`): How wide to draw the shape.
34        height (`int`): How tall to draw the shape.
35        color (`str`): What color to draw the shape.
36        outline (`str`): What color should the border of the shape be.
37        tag (`str`): The tag to assign to the shape.
38
39    Returns:
40         `Shape`: The rectangle that was created.
41    """
42    point_0 = top_left
43    point_1 = (top_left[0] + width, top_left[1])
44    point_2 = (top_left[0] + width, top_left[1] + height)
45    point_3 = (top_left[0], top_left[1] + height)
46    return _a_canvas.create_polygon(
47        point_0, point_1, point_2, point_3, fill=_safe_color(color), tags=tag, 
48    )

A reporter function that draws a rectangle.

Arguments:
  • top_left (tuple): A coordinate representing the top left-hand corner of the shape.
  • width (int): How wide to draw the shape.
  • height (int): How tall to draw the shape.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The rectangle that was created.

def square( top_left=(0, 0), size=25, color="hot pink", outline="", tag="",):
51def square(top_left=(0, 0), size=25, color="hot pink", outline="", tag="", ):
52    """
53    A reporter function that draws a square.
54    Args:
55        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
56        size (`int`): How big to draw the shape.
57        color (`str`): What color to draw the shape.
58        outline (`str`): What color should the border of the shape be.
59        tag (`str`): The tag to assign to the shape.
60
61    Returns:
62         `Shape`: The square that was created.
63    """
64    return rectangle(
65        top_left=top_left, width=size, height=size, color=color, tag=tag, 
66    )

A reporter function that draws a square.

Arguments:
  • top_left (tuple): A coordinate representing the top left-hand corner of the shape.
  • size (int): How big to draw the shape.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The square that was created.

def oval( center=(0, 0), radius_x=25, radius_y=50, color="hot pink", outline="", tag="",):
 69def oval(
 70    center=(0, 0),
 71    radius_x=25,
 72    radius_y=50,
 73    color="hot pink",
 74    outline="",
 75    tag="",
 76    ,
 77):
 78    """
 79    A reporter function that draws an oval.
 80    Args:
 81        center (`tuple`): A coordinate representing the center of the shape.
 82        radius_x (`int`): Specifies the oval"s radius on the x-axis.
 83        radius_y (`int`): Specifies the oval"s radius on the y-axis.
 84        color (`str`): What color to draw the shape.
 85        outline (`str`): What color should the border of the shape be.
 86        tag (`str`): The tag to assign to the shape.
 87
 88    Returns:
 89         `Shape`: The oval that was created.
 90    """
 91    x = center[0]
 92    y = center[1]
 93    x0, y0, x1, y1 = (x - radius_x, y - radius_y, x + radius_x, y + radius_y)
 94    steps = 100
 95    # major and minor axes
 96    a = (x1 - x0) / 2.0
 97    b = (y1 - y0) / 2.0
 98    # center
 99    xc = x0 + a
100    yc = y0 + b
101    point_list = []
102    # create the oval as a list of points
103    for i in range(steps):
104        # Calculate the angle for this step
105        theta = (pi * 2) * (float(i) / steps)
106        x = a * cos(theta)
107        y = b * sin(theta)
108        point_list.append(round(x + xc))
109        point_list.append(round(y + yc))
110
111    return _a_canvas.create_polygon(
112        point_list, fill=_safe_color(color), tags=tag, 
113    )

A reporter function that draws an oval.

Arguments:
  • center (tuple): A coordinate representing the center of the shape.
  • radius_x (int): Specifies the oval's radius on the x-axis.
  • radius_y (int): Specifies the oval's radius on the y-axis.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The oval that was created.

def cloud(center=(0, 0), size=30, color="white", tag=""):
116def cloud(center=(0, 0), size=30, color="white", tag=""):
117    """
118    Reporter function that draws a cloud to the screen.
119    Args:
120        center (`tuple`): the point on which to center the cloud
121        size (`int`): how big (roughly) the cloud is drawn
122        color (`str`): which determines the color of the cloud
123        tag (`str`): to give the cloud a name
124
125    Returns:
126        `Shape`: The cloud that was created.
127    """
128    for i in range(10):
129        x_offset = randint((-1 * size * 1.333), (size * 1.333))
130        y_offset = randint(0, (size * 0.667))
131        circle(
132            center=(center[0] + x_offset, center[1] + y_offset),
133            radius=randint((size * 0.667), (size * 1.667)),
134            color=color,
135            tag=tag,
136        )
137    return tag

Reporter function that draws a cloud to the screen.

Arguments:
  • center (tuple): the point on which to center the cloud
  • size (int): how big (roughly) the cloud is drawn
  • color (str): which determines the color of the cloud
  • tag (str): to give the cloud a name
Returns:

Shape: The cloud that was created.

def circle( center=(0, 0), radius=25, color="hot pink", outline="", tag="",):
140def circle(center=(0, 0), radius=25, color="hot pink", outline="", tag="", ):
141    """
142    A reporter function that draws a circle.
143    Args:
144        center (`tuple`): A coordinate representing the center of the shape.
145        radius (`int`): Specifies the circle"s radius.
146        color (`str`): What color to draw the shape.
147        outline (`str`): What color should the border of the shape be.
148        tag (`str`): The tag to assign to the shape.
149
150    Returns:
151         `Shape`: The circle that was created.
152    """
153    return oval(
154        center=center, radius_x=radius, radius_y=radius, color=color, tag=tag, 
155    )

A reporter function that draws a circle.

Arguments:
  • center (tuple): A coordinate representing the center of the shape.
  • radius (int): Specifies the circle's radius.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The circle that was created.

def wedge( center=(0, 0), radius=25, angle=180, color="hot pink", outline="", tag="",):
158def wedge(
159    center=(0, 0), radius=25, angle=180, color="hot pink", outline="", tag="", 
160):
161    """
162    A reporter function that draws a circle.
163    Args:
164        center (`tuple`): A coordinate representing the center of the shape.
165        radius (`int`): Specifies the circle"s radius.
166        angle (`int`): A number between 0 and 360 that specifies how much of the circle to draw.
167        color (`str`): What color to draw the shape.
168        outline (`str`): What color should the border of the shape be.
169        tag (`str`): The tag to assign to the shape.
170
171    Returns:
172         `Shape`: The wedge that was created.
173    """
174    point_list = [center[0], center[1]]
175    for i in range(0, 0 + angle):
176        x1 = center[0] + radius * cos(radians(i))
177        point_list.append(x1)
178        y1 = center[1] + radius * sin(radians(i))
179        point_list.append(y1)
180
181    point_list.append(center[0])
182    point_list.append(center[1])
183
184    return _a_canvas.create_polygon(
185        point_list, fill=_safe_color(color), outline=outline, tags=tag, 
186    )

A reporter function that draws a circle.

Arguments:
  • center (tuple): A coordinate representing the center of the shape.
  • radius (int): Specifies the circle's radius.
  • angle (int): A number between 0 and 360 that specifies how much of the circle to draw.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The wedge that was created.

def triangle( bottom_center=(0, 0), width=25, top_shift=0, height=0, color="hot pink", outline="", tag="",):
189def triangle(
190    bottom_center=(0, 0),
191    width=25,
192    top_shift=0,
193    height=0,
194    color="hot pink",
195    outline="",
196    tag="",
197    ,
198):
199    """
200    A reporter function that draws a triangle.
201    Args:
202        bottom_center (`tuple`): A coordinate representing the bottom center of the shape.
203        width (`int`): Specifies the width of the base of the triangle.
204        top_shift (`int`): Specifies the how far to the left or right to shift the top of
205            the triangle from the bottom center.
206        height (`int`): Specifies the triangle"s height.
207        color (`str`): What color to draw the shape.
208        outline (`str`): What color should the border of the shape be.
209        tag (`str`): The tag to assign to the shape.
210
211    Returns:
212         `Shape`: The triangle that was created.
213    """
214    if height == 0
215        height = width * sqrt(3) / 2
216    point_0 = (bottom_center[0] - width / 2, bottom_center[1])
217    point_1 = (bottom_center[0] + width / 2, bottom_center[1])
218    point_2 = (bottom_center[0] + top_shift, bottom_center[1] - height)
219
220    return _a_canvas.create_polygon(
221        point_0, point_1, point_2, fill=_safe_color(color), tags=tag, 
222    )

A reporter function that draws a triangle.

Arguments:
  • bottom_center (tuple): A coordinate representing the bottom center of the shape.
  • width (int): Specifies the width of the base of the triangle.
  • top_shift (int): Specifies the how far to the left or right to shift the top of the triangle from the bottom center.
  • height (int): Specifies the triangle's height.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The triangle that was created.

def line(points=[], curvy=False, color="hot pink", tag="", ):
225def line(points=[], curvy=False, color="hot pink", tag="", ):
226    """
227    A reporter function that draws a line given a list of points.
228    Args:
229        points (`list`): The points that define the line; this should be a list of tuples (coordinates).
230        curvy (`bool`): Makes a curvy line instead.
231        color (`str`): What color to make the shape.
232        tag (`str`): The tag to assign to the shape.
233
234    Returns:
235        `Shape`: The line that was created.
236    """
237    return _a_canvas.create_line(points, fill=color, smooth=curvy, tags=tag, )

A reporter function that draws a line given a list of points.

Arguments:
  • points (list): The points that define the line; this should be a list of tuples (coordinates).
  • curvy (bool): Makes a curvy line instead.
  • color (str): What color to make the shape.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The line that was created.

def arc( points=[], width=5, color="hot pink", line_steps=15, tag="",):
240def arc(points=[], width=5, color="hot pink", line_steps=15, tag="", ):
241    """
242    A reporter function that draws an arc ("curve") given a list of points.
243    Args:
244        points (`list`): The points outlining the curve; this should be a list of tuples (coordinates).
245            Make sure to give it at least 3 (x,y) coordinates that aren"t a straight line!
246        color (`str`): What color to make the shape.
247        tag (`str`): The tag to assign to the shape.
248
249    Returns:
250        `Shape`: The arc that was created.
251    """
252    return _a_canvas.create_line(
253        points,
254        width=width,
255        fill=color,
256        splinesteps=line_steps,
257        smooth=True,
258        tags=tag,
259        ,
260    )

A reporter function that draws an arc ("curve") given a list of points.

Arguments:
  • points (list): The points outlining the curve; this should be a list of tuples (coordinates). Make sure to give it at least 3 (x,y) coordinates that aren't a straight line!
  • color (str): What color to make the shape.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The arc that was created.

def diamond( center=(0, 0), width=25, height=50, color="hot pink", outline="", tag="",):
263def diamond(
264    center=(0, 0), width=25, height=50, color="hot pink", outline="", tag="", 
265):
266    """
267    A reporter function that draws a rectangle.
268    Args:
269        center (`tuple`): A coordinate representing the center of the shape.
270        width (`int`): How wide to draw the shape.
271        height (`int`): How tall to draw the shape.
272        color (`str`): What color to draw the shape.
273        outline (`str`): What color should the border of the shape be.
274        tag (`str`): The tag to assign to the shape.
275
276    Returns:
277         `Shape`: The shape that was created.
278    """
279    point_0 = (center[0] - width / 2, center[1])
280    point_1 = (center[0], center[1] - height / 2)
281    point_2 = (center[0] + width / 2, center[1])
282    point_3 = (center[0], center[1] + height / 2)
283    return _a_canvas.create_polygon(
284        point_0,
285        point_1,
286        point_2,
287        point_3,
288        fill=_safe_color(color),
289        tags=tag,
290        outline=outline,
291        ,
292    )

A reporter function that draws a rectangle.

Arguments:
  • center (tuple): A coordinate representing the center of the shape.
  • width (int): How wide to draw the shape.
  • height (int): How tall to draw the shape.
  • color (str): What color to draw the shape.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The shape that was created.

def star( center=(0, 0), radius=50, color="hot pink", outer_radius=75, points=5, outline="", tag="",):
295def star(
296    center=(0, 0),
297    radius=50,
298    color="hot pink",
299    outer_radius=75,
300    points=5,
301    outline="",
302    tag="",
303    ,
304):
305    """
306    A reporter function that draws a star.
307    Args:
308        center (`tuple`): A coordinate representing the center of the shape.
309        radius (`int`): Specifies the radius of the inside part of the star.
310        color (`str`): Specifies the color of the star.
311        outer_radius (`int`): Specifies the radius of the outside part of the star.
312        points (`int`): Specifies the number of points for the star.
313        outline (`str`): What color should the border of the shape be.
314        tag (`str`): The tag to assign to the shape.
315
316    Returns:
317         `Shape`: The star that was created.
318    """
319    arc_segment = 360 / points
320    vertices = []
321    for i in range(points):
322        inner_point = (
323            radius * cos(radians(arc_segment * i)) + center[0],
324            -1 * radius * sin(radians(arc_segment * i)) + center[1],
325        )
326        vertices.append(inner_point)
327        outer_point = (
328            outer_radius * cos(radians(arc_segment * i + arc_segment / 2)) + center[0],
329            -1 * outer_radius * sin(radians(arc_segment * i + arc_segment / 2))
330            + center[1],
331        )
332        vertices.append(outer_point)
333    return polygon(vertices, color=color, tag=tag, )

A reporter function that draws a star.

Arguments:
  • center (tuple): A coordinate representing the center of the shape.
  • radius (int): Specifies the radius of the inside part of the star.
  • color (str): Specifies the color of the star.
  • outer_radius (int): Specifies the radius of the outside part of the star.
  • points (int): Specifies the number of points for the star.
  • outline (str): What color should the border of the shape be.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The star that was created.

def polygon(points=[], color="hot pink", outline="", tag="", ):
336def polygon(points=[], color="hot pink", outline="", tag="", ):
337    """
338    A reporter function that draws a polygon given a list of points.
339    Args:
340        points (`list`): The points outlining the polygon; this should be a list of tuples (coordinates).
341            defaults to an empty list.
342        outline (`str`): What color should the border of the shape be.
343        color (`str`): What color to make the shape.
344
345    Returns:
346        `Shape`: The polygon that was created.
347    """
348    return _a_canvas.create_polygon(points, fill=_safe_color(color), tags=tag, )

A reporter function that draws a polygon given a list of points.

Arguments:
  • points (list): The points outlining the polygon; this should be a list of tuples (coordinates). defaults to an empty list.
  • outline (str): What color should the border of the shape be.
  • color (str): What color to make the shape.
Returns:

Shape: The polygon that was created.

def spiral( center=(0, 0), width=100, roughness=0.01, start=0, spirals=5, line_width=1,):
355def spiral(
356    center=(0, 0), width=100, roughness=0.01, start=0, spirals=5, line_width=1, 
357):
358    """
359    A reporter function that draws a spiral.
360    Args:
361        center (`tuple`): A coordinate representing the center of the shape.
362        width (`int`): Specifies the total width of the spiral.
363        roughness (`float`): Controls how spiral-y the shape is (lower is less spiral-y)
364        start (`int`): Where on the spiral to start drawing.
365        spirals (`int`): How many loops to draw.
366        line_width (`int`): How wide for the line to be drawn.
367        tag (`str`): The tag to assign to the shape.
368
369    Returns:
370         `Shape`: The spiral that was created.
371    """
372    theta = 0.0
373    r = start
374    all_points = []
375    prev_pos = _polar_to_cartesian(r, theta)
376    distance = width / 4 / pi / spirals
377    all_points.append((prev_pos[0] + center[0], prev_pos[1] + center[1]))
378    while theta < 2 * spirals * pi
379        theta += roughness
380        r = start + distance * theta
381        pos = _polar_to_cartesian(r, theta)
382        all_points.append((pos[0] + center[0], pos[1] + center[1]))
383
384    return arc(points=all_points, width=line_width, )

A reporter function that draws a spiral.

Arguments:
  • center (tuple): A coordinate representing the center of the shape.
  • width (int): Specifies the total width of the spiral.
  • roughness (float): Controls how spiral-y the shape is (lower is less spiral-y)
  • start (int): Where on the spiral to start drawing.
  • spirals (int): How many loops to draw.
  • line_width (int): How wide for the line to be drawn.
  • tag (str): The tag to assign to the shape.
Returns:

Shape: The spiral that was created.

def pixel_art(top_left, artwork, palette, pixel=10, tag=""):
406def pixel_art(top_left, artwork, palette, pixel=10, tag=""):
407    """
408    Draws a pixel art design!
409
410    Args:
411        top_left (`tuple`): the top left coordinate of the pixel art
412        artwork (sequence of sequences): the art to draw
413        palette (sequence): the palette of colors to use for each different square
414        pixel (`int`, optional): how big each individual pixel should be
415        tag (`str`, optional): the tag to assign to every square in the row
416
417    Note: this doesn"t return anything so make sure to use a tag if you want to animate / modify.
418    """
419    x = top_left[0]
420    y = top_left[1]
421    for row in artwork
422        # draw each row at the specified (x, y) position:
423        _draw_row(row, (x, y), colors=palette, pixel=pixel, tag=tag)
424        # ...and don"t forget to shift the y-value down by the proper
425        #  amount so that the next row won"t draw on top of the first one:
426        y += pixel

Draws a pixel art design!

Arguments:
  • top_left (tuple): the top left coordinate of the pixel art
  • artwork (sequence of sequences): the art to draw
  • palette (sequence): the palette of colors to use for each different square
  • pixel (int, optional): how big each individual pixel should be
  • tag (str, optional): the tag to assign to every square in the row

Note: this doesn't return anything so make sure to use a tag if you want to animate / modify.

def move(shape, x_shift=0, y_shift=0):
429def move(shape, x_shift=0, y_shift=0):
430    """
431    Purpose: Move the x and y position of all shapes that have been tagged
432    with the tag argument
433
434    Args:
435        shape (`Shape` or Tag): The shape in question.
436        x_shift (`int`; optional): amount to move in the x direction
437        y_shift (`int`; optional): amount to move in the y direction
438    """
439    shape_ids = _a_canvas.find_withtag(shape)
440    for id in shape_ids
441        _a_canvas.move(id, x_shift, y_shift)

Purpose: Move the x and y position of all shapes that have been tagged with the tag argument

Arguments:
  • shape (Shape or Tag): The shape in question.
  • x_shift (int; optional): amount to move in the x direction
  • y_shift (int; optional): amount to move in the y direction
def portion(shape, start=0, end=0.5):
444def portion(shape, start=0, end=0.5):
445    """
446    Purpose: Take a slice or portion of some already created shape.
447
448    Args:
449        shape (`Shape` or Tag): The shape to take a portion of
450        start (`float`): A number between 0 and 1 representing where to start the slice.
451        end (`float`): A number between 0 and 1 representing where to end the slice.
452
453    For example, taking a portion from 0 to 0.5 of a circle would result in a semi-circle.
454
455    Note: this function is experimental. It might produce unexpected results!
456    """
457    all_shapes = _a_canvas.find_withtag(shape)
458
459    for a_shape in all_shapes
460        coords = _a_canvas.coords(a_shape)
461
462        start_coord = floor(start * len(coords))
463        if start_coord % 2 == 1
464            start_coord = start_coord - 1  # need to start with an x,y pair
465        end_coord = floor(end * len(coords))
466        if end_coord % 2 == 1
467            end_coord = end_coord - 1  # need to end with an x,y pair
468
469        # slice is up to not including so get the last x,y pair
470        new_coords = coords[start_coord  end_coord + 2]
471
472        # loop shape back in on itself
473        new_coords.append(new_coords[0])
474        new_coords.append(new_coords[1])
475
476        # set the coordinates:
477        _a_canvas.coords(a_shape, new_coords)

Purpose: Take a slice or portion of some already created shape.

Arguments:
  • shape (Shape or Tag): The shape to take a portion of
  • start (float): A number between 0 and 1 representing where to start the slice.
  • end (float): A number between 0 and 1 representing where to end the slice.

For example, taking a portion from 0 to 0.5 of a circle would result in a semi-circle.

Note: this function is experimental. It might produce unexpected results!

def put_in_front(shape):
480def put_in_front(shape):
481    """
482    A function that "raises" a shape to the "top" of the screen."
483
484    Args:
485        shape (`Shape` or Tag): The shape in question.
486    """
487    _a_canvas.tag_raise(shape)

A function that "raises" a shape to the "top" of the screen."

Arguments:
  • shape (Shape or Tag): The shape in question.
def put_in_back(shape):
490def put_in_back(shape):
491    """
492    A function that "lowers" a shape to the "bottom" of the screen."
493
494    Args:
495        shape (`Shape` or Tag): The shape in question.
496    """
497    _a_canvas.tag_lower(shape)

A function that "lowers" a shape to the "bottom" of the screen."

Arguments:
  • shape (Shape or Tag): The shape in question.
def align(shape1, shape2, via="middle", offset_x=0, offset_y=0):
521def align(shape1, shape2, via="middle", offset_x=0, offset_y=0):
522    """
523    A reporter function that aligns `shape1` with `shape2`. It does this by moving `shape1` to align with
524    whatever property of `shape2` is selected with the `via` input.
525
526    Args:
527        shape1 (`Shape` or Tag): The first shape to use.
528        shape2 (`Shape` or Tag): The second shape to use.
529        via (`str`): Has to be one of, the following options: `"center"` (horizontal center),
530            `"middle"` (vertical center), `"top"`, `"bottom"`, `"left"`, or `"right"`
531        offset_x (`int`): How much to shift in the x-axis after alignment
532        offset_y (`int`): How much to shift in the y-axis after alignment
533
534    Returns:
535        `Shape`: The modified shape1.
536    """
537    via_options = ["center", "middle", "top", "bottom", "left", "right"]
538    if via not in via_options
539        raise ValueError(
540            "The via input must be one of "
541            + (via_options)
542            + " but instead we found "
543            + (via)
544        )
545
546    outline1 = _get_outline(shape1)
547    outline2 = _get_outline(shape2)
548
549    if via == "center"
550        _a_canvas.move(
551            shape1, (outline2["center"][0] - outline1["center"][0]) + offset_x, offset_y
552        )
553
554    elif via == "middle"
555        _a_canvas.move(
556            shape1, offset_x, (outline2["center"][1] - outline1["center"][1]) + offset_y
557        )
558
559    elif via == "top"
560        _a_canvas.move(shape1, offset_x, (outline2["top"] - outline1["top"]) + offset_y)
561
562    elif via == "bottom"
563        _a_canvas.move(
564            shape1, offset_x, (outline2["bottom"] - outline1["bottom"]) + offset_y
565        )
566
567    elif via == "left"
568        _a_canvas.move(
569            shape1, (outline2["left"] - outline1["left"]) + offset_x, offset_y
570        )
571
572    elif via == "right"
573        _a_canvas.move(
574            shape1, (outline2["right"] - outline1["right"]) + offset_x, offset_y
575        )
576
577    return shape1

A reporter function that aligns shape1 with shape2. It does this by moving shape1 to align with whatever property of shape2 is selected with the via input.

Arguments:
  • shape1 (Shape or Tag): The first shape to use.
  • shape2 (Shape or Tag): The second shape to use.
  • via (str): Has to be one of, the following options: "center" (horizontal center), "middle" (vertical center), "top", "bottom", "left", or "right"
  • offset_x (int): How much to shift in the x-axis after alignment
  • offset_y (int): How much to shift in the y-axis after alignment
Returns:

Shape: The modified shape1.

def overlay(shape1, shape2, offset_x=0, offset_y=0):
580def overlay(shape1, shape2, offset_x=0, offset_y=0):
581    """
582    A reporter function that overlays shape1 onto shape2. It does this by moving shape 1"s center
583    to shape 2"s center, and then applying any specified offset.
584    Args:
585        shape1 (`Shape` or Tag): The first shape to use.
586        shape2 (`Shape` or Tag): The second shape to use.
587        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
588        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
589
590    Returns:
591        `Shape`: The modified shape1.
592    """
593    center1 = get_center(shape1)
594    center2 = get_center(shape2)
595    _a_canvas.move(
596        shape1,
597        (center2[0] - center1[0]) + offset_x,
598        (center2[1] - center1[1]) + offset_y,
599    )
600    _a_canvas.tag_raise(shape1, shape2)
601    return shape1

A reporter function that overlays shape1 onto shape2. It does this by moving shape 1's center to shape 2's center, and then applying any specified offset.

Arguments:
  • shape1 (Shape or Tag): The first shape to use.
  • shape2 (Shape or Tag): The second shape to use.
  • offset_x (int): How much to shift shape 2 in the x-direction after centering it.
  • offset_y (int): How much to shift shape 2 in the x-direction after centering it.
Returns:

Shape: The modified shape1.

def underlay(shape1, shape2, offset_x=0, offset_y=0):
604def underlay(shape1, shape2, offset_x=0, offset_y=0):
605    """
606    A reporter function that underlays shape1 beneath shape2. It does this by moving shape 1"s center
607    to shape 2"s center, and then applying any specified offset.
608    Args:
609        shape1 (`Shape` or Tag): The first shape to use.
610        shape2 (`Shape` or Tag): The second shape to use.
611        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
612        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
613
614    Returns:
615        `Shape`: The modified shape1.
616    """
617    center1 = get_center(shape1)
618    center2 = get_center(shape2)
619    _a_canvas.move(
620        shape1,
621        (center2[0] - center1[0]) + offset_x,
622        (center2[1] - center1[1]) + offset_y,
623    )
624    _a_canvas.tag_lower(shape1, shape2)
625    return shape1

A reporter function that underlays shape1 beneath shape2. It does this by moving shape 1's center to shape 2's center, and then applying any specified offset.

Arguments:
  • shape1 (Shape or Tag): The first shape to use.
  • shape2 (Shape or Tag): The second shape to use.
  • offset_x (int): How much to shift shape 2 in the x-direction after centering it.
  • offset_y (int): How much to shift shape 2 in the x-direction after centering it.
Returns:

Shape: The modified shape1.

def above(shape1, shape2, offset_x=0, offset_y=0):
628def above(shape1, shape2, offset_x=0, offset_y=0):
629    """
630    A reporter function that places shape1 above shape2 (vertically). It does this by moving shape 1"s center
631    to shape 2"s center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
632    specified offset.
633
634    Args:
635        shape1 (`Shape` or Tag): The first shape to use.
636        shape2 (`Shape` or Tag): The second shape to use.
637        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
638        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
639
640    Returns:
641        `Shape`: The modified shape1.
642    """
643    overlay(shape1, shape2)
644    _a_canvas.move(
645        shape1,
646        0 + offset_x,
647        -1 * (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
648    )
649    return shape1

A reporter function that places shape1 above shape2 (vertically). It does this by moving shape 1's center to shape 2's center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any specified offset.

Arguments:
  • shape1 (Shape or Tag): The first shape to use.
  • shape2 (Shape or Tag): The second shape to use.
  • offset_x (int): How much to shift shape 2 in the x-direction after moving it.
  • offset_y (int): How much to shift shape 2 in the x-direction after moving it.
Returns:

Shape: The modified shape1.

def beside(shape1, shape2, offset_x=0, offset_y=0):
652def beside(shape1, shape2, offset_x=0, offset_y=0):
653    """
654    A reporter function that places shape1 beside shape2 (horizontally). It does this by moving shape 1"s center
655    to shape 2"s center, moving shape 1 in the x-direction the exact width of shape 2, and then applying any
656    specified offset.
657
658    Args:
659        shape1 (`Shape` or Tag): The first shape to use.
660        shape2 (`Shape` or Tag): The second shape to use.
661        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
662        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
663
664    Returns:
665        `Shape`: The modified shape1.
666    """
667    overlay(shape1, shape2)
668    _a_canvas.move(
669        shape1,
670        (get_width(shape2) + get_width(shape1)) / 2 + offset_x,
671        0 + offset_y,
672    )
673    return shape1

A reporter function that places shape1 beside shape2 (horizontally). It does this by moving shape 1's center to shape 2's center, moving shape 1 in the x-direction the exact width of shape 2, and then applying any specified offset.

Arguments:
  • shape1 (Shape or Tag): The first shape to use.
  • shape2 (Shape or Tag): The second shape to use.
  • offset_x (int): How much to shift shape 2 in the x-direction after moving it.
  • offset_y (int): How much to shift shape 2 in the x-direction after moving it.
Returns:

Shape: The modified shape1.

def below(shape1, shape2, offset_x=0, offset_y=0):
676def below(shape1, shape2, offset_x=0, offset_y=0):
677    """
678    A reporter function that places shape1 below shape2 (vertically). It does this by moving shape 1"s center
679    to shape 2"s center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
680    specified offset.
681
682    Args:
683        shape1 (`Shape` or Tag): The first shape to use.
684        shape2 (`Shape` or Tag): The second shape to use.
685        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
686        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
687
688    Returns:
689        `Shape`: The modified shape1.
690    """
691    overlay(shape1, shape2)
692    _a_canvas.move(
693        shape1,
694        0 + offset_x,
695        (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
696    )
697    return shape1

A reporter function that places shape1 below shape2 (vertically). It does this by moving shape 1's center to shape 2's center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any specified offset.

Arguments:
  • shape1 (Shape or Tag): The first shape to use.
  • shape2 (Shape or Tag): The second shape to use.
  • offset_x (int): How much to shift shape 2 in the x-direction after moving it.
  • offset_y (int): How much to shift shape 2 in the x-direction after moving it.
Returns:

Shape: The modified shape1.

def delete(shape):
700def delete(shape):
701    """
702    A function that deletes a shape from our screen.
703
704    Args:
705        shape (`Shape` or Tag): The shape to delete.
706    """
707    _a_canvas.delete(shape)

A function that deletes a shape from our screen.

Arguments:
  • shape (Shape or Tag): The shape to delete.
def clear_window(keep_grid=True):
710def clear_window(keep_grid=True):
711    """
712    A function that deletes everything from the window.
713
714    Args:
715        keep_grid (`bool`): Whether or not to keep the grid.
716    """
717    all_shapes = _a_canvas.find_all()
718
719    for shape in all_shapes
720        tags = _a_canvas.gettags(shape)
721        if "grid" in tags and keep_grid
722            continue
723        _a_canvas.delete(shape)

A function that deletes everything from the window.

Arguments:
  • keep_grid (bool): Whether or not to keep the grid.
def duplicate(shape, color=None):
726def duplicate(shape, color=None):
727    """
728    A reporter function that perfectly copies a shape and returns that copy.
729
730    Args:
731        shape (`Shape` or Tag): The shape to duplicate.
732        color (`str`): A new color to use with the duplicated shape.
733
734    Returns:
735        `Shape`: The new duplicated shape.
736    """
737    shape_type = _a_canvas.type(shape)
738    shape_config = _a_canvas.itemconfig(shape)
739    shape_coords = _a_canvas.coords(shape)
740    the_copy = None
741    if shape_type == "polygon"
742        new_config = {key shape_config[key][-1] for key in shape_config.keys()}
743        if color != None
744            new_config["fill"] = color
745        the_copy = _a_canvas.create_polygon(shape_coords, new_config)
746        return the_copy

A reporter function that perfectly copies a shape and returns that copy.

Arguments:
  • shape (Shape or Tag): The shape to duplicate.
  • color (str): A new color to use with the duplicated shape.
Returns:

Shape: The new duplicated shape.

def mirror(shape):
749def mirror(shape):
750    """
751    A function that takes a shape and flips it across its vertical
752    axis, returning the modified shape.
753
754    Args:
755        shape (`Shape` or Tag): The shape in question.
756
757    """
758    center = get_center(shape)[0]
759    shape_ids = _a_canvas.find_withtag(shape)
760    for shape_id in shape_ids
761        flipped_coordinates = []
762        shape_coords = _a_canvas.coords(shape_id)
763        counter = 0
764        for num in shape_coords
765            if counter % 2 == 0
766                if num < center
767                    flipped_coordinates.append(num + 2 * (center - num))
768                elif num > center
769                    flipped_coordinates.append(num - 2 * (num - center))
770                else
771                    flipped_coordinates.append(num)
772            else
773                flipped_coordinates.append(num)
774            counter += 1
775        _a_canvas.coords(shape_id, flipped_coordinates)

A function that takes a shape and flips it across its vertical axis, returning the modified shape.

Arguments:
  • shape (Shape or Tag): The shape in question.
def rotate(shape, degrees=5, origin=None):
778def rotate(shape, degrees=5, origin=None):
779    """
780    A reporter function that takes a shape and rotates it by a specified amount around a specified point.
781    It does this by interpolating a polygon around the shape and calculating the shifts of individual
782    points on the edge of the polygon.
783
784    Args:
785        shape (`Shape` or Tag): The shape to rotate.
786        degrees (`int`): The number of degrees to rotate the shape.
787        origin (`tuple`): An `(x,y)` coordinate about which to perform the rotation. Defaults to the center
788            of the given shape.
789
790    Returns:
791        `Shape`: The modified shape.
792    """
793    if origin is None
794        origin = get_center(shape)
795
796    theta = radians(degrees)
797    ox, oy = origin
798
799    all_shapes = _a_canvas.find_withtag(shape)
800
801    for a_shape in all_shapes
802        coords = _a_canvas.coords(a_shape)
803        # update coordinates:
804        for i in range(0, len(coords), 2):
805            px, py = coords[i], coords[i + 1]
806            qx = cos(theta) * (px - ox) - sin(theta) * (py - oy) + ox
807            qy = sin(theta) * (px - ox) + cos(theta) * (py - oy) + oy
808            coords[i] = qx
809            coords[i + 1] = qy
810        # set the coordinates:
811        _a_canvas.coords(a_shape, coords)
812
813    return shape

A reporter function that takes a shape and rotates it by a specified amount around a specified point. It does this by interpolating a polygon around the shape and calculating the shifts of individual points on the edge of the polygon.

Arguments:
  • shape (Shape or Tag): The shape to rotate.
  • degrees (int): The number of degrees to rotate the shape.
  • origin (tuple): An (x,y) coordinate about which to perform the rotation. Defaults to the center of the given shape.
Returns:

Shape: The modified shape.

def distance(point1, point2):
816def distance(point1, point2):
817    """
818    A reporter function calculates the distance between two `(x, y)` coordinates.
819
820    Args:
821        point1 (`tuple`): The first `(x, y)` coordinate.
822        point2 (`tuple`): The second `(x, y)` coordinate.
823
824    Returns:
825         A `float` representing the distance between the two points.
826    """
827    return sqrt(((point1[0] - point2[0])  2) + ((point1[1] - point2[1])  2))

A reporter function calculates the distance between two (x, y) coordinates.

Arguments:
  • point1 (tuple): The first (x, y) coordinate.
  • point2 (tuple): The second (x, y) coordinate.
Returns:

A float representing the distance between the two points.

def scale(shape, x_scale=1.0, y_scale=1.0):
830def scale(shape, x_scale=1.0, y_scale=1.0):
831    """
832    A function that takes a given `Shape` or tag and scales it on either/both the x and y-axis.
833
834    The two optional inputs accept floats between 0.0 and 1.0. Values greater than 1 will cause
835    the shape to grow along that access. Values less than 1.0 will cause the shape to shrink.
836
837    Args:
838        shape (`Shape` or Tag): The shape or tag to re-fill.
839        x_scale (`float`): How much to scale in the x-axis.
840        y_scale (`float`): How much to scale in the y-axis.
841    """
842    ids = _a_canvas.find_withtag(shape)
843
844    coord = get_center(shape)
845
846    for i in ids
847        _a_canvas.scale(i, coord[0], coord[1], x_scale, y_scale)

A function that takes a given Shape or tag and scales it on either/both the x and y-axis.

The two optional inputs accept floats between 0.0 and 1.0. Values greater than 1 will cause the shape to grow along that access. Values less than 1.0 will cause the shape to shrink.

Arguments:
  • shape (Shape or Tag): The shape or tag to re-fill.
  • x_scale (float): How much to scale in the x-axis.
  • y_scale (float): How much to scale in the y-axis.
def update_color(shape, color):
850def update_color(shape, color):
851    """
852    Change the fill color of a tagged object.
853
854    Args:
855        shape (`Shape` or Tag): The shape or tag to re-fill.
856        color (`str`): A color name or hex code to re-fill with.
857    """
858    ids = _a_canvas.find_withtag(shape)
859    for id in ids
860        _a_canvas.itemconfig(id, fill=color)

Change the fill color of a tagged object.

Arguments:
  • shape (Shape or Tag): The shape or tag to re-fill.
  • color (str): A color name or hex code to re-fill with.
def interpolate_colors(color1, color2, frac):
863def interpolate_colors(color1, color2, frac):
864    """
865    A reporter function that generates a new color between two given colors.
866    Args:
867        color1 (`str`): The path of the file to wrap
868        color2 (`str`): The path of the file to wrap
869        frac (`float`): What fraction of each color to take. An input of 0 returns
870            color1, an input of 1 returns color2, an input of 0.5 returns a color
871            perfectly between the two.
872
873    Returns:
874         A color (as a hex `str`) to be used elsewhere
875    """
876    if "#" not in color1
877        color1 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color1)))
878    else
879        color1 = _tupelize_color(color1)
880    if "#" not in color2
881        color2 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color2)))
882    else
883        color2 = _tupelize_color(color2)
884    return _interpolate_tuple(color1, color2, frac)

A reporter function that generates a new color between two given colors.

Arguments:
  • color1 (str): The path of the file to wrap
  • color2 (str): The path of the file to wrap
  • frac (float): What fraction of each color to take. An input of 0 returns color1, an input of 1 returns color2, an input of 0.5 returns a color perfectly between the two.
Returns:

A color (as a hex str) to be used elsewhere

def get_colors(shape_or_shapes):
887def get_colors(shape_or_shapes):
888    """
889    A reporter function that returns all the colors associated with a tag or list of tags.
890
891    Args:
892        shape_or_shapes (`str`/`Shape` or `List`): the shape/tag or list of shapes/tags you"d like to find the colors of
893
894    Returns:
895        A `List` containing all unique colors associated with that tag(s)
896    """
897    all_shapes = []
898    if not isinstance(shape_or_shapes, ):
899        shape_or_shapes = [shape_or_shapes]
900    for shape in shape_or_shapes
901        all_shapes += _a_canvas.find_withtag(shape)
902
903    all_colors = []
904    for shape in all_shapes
905        color = _a_canvas.itemcget(shape, "fill")
906        if color not in all_colors
907            all_colors.append(color)
908
909    return all_colors

A reporter function that returns all the colors associated with a tag or list of tags.

Arguments:
  • shape_or_shapes (str/Shape or List): the shape/tag or list of shapes/tags you'd like to find the colors of
Returns:

A List containing all unique colors associated with that tag(s)

def get_center(shape):
912def get_center(shape):
913    """
914    A reporter function calculates the a coordinate at the center of some shape.
915
916    Args:
917        shape (`Shape` or Tag): The shape in question.
918
919    Returns:
920         A `tuple` representing center of the given shape.
921    """
922    bbox = _safe_bbox(shape)
923
924    if bbox is None
925        raise Exception(
926            f"We couldn"t find the shape with id/tag {shape}. Make sure it exists!"
927        )
928
929    return (((bbox[2] + bbox[0]) / 2), ((bbox[1] + bbox[3]) / 2))

A reporter function calculates the a coordinate at the center of some shape.

Arguments:
  • shape (Shape or Tag): The shape in question.
Returns:

A tuple representing center of the given shape.

def get_top(shape):
932def get_top(shape):
933    """
934    A reporter function calculates the minimum y-value of a given shape (since the y-axis is flipped).
935
936    Args:
937        shape (`Shape` or Tag): The shape in question.
938
939    Returns:
940         A `int` representing the minimum y-coordinate of the shape.
941    """
942    bbox = _safe_bbox(shape)
943    return bbox[1]

A reporter function calculates the minimum y-value of a given shape (since the y-axis is flipped).

Arguments:
  • shape (Shape or Tag): The shape in question.
Returns:

A int representing the minimum y-coordinate of the shape.

def get_bottom(shape):
946def get_bottom(shape):
947    """
948    A reporter function calculates the maximum y-value of a given shape (since the y-axis is flipped).
949
950    Args:
951        shape (`Shape` or Tag): The shape in question.
952
953    Returns:
954         A `int` representing the maximum y-coordinate of the shape.
955    """
956    bbox = _safe_bbox(shape)
957    return bbox[3]

A reporter function calculates the maximum y-value of a given shape (since the y-axis is flipped).

Arguments:
  • shape (Shape or Tag): The shape in question.
Returns:

A int representing the maximum y-coordinate of the shape.

def get_left(shape):
960def get_left(shape):
961    """
962    A reporter function calculates the minimum x-value of a given shape.
963
964    Args:
965        shape (`Shape` or Tag): The shape in question.
966
967    Returns:
968         A `int` representing the minimum x-coordinate of the shape.
969    """
970    bbox = _safe_bbox(shape)
971    return bbox[0]

A reporter function calculates the minimum x-value of a given shape.

Arguments:
  • shape (Shape or Tag): The shape in question.
Returns:

A int representing the minimum x-coordinate of the shape.

def get_right(shape):
974def get_right(shape):
975    """
976    A reporter function calculates the maximum x-value of a given shape.
977
978    Args:
979        shape (`Shape` or Tag): The shape in question.
980
981    Returns:
982         A `int` representing the maximum x-coordinate of the shape.
983    """
984    bbox = _safe_bbox(shape)
985    return bbox[2]

A reporter function calculates the maximum x-value of a given shape.

Arguments:
  • shape (Shape or Tag): The shape in question.
Returns:

A int representing the maximum x-coordinate of the shape.

def get_height(shape):
988def get_height(shape):
989    """
990    A reporter function calculates the height of some given shape.
991
992    Args:
993        shape (`Shape` or Tag): The shape in question.
994
995    Returns:
996         A `int` representing the height of the shape.
997    """
998    bbox = _safe_bbox(shape)
999    return bbox[3] - bbox[1] - 1

A reporter function calculates the height of some given shape.

Arguments:
  • shape (Shape or Tag): The shape in question.
Returns:

A int representing the height of the shape.

def get_width(shape):
1002def get_width(shape):
1003    """
1004    A reporter function calculates the width of some given shape.
1005
1006    Args:
1007        shape (`Shape` or Tag): The shape in question.
1008
1009    Returns:
1010         An `int` representing width of the shape.
1011    """
1012    bbox = _safe_bbox(shape)
1013    return bbox[2] - bbox[0] - 1

A reporter function calculates the width of some given shape.

Arguments:
  • shape (Shape or Tag): The shape in question.
Returns:

An int representing width of the shape.

def make_grid(c, w, h, interval=100):
1016def make_grid(c, w, h, interval=100):
1017    """
1018    Draws a grid on a screen with intervals of 100.
1019
1020    Args:
1021        w (`int`): The width of the grid to draw
1022        h (`int`): The height of the grid to draw
1023    """
1024    # Creates all vertical lines at intervals of 100
1025    for i in range(0, w, interval):
1026        _a_canvas.create_line(i, 0, i, h, tag="grid", fill="black")
1027    # Creates all horizontal lines at intervals of 100
1028    for i in range(0, h, interval):
1029        _a_canvas.create_line(0, i, w, i, tag="grid", fill="black")
1030    # Creates axis labels
1031    offset = 2
1032    for y in range(0, h, interval):
1033        for x in range(0, w, interval):
1034            _a_canvas.create_oval(
1035                x - offset, y - offset, x + offset, y + offset, fill="black", tag="grid"
1036            )
1037            _a_canvas.create_text(
1038                x + offset,
1039                y + offset,
1040                text="({0}, {1})".format(x, y),
1041                anchor="nw",
1042                font=("Purisa", 8),
1043                fill="black",
1044                tag="grid",
1045            )

Draws a grid on a screen with intervals of 100.

Arguments:
  • w (int): The width of the grid to draw
  • h (int): The height of the grid to draw
def does_tag_exist(tag):
1102def does_tag_exist(tag):
1103    """
1104    Returns `True` if a given tag exists otherwise returns `False`.
1105
1106    Args:
1107        `tag` (`str`): [Required] The tag of the object to lookup.
1108
1109    """
1110    result = _a_canvas.find_withtag(tag)
1111
1112    if result
1113        return True
1114    else
1115        return False

Returns True if a given tag exists otherwise returns False.

Arguments:
  • tag (str): [Required] The tag of the object to lookup.
def random_color():
1118def random_color():
1119    """
1120    Returns a random color as a `string` to be used.
1121    It does not accept any inputs.
1122    """
1123    r = lambda randint(0, 255)
1124    return "#%02X%02X%02X" % (r(), r(), r())

Returns a random color as a string to be used. It does not accept any inputs.

def setup_shapes(title, background="white", grid=True, width=600, height=600):
1130def setup_shapes(title, background="white", grid=True, width=600, height=600):
1131    """
1132    A static function that sets up the pop-up window. DO NOT USE THIS FUNCTION.
1133    """
1134    global _a_canvas
1135    gui = Tk()
1136    gui.title(title)
1137    _a_canvas = Canvas(gui, background=background, width=width, height=width)
1138    _a_canvas.pack()
1139    if grid
1140        make_grid(_a_canvas, width, height)
1141    return _a_canvas

A static function that sets up the pop-up window. DO NOT USE THIS FUNCTION.