cs110_p1

   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_VERSION = "2025.1.1"
   9
  10## 2025.1.1
  11# Feature: adds ability to fill the screen with the window
  12# Feature: grid - add show_label param
  13
  14###################################################################
  15### IGNORE EVERYTHING THAT STARTS WITH A _
  16from random import randint
  17from math import sqrt, pi, radians, sin, cos, floor
  18from time import sleep
  19from tkinter import Tk, Canvas
  20
  21
  22__docformat__ = "google"
  23
  24_a_canvas = None
  25_resize_enabled = False
  26
  27
  28Shape_Drawing_Functions = ""
  29
  30
  31def arc(points=[], width=5, color="hot pink", line_steps=15, tag="", ):
  32    """
  33    A reporter function that draws an arc ("curve") given a list of points.
  34    Args:
  35        points (`list`): The points outlining the curve; this should be a list of tuples (coordinates).
  36            Make sure to give it at least 3 (x,y) coordinates that aren"t a straight line!
  37        color (`str`): What color to make the shape.
  38        tag (`str`): The tag to assign to the shape.
  39
  40    Returns:
  41        `Shape`: The arc that was created.
  42    """
  43    return _a_canvas.create_line(
  44        points,
  45        width=width,
  46        fill=color,
  47        splinesteps=line_steps,
  48        smooth=True,
  49        tags=tag,
  50        ,
  51    )
  52
  53
  54def car(top_left=(0, 0), size=100, body_color="#3D9970", wheel_color="black", tag=""):
  55    """
  56    Draws a cool car.
  57
  58    Args:
  59        top_left (`tuple`): A coordinate at which to draw the car.
  60        body_color (`str`): Color to make the body of the car.
  61        wheel_color (`str`): Color to make the wheel of the car.
  62        tag (`str`): The tag to assign to the shape.
  63    """
  64    x, y = top_left
  65    rectangle((x + 5 * size / 10, y), size, size / 10 * 4, color=body_color, tag=tag)
  66    rectangle(
  67        (x, y + size - 7 * size / 10),
  68        size * 2,
  69        size / 10 * 4.5,
  70        color=body_color,
  71        tag=tag,
  72    )
  73    circle(
  74        (x + 5 * size / 10, y + size - size / 5), size / 5, color=wheel_color, tag=tag
  75    )
  76    circle(
  77        (x + 15 * size / 10, y + size - size / 5), size / 5, color=wheel_color, tag=tag
  78    )
  79
  80
  81def circle(center=(0, 0), radius=25, color="hot pink", outline="", tag="", ):
  82    """
  83    A reporter function that draws a circle.
  84    Args:
  85        center (`tuple`): A coordinate representing the center of the shape.
  86        radius (`int`): Specifies the circle"s radius.
  87        color (`str`): What color to draw the shape.
  88        outline (`str`): What color should the border of the shape be.
  89        tag (`str`): The tag to assign to the shape.
  90
  91    Returns:
  92        `Shape`: The circle that was created.
  93    """
  94    return oval(
  95        center=center, radius_x=radius, radius_y=radius, color=color, tag=tag, 
  96    )
  97
  98
  99def cloud(center=(0, 0), size=30, color="white", tag=""):
 100    """
 101    Reporter function that draws a cloud to the screen.
 102    Args:
 103        center (`tuple`): the point on which to center the cloud
 104        size (`int`): how big (roughly) the cloud is drawn
 105        color (`str`): which determines the color of the cloud
 106        tag (`str`): to give the cloud a name
 107
 108    Returns:
 109        `Shape`: The cloud that was created.
 110    """
 111    for i in range(10):
 112        x_offset = randint((-1 * size * 1.333), (size * 1.333))
 113        y_offset = randint(0, (size * 0.667))
 114        circle(
 115            center=(center[0] + x_offset, center[1] + y_offset),
 116            radius=randint((size * 0.667), (size * 1.667)),
 117            color=color,
 118            tag=tag,
 119        )
 120    return tag
 121
 122
 123def diamond(
 124    center=(0, 0), width=25, height=50, color="hot pink", outline="", tag="", 
 125):
 126    """
 127    A reporter function that draws a rectangle.
 128    Args:
 129        center (`tuple`): A coordinate representing the center of the shape.
 130        width (`int`): How wide to draw the shape.
 131        height (`int`): How tall to draw the shape.
 132        color (`str`): What color to draw the shape.
 133        outline (`str`): What color should the border of the shape be.
 134        tag (`str`): The tag to assign to the shape.
 135
 136    Returns:
 137        `Shape`: The shape that was created.
 138    """
 139    point_0 = (center[0] - width / 2, center[1])
 140    point_1 = (center[0], center[1] - height / 2)
 141    point_2 = (center[0] + width / 2, center[1])
 142    point_3 = (center[0], center[1] + height / 2)
 143    return _a_canvas.create_polygon(
 144        point_0,
 145        point_1,
 146        point_2,
 147        point_3,
 148        fill=_safe_color(color),
 149        tags=tag,
 150        outline=outline,
 151        ,
 152    )
 153
 154
 155def grid(width=None, height=None, interval=100, show_labels=True):
 156    """
 157    Draws a grid on a screen with intervals of 100.
 158
 159    Args:
 160        width (`int`): The width of the grid to draw (defaults to the whole window)
 161        height (`int`): The height of the grid to draw (defaults to the whole window)
 162        interval (`int`): The interval to draw the grid on.
 163        show_labels (`bool`): Whether or not to show coordinate labels.
 164
 165    """
 166
 167    if width is None
 168        width = get_window_width()
 169
 170    if height is None
 171        height = get_window_height()
 172
 173    # Creates all vertical lines at intervals of 100
 174    for i in range(0, width, interval):
 175        _a_canvas.create_line(i, 0, i, height, tag="grid", fill="black")
 176    # Creates all horizontal lines at intervals of 100
 177    for i in range(0, height, interval):
 178        _a_canvas.create_line(0, i, width, i, tag="grid", fill="black")
 179
 180    if show_labels
 181        # Creates axis labels
 182        offset = 2
 183        for y in range(0, height, interval):
 184            for x in range(0, width, interval):
 185                _a_canvas.create_oval(
 186                    x - offset,
 187                    y - offset,
 188                    x + offset,
 189                    y + offset,
 190                    fill="black",
 191                    tag="grid",
 192                )
 193                _a_canvas.create_text(
 194                    x + offset,
 195                    y + offset,
 196                    text="({0}, {1})".format(x, y),
 197                    anchor="nw",
 198                    font=("Purisa", 8),
 199                    fill="black",
 200                    tag="grid",
 201                )
 202
 203
 204_cache = []
 205
 206
 207def image(image_path, position=(200, 200), rotation=None, scale=None, tag="", ):
 208    """
 209    Draws a given image on the screen. NOTE: Requires the `pillow` package to be installed - contact
 210    Prof. Bain or post on edSTEM if you"d like more details!
 211
 212    Args:
 213        image_path (`str`): Location of the image file on your computer.
 214        position (`tuple`): A coordinate at which to render the image.
 215        rotation (`int`): A number of degrees to rotate the given image.
 216        scale (`int`): A scaling factor to multiply the image size by.
 217        tag (`str`): A string representing the "name" fo this shape.
 218    """
 219    # import PIL libraries
 220    from PIL import Image, ImageTk
 221
 222    anchor = "nw"
 223
 224    import os
 225
 226    # 1. create PIL image and apply any image transformations:
 227    dir_path = os.path.dirname(os.path.realpath(__file__))
 228    image_path = os.path.join(dir_path, image_path)
 229    pil_image = Image.open(image_path)
 230    if scale
 231        size = (round(pil_image.size[0] * scale), round(pil_image.size[1] * scale))
 232        pil_image = pil_image.resize(size)
 233    if rotation
 234        pil_image = pil_image.rotate(rotation)  # note: returns a copy
 235
 236    # 2. convert to tkinter-compatible image format:
 237    tkinter_image = ImageTk.PhotoImage(pil_image)
 238    _cache.append(
 239        tkinter_image
 240    )  # workaround for known tkinter bug: http://effbot.org/pyfaq/why-do-my-tkinter-images-not-appear.htm
 241
 242    # 3. draw image on canvas:
 243    _a_canvas.create_image(
 244        *position, image=tkinter_image, anchor=anchor, tags=tag, 
 245    )
 246
 247
 248def line(points=[], curvy=False, color="hot pink", tag="", ):
 249    """
 250    A reporter function that draws a line given a list of points.
 251    Args:
 252        points (`list`): The points that define the line; this should be a list of tuples (coordinates).
 253        curvy (`bool`): Makes a curvy line instead.
 254        color (`str`): What color to make the shape.
 255        tag (`str`): The tag to assign to the shape.
 256
 257    Returns:
 258        `Shape`: The line that was created.
 259    """
 260    return _a_canvas.create_line(points, fill=color, smooth=curvy, tags=tag, )
 261
 262
 263def oval(
 264    center=(0, 0),
 265    radius_x=25,
 266    radius_y=50,
 267    color="hot pink",
 268    outline="",
 269    tag="",
 270    ,
 271):
 272    """
 273    A reporter function that draws an oval.
 274    Args:
 275        center (`tuple`): A coordinate representing the center of the shape.
 276        radius_x (`int`): Specifies the oval"s radius on the x-axis.
 277        radius_y (`int`): Specifies the oval"s radius on the y-axis.
 278        color (`str`): What color to draw the shape.
 279        outline (`str`): What color should the border of the shape be.
 280        tag (`str`): The tag to assign to the shape.
 281
 282    Returns:
 283        `Shape`: The oval that was created.
 284    """
 285    x = center[0]
 286    y = center[1]
 287    x0, y0, x1, y1 = (x - radius_x, y - radius_y, x + radius_x, y + radius_y)
 288    steps = 100
 289    # major and minor axes
 290    a = (x1 - x0) / 2.0
 291    b = (y1 - y0) / 2.0
 292    # center
 293    xc = x0 + a
 294    yc = y0 + b
 295    point_list = []
 296    # create the oval as a list of points
 297    for i in range(steps):
 298        # Calculate the angle for this step
 299        theta = (pi * 2) * (float(i) / steps)
 300        x = a * cos(theta)
 301        y = b * sin(theta)
 302        point_list.append(round(x + xc))
 303        point_list.append(round(y + yc))
 304
 305    return _a_canvas.create_polygon(
 306        point_list, fill=_safe_color(color), tags=tag, 
 307    )
 308
 309
 310def pixel_art(top_left, artwork, palette, pixel=10, tag=""):
 311    """
 312    Draws a pixel art design!
 313
 314    Args:
 315        top_left (`tuple`): the top left coordinate of the pixel art
 316        artwork (sequence of sequences): the art to draw
 317        palette (sequence): the palette of colors to use for each different square
 318        pixel (`int`, optional): how big each individual pixel should be
 319        tag (`str`, optional): the tag to assign to every square in the row
 320
 321    Note: this doesn"t return anything so make sure to use a tag if you want to animate / modify.
 322    """
 323    x = top_left[0]
 324    y = top_left[1]
 325    for row in artwork
 326        # draw each row at the specified (x, y) position:
 327        _draw_row(row, (x, y), colors=palette, pixel=pixel, tag=tag)
 328        # ...and don"t forget to shift the y-value down by the proper
 329        #  amount so that the next row won"t draw on top of the first one:
 330        y += pixel
 331
 332
 333def polygon(points=[], color="hot pink", outline="", tag="", ):
 334    """
 335    A reporter function that draws a polygon given a list of points.
 336    Args:
 337        points (`list`): The points outlining the polygon; this should be a list of tuples (coordinates).
 338            defaults to an empty list.
 339        outline (`str`): What color should the border of the shape be.
 340        color (`str`): What color to make the shape.
 341
 342    Returns:
 343        `Shape`: The polygon that was created.
 344    """
 345    return _a_canvas.create_polygon(points, fill=_safe_color(color), tags=tag, )
 346
 347
 348def rectangle(
 349    top_left=(0, 0), width=25, height=50, color="hot pink", outline="", tag="", 
 350):
 351    """
 352    A reporter function that draws a rectangle.
 353    Args:
 354        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
 355        width (`int`): How wide to draw the shape.
 356        height (`int`): How tall to draw the shape.
 357        color (`str`): What color to draw the shape.
 358        outline (`str`): What color should the border of the shape be.
 359        tag (`str`): The tag to assign to the shape.
 360
 361    Returns:
 362        `Shape`: The rectangle that was created.
 363    """
 364    point_0 = top_left
 365    point_1 = (top_left[0] + width, top_left[1])
 366    point_2 = (top_left[0] + width, top_left[1] + height)
 367    point_3 = (top_left[0], top_left[1] + height)
 368    return _a_canvas.create_polygon(
 369        point_0, point_1, point_2, point_3, fill=_safe_color(color), tags=tag, 
 370    )
 371
 372
 373def spiral(
 374    center=(0, 0), width=100, roughness=0.01, start=0, spirals=5, line_width=1, 
 375):
 376    """
 377    A reporter function that draws a spiral.
 378    Args:
 379        center (`tuple`): A coordinate representing the center of the shape.
 380        width (`int`): Specifies the total width of the spiral.
 381        roughness (`float`): Controls how spiral-y the shape is (lower is less spiral-y)
 382        start (`int`): Where on the spiral to start drawing.
 383        spirals (`int`): How many loops to draw.
 384        line_width (`int`): How wide for the line to be drawn.
 385        tag (`str`): The tag to assign to the shape.
 386
 387    Returns:
 388        `Shape`: The spiral that was created.
 389    """
 390    theta = 0.0
 391    r = start
 392    all_points = []
 393    prev_pos = _polar_to_cartesian(r, theta)
 394    distance = width / 4 / pi / spirals
 395    all_points.append((prev_pos[0] + center[0], prev_pos[1] + center[1]))
 396    while theta < 2 * spirals * pi
 397        theta += roughness
 398        r = start + distance * theta
 399        pos = _polar_to_cartesian(r, theta)
 400        all_points.append((pos[0] + center[0], pos[1] + center[1]))
 401
 402    return arc(points=all_points, width=line_width, )
 403
 404
 405def square(top_left=(0, 0), size=25, color="hot pink", outline="", tag="", ):
 406    """
 407    A reporter function that draws a square.
 408    Args:
 409        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
 410        size (`int`): How big to draw the shape.
 411        color (`str`): What color to draw the shape.
 412        outline (`str`): What color should the border of the shape be.
 413        tag (`str`): The tag to assign to the shape.
 414
 415    Returns:
 416        `Shape`: The square that was created.
 417    """
 418    return rectangle(
 419        top_left=top_left, width=size, height=size, color=color, tag=tag, 
 420    )
 421
 422
 423def star(
 424    center=(0, 0),
 425    radius=50,
 426    color="hot pink",
 427    outer_radius=75,
 428    points=5,
 429    outline="",
 430    tag="",
 431    ,
 432):
 433    """
 434    A reporter function that draws a star.
 435    Args:
 436        center (`tuple`): A coordinate representing the center of the shape.
 437        radius (`int`): Specifies the radius of the inside part of the star.
 438        color (`str`): Specifies the color of the star.
 439        outer_radius (`int`): Specifies the radius of the outside part of the star.
 440        points (`int`): Specifies the number of points for the star.
 441        outline (`str`): What color should the border of the shape be.
 442        tag (`str`): The tag to assign to the shape.
 443
 444    Returns:
 445        `Shape`: The star that was created.
 446    """
 447    arc_segment = 360 / points
 448    vertices = []
 449    for i in range(points):
 450        inner_point = (
 451            radius * cos(radians(arc_segment * i)) + center[0],
 452            -1 * radius * sin(radians(arc_segment * i)) + center[1],
 453        )
 454        vertices.append(inner_point)
 455        outer_point = (
 456            outer_radius * cos(radians(arc_segment * i + arc_segment / 2)) + center[0],
 457            -1 * outer_radius * sin(radians(arc_segment * i + arc_segment / 2))
 458            + center[1],
 459        )
 460        vertices.append(outer_point)
 461    return polygon(vertices, color=color, tag=tag, )
 462
 463
 464def text(
 465    top_left=(0, 0), text="", font=("Purisa", 32), color="black", tag="", 
 466):
 467    """
 468    A reporter function that draws text to the screen
 469    Args:
 470        top_left (`tuple`): coordinate pair to specify the location.
 471        text (`str`): What text to draw.
 472        font (`tuple`): A tuple where the first element is a string for the font name and the second is an
 473           int with the font size.
 474        color (`str`): What color should the text be.
 475        tag (`str`): The name to tag this thing with.
 476
 477    Returns:
 478        `Shape`: The text that was created.
 479    """
 480    return _a_canvas.create_text(
 481        top_left, text=text, font=font, fill=color, tags=tag, 
 482    )
 483
 484
 485def triangle(
 486    bottom_center=(0, 0),
 487    width=25,
 488    top_shift=0,
 489    height=0,
 490    color="hot pink",
 491    outline="",
 492    tag="",
 493    ,
 494):
 495    """
 496    A reporter function that draws a triangle.
 497    Args:
 498        bottom_center (`tuple`): A coordinate representing the bottom center of the shape.
 499        width (`int`): Specifies the width of the base of the triangle.
 500        top_shift (`int`): Specifies the how far to the left or right to shift the top of
 501            the triangle from the bottom center.
 502        height (`int`): Specifies the triangle"s height.
 503        color (`str`): What color to draw the shape.
 504        outline (`str`): What color should the border of the shape be.
 505        tag (`str`): The tag to assign to the shape.
 506
 507    Returns:
 508        `Shape`: The triangle that was created.
 509    """
 510    if height == 0
 511        height = width * sqrt(3) / 2
 512    point_0 = (bottom_center[0] - width / 2, bottom_center[1])
 513    point_1 = (bottom_center[0] + width / 2, bottom_center[1])
 514    point_2 = (bottom_center[0] + top_shift, bottom_center[1] - height)
 515
 516    return _a_canvas.create_polygon(
 517        point_0, point_1, point_2, fill=_safe_color(color), tags=tag, 
 518    )
 519
 520
 521def wedge(
 522    center=(0, 0), radius=25, angle=180, color="hot pink", outline="", tag="", 
 523):
 524    """
 525    A reporter function that draws a circle.
 526    Args:
 527        center (`tuple`): A coordinate representing the center of the shape.
 528        radius (`int`): Specifies the circle"s radius.
 529        angle (`int`): A number between 0 and 360 that specifies how much of the circle to draw.
 530        color (`str`): What color to draw the shape.
 531        outline (`str`): What color should the border of the shape be.
 532        tag (`str`): The tag to assign to the shape.
 533
 534    Returns:
 535        `Shape`: The wedge that was created.
 536    """
 537    point_list = [center[0], center[1]]
 538    for i in range(0, 0 + angle):
 539        x1 = center[0] + radius * cos(radians(i))
 540        point_list.append(x1)
 541        y1 = center[1] + radius * sin(radians(i))
 542        point_list.append(y1)
 543
 544    point_list.append(center[0])
 545    point_list.append(center[1])
 546
 547    return _a_canvas.create_polygon(
 548        point_list, fill=_safe_color(color), outline=outline, tags=tag, 
 549    )
 550
 551
 552Shape_Modifier_Functions = ""
 553
 554
 555def above(shape1, shape2, offset_x=0, offset_y=0):
 556    """
 557    A reporter function that places shape1 above shape2 (vertically). It does this by moving shape 1"s center
 558    to shape 2"s center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
 559    specified offset.
 560
 561    Args:
 562        shape1 (`Shape` or Tag): The first shape to use.
 563        shape2 (`Shape` or Tag): The second shape to use.
 564        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
 565        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
 566
 567    Returns:
 568        `Shape`: The modified shape1.
 569    """
 570    overlay(shape1, shape2)
 571    _a_canvas.move(
 572        shape1,
 573        0 + offset_x,
 574        -1 * (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
 575    )
 576    return shape1
 577
 578
 579def align(shape1, shape2, via="middle", offset_x=0, offset_y=0):
 580    """
 581    A reporter function that aligns `shape1` with `shape2`. It does this by moving `shape1` to align with
 582    whatever property of `shape2` is selected with the `via` input.
 583
 584    Args:
 585        shape1 (`Shape` or Tag): The first shape to use.
 586        shape2 (`Shape` or Tag): The second shape to use.
 587        via (`str`): Has to be one of, the following options: `"center"` (horizontal center),
 588            `"middle"` (vertical center), `"top"`, `"bottom"`, `"left"`, or `"right"`
 589        offset_x (`int`): How much to shift in the x-axis after alignment
 590        offset_y (`int`): How much to shift in the y-axis after alignment
 591
 592    Returns:
 593        `Shape`: The modified shape1.
 594    """
 595    via_options = ["center", "middle", "top", "bottom", "left", "right"]
 596    if via not in via_options
 597        raise ValueError(
 598            "The via input must be one of "
 599            + (via_options)
 600            + " but instead we found "
 601            + (via)
 602        )
 603
 604    outline1 = _get_outline(shape1)
 605    outline2 = _get_outline(shape2)
 606
 607    if via == "center"
 608        _a_canvas.move(
 609            shape1, (outline2["center"][0] - outline1["center"][0]) + offset_x, offset_y
 610        )
 611
 612    elif via == "middle"
 613        _a_canvas.move(
 614            shape1, offset_x, (outline2["center"][1] - outline1["center"][1]) + offset_y
 615        )
 616
 617    elif via == "top"
 618        _a_canvas.move(shape1, offset_x, (outline2["top"] - outline1["top"]) + offset_y)
 619
 620    elif via == "bottom"
 621        _a_canvas.move(
 622            shape1, offset_x, (outline2["bottom"] - outline1["bottom"]) + offset_y
 623        )
 624
 625    elif via == "left"
 626        _a_canvas.move(
 627            shape1, (outline2["left"] - outline1["left"]) + offset_x, offset_y
 628        )
 629
 630    elif via == "right"
 631        _a_canvas.move(
 632            shape1, (outline2["right"] - outline1["right"]) + offset_x, offset_y
 633        )
 634
 635    return shape1
 636
 637
 638def beside(shape1, shape2, offset_x=0, offset_y=0):
 639    """
 640    A reporter function that places shape1 beside shape2 (horizontally). It does this by moving shape 1"s center
 641    to shape 2"s center, moving shape 1 in the x-direction the exact width of shape 2, and then applying any
 642    specified offset.
 643
 644    Args:
 645        shape1 (`Shape` or Tag): The first shape to use.
 646        shape2 (`Shape` or Tag): The second shape to use.
 647        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
 648        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
 649
 650    Returns:
 651        `Shape`: The modified shape1.
 652    """
 653    overlay(shape1, shape2)
 654    _a_canvas.move(
 655        shape1,
 656        (get_width(shape2) + get_width(shape1)) / 2 + offset_x,
 657        0 + offset_y,
 658    )
 659    return shape1
 660
 661
 662def below(shape1, shape2, offset_x=0, offset_y=0):
 663    """
 664    A reporter function that places shape1 below shape2 (vertically). It does this by moving shape 1"s center
 665    to shape 2"s center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
 666    specified offset.
 667
 668    Args:
 669        shape1 (`Shape` or Tag): The first shape to use.
 670        shape2 (`Shape` or Tag): The second shape to use.
 671        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
 672        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
 673
 674    Returns:
 675        `Shape`: The modified shape1.
 676    """
 677    overlay(shape1, shape2)
 678    _a_canvas.move(
 679        shape1,
 680        0 + offset_x,
 681        (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
 682    )
 683    return shape1
 684
 685
 686def change_color(shape, color):
 687    """
 688    Change the fill color of a tagged object.
 689
 690    Args:
 691        shape (`Shape` or Tag): The shape or tag to re-fill.
 692        color (`str`): A color name or hex code to re-fill with.
 693    """
 694    ids = _a_canvas.find_withtag(shape)
 695    for id in ids
 696        _a_canvas.itemconfig(id, fill=color)
 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 assign_tag(shape, tag):
 710    """
 711    A function that assigns a `Shape` or other tagged object a new tag. This will
 712    overwrite any existing tag that matches the provided `tag` argument. This means that if you have
 713    a shape with multiple tags, _this function will only overwrite that one tag_. You would need to run
 714    the function multiple times to rewrite the remaining tags.
 715
 716    Args:
 717        shape (`Shape` or Tag): The shape to which you"d like to assign a new tag
 718        tag (`str`): A new valid tag for this shape.
 719
 720    """
 721    ids = _a_canvas.find_withtag(shape)
 722    for id in ids
 723        the_tags = (_a_canvas.gettags(id))        
 724        if shape in the_tags # if it has a tag replace it
 725            index = the_tags.index(shape)
 726            the_tags[index] = tag
 727        else # otherwise it didn"t have a tag
 728            the_tags.append(tag)
 729        _a_canvas.itemconfig(id, tags=the_tags)
 730            
 731
 732def duplicate(shape, color=None):
 733    """
 734    A reporter function that perfectly copies a shape and returns that copy.
 735
 736    Args:
 737        shape (`Shape` or Tag): The shape to duplicate.
 738        color (`str`): A new color to use with the duplicated shape.
 739
 740    Returns:
 741        `Shape`: The new duplicated shape.
 742    """
 743    shape_type = _a_canvas.type(shape)
 744    shape_config = _a_canvas.itemconfig(shape)
 745    shape_coords = _a_canvas.coords(shape)
 746    the_copy = None
 747    if shape_type == "polygon"
 748        new_config = {key shape_config[key][-1] for key in shape_config.keys()}
 749        if color != None
 750            new_config["fill"] = color
 751        the_copy = _a_canvas.create_polygon(shape_coords, new_config)
 752        return the_copy
 753
 754
 755def mirror(shape):
 756    """
 757    A function that takes a shape and flips it across its vertical
 758    axis, returning the modified shape.
 759
 760    Args:
 761        shape (`Shape` or Tag): The shape in question.
 762
 763    """
 764    center = get_center(shape)[0]
 765    shape_ids = _a_canvas.find_withtag(shape)
 766    for shape_id in shape_ids
 767        flipped_coordinates = []
 768        shape_coords = _a_canvas.coords(shape_id)
 769        counter = 0
 770        for num in shape_coords
 771            if counter % 2 == 0
 772                if num < center
 773                    flipped_coordinates.append(num + 2 * (center - num))
 774                elif num > center
 775                    flipped_coordinates.append(num - 2 * (num - center))
 776                else
 777                    flipped_coordinates.append(num)
 778            else
 779                flipped_coordinates.append(num)
 780            counter += 1
 781        _a_canvas.coords(shape_id, flipped_coordinates)
 782
 783
 784def move(shape, x_shift=0, y_shift=0):
 785    """
 786    Purpose: Move the x and y position of all shapes that have been tagged
 787    with the tag argument
 788
 789    Args:
 790        shape (`Shape` or Tag): The shape in question.
 791        x_shift (`int`; optional): amount to move in the x direction
 792        y_shift (`int`; optional): amount to move in the y direction
 793    """
 794    shape_ids = _a_canvas.find_withtag(shape)
 795    for id in shape_ids
 796        _a_canvas.move(id, x_shift, y_shift)
 797
 798
 799def move_to(tag, to, anchor="center"):
 800    """
 801    Move the given tagged item to a particular `point` maintaining some `anchor`.
 802    Note: this is NOT the same as the `move` function which moves an object by a specific amount.
 803
 804    Args:
 805        tag (Shape or `str`): the shape (or shapes) to move
 806        to (`tuple`): the `(x, y)` coordinate to which you wish to move the tagged object
 807        anchor (`str`): which point on the shape do you want to move toward the given tuple. You can
 808            use either `"center"` (default), `"top_left"`, `"top_right"`, `"bottom_left"`, or `"bottom_right"`.
 809    """
 810    anchor_options = ["center", "top_left", "top_right", "bottom_left", "bottom_right"]
 811    if anchor not in anchor_options
 812        raise ValueError(
 813            "The anchor input must be one of "
 814            + (anchor_options)
 815            + " but instead we found "
 816            + (anchor)
 817        )
 818
 819    outline = _get_outline(tag)
 820    delta_x = 0
 821    delta_y = 0
 822
 823    if anchor == "top_left"
 824        delta_x = to[0] - outline["left"]
 825        delta_y = to[1] - outline["top"]
 826    elif anchor == "top_right"
 827        delta_x = to[0] - outline["right"]
 828        delta_y = to[1] - outline["top"]
 829    elif anchor == "bottom_right"
 830        delta_x = to[0] - outline["right"]
 831        delta_y = to[1] - outline["bottom"]
 832    elif anchor == "bottom_left"
 833        delta_x = to[0] - outline["left"]
 834        delta_y = to[1] - outline["bottom"]
 835    elif anchor == "center"
 836        delta_x = to[0] - outline["center"][0]
 837        delta_y = to[1] - outline["center"][1]
 838
 839    _a_canvas.move(tag, delta_x, delta_y)
 840
 841
 842def overlay(shape1, shape2, offset_x=0, offset_y=0):
 843    """
 844    A reporter function that overlays shape1 onto shape2. It does this by moving shape 1"s center
 845    to shape 2"s center, and then applying any specified offset.
 846    Args:
 847        shape1 (`Shape` or Tag): The first shape to use.
 848        shape2 (`Shape` or Tag): The second shape to use.
 849        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
 850        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
 851
 852    Returns:
 853        `Shape`: The modified shape1.
 854    """
 855    center1 = get_center(shape1)
 856    center2 = get_center(shape2)
 857    _a_canvas.move(
 858        shape1,
 859        (center2[0] - center1[0]) + offset_x,
 860        (center2[1] - center1[1]) + offset_y,
 861    )
 862    _a_canvas.tag_raise(shape1, shape2)
 863    return shape1
 864
 865
 866def portion(shape, start=0, end=0.5):
 867    """
 868    Purpose: Take a slice or portion of some already created shape.
 869
 870    Args:
 871        shape (`Shape` or Tag): The shape to take a portion of
 872        start (`float`): A number between 0 and 1 representing where to start the slice.
 873        end (`float`): A number between 0 and 1 representing where to end the slice.
 874
 875    For example, taking a portion from 0 to 0.5 of a circle would result in a semi-circle.
 876
 877    Note: this function is experimental. It might produce unexpected results!
 878    """
 879    all_shapes = _a_canvas.find_withtag(shape)
 880
 881    for a_shape in all_shapes
 882        coords = _a_canvas.coords(a_shape)
 883
 884        start_coord = floor(start * len(coords))
 885        if start_coord % 2 == 1
 886            start_coord = start_coord - 1  # need to start with an x,y pair
 887        end_coord = floor(end * len(coords))
 888        if end_coord % 2 == 1
 889            end_coord = end_coord - 1  # need to end with an x,y pair
 890
 891        # slice is up to not including so get the last x,y pair
 892        new_coords = coords[start_coord  end_coord + 2]
 893
 894        # loop shape back in on itself
 895        new_coords.append(new_coords[0])
 896        new_coords.append(new_coords[1])
 897
 898        # set the coordinates:
 899        _a_canvas.coords(a_shape, new_coords)
 900
 901
 902def put_in_back(shape):
 903    """
 904    A function that "lowers" a shape to the "bottom" of the screen."
 905
 906    Args:
 907        shape (`Shape` or Tag): The shape in question.
 908    """
 909    _a_canvas.tag_lower(shape)
 910
 911
 912def put_in_front(shape):
 913    """
 914    A function that "raises" a shape to the "top" of the screen."
 915
 916    Args:
 917        shape (`Shape` or Tag): The shape in question.
 918    """
 919    _a_canvas.tag_raise(shape)
 920
 921
 922def rotate(shape, degrees=5, origin=None):
 923    """
 924    A reporter function that takes a shape and rotates it by a specified amount around a specified point.
 925    It does this by interpolating a polygon around the shape and calculating the shifts of individual
 926    points on the edge of the polygon.
 927
 928    Args:
 929        shape (`Shape` or Tag): The shape to rotate.
 930        degrees (`int`): The number of degrees to rotate the shape.
 931        origin (`tuple`): An `(x,y)` coordinate about which to perform the rotation. Defaults to the center
 932            of the given shape.
 933
 934    Returns:
 935        `Shape`: The modified shape.
 936    """
 937    if origin is None
 938        origin = get_center(shape)
 939
 940    theta = radians(degrees)
 941    ox, oy = origin
 942
 943    all_shapes = _a_canvas.find_withtag(shape)
 944
 945    for a_shape in all_shapes
 946        coords = _a_canvas.coords(a_shape)
 947        # update coordinates:
 948        for i in range(0, len(coords), 2):
 949            px, py = coords[i], coords[i + 1]
 950            qx = cos(theta) * (px - ox) - sin(theta) * (py - oy) + ox
 951            qy = sin(theta) * (px - ox) + cos(theta) * (py - oy) + oy
 952            coords[i] = qx
 953            coords[i + 1] = qy
 954        # set the coordinates:
 955        _a_canvas.coords(a_shape, coords)
 956
 957    return shape
 958
 959
 960def scale(shape, x_scale=1.0, y_scale=1.0):
 961    """
 962    A function that takes a given `Shape` or tag and scales it on either/both the x and y-axis.
 963
 964    The two optional inputs accept floats between 0.0 and 1.0. Values greater than 1 will cause
 965    the shape to grow along that access. Values less than 1.0 will cause the shape to shrink.
 966
 967    Args:
 968        shape (`Shape` or Tag): The shape or tag to re-fill.
 969        x_scale (`float`): How much to scale in the x-axis.
 970        y_scale (`float`): How much to scale in the y-axis.
 971    """
 972    ids = _a_canvas.find_withtag(shape)
 973
 974    coord = get_center(shape)
 975
 976    for i in ids
 977        _a_canvas.scale(i, coord[0], coord[1], x_scale, y_scale)
 978
 979
 980def underlay(shape1, shape2, offset_x=0, offset_y=0):
 981    """
 982    A reporter function that underlays shape1 beneath shape2. It does this by moving shape 1"s center
 983    to shape 2"s center, and then applying any specified offset.
 984    Args:
 985        shape1 (`Shape` or Tag): The first shape to use.
 986        shape2 (`Shape` or Tag): The second shape to use.
 987        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
 988        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
 989
 990    Returns:
 991        `Shape`: The modified shape1.
 992    """
 993    center1 = get_center(shape1)
 994    center2 = get_center(shape2)
 995    _a_canvas.move(
 996        shape1,
 997        (center2[0] - center1[0]) + offset_x,
 998        (center2[1] - center1[1]) + offset_y,
 999    )
1000    _a_canvas.tag_lower(shape1, shape2)
1001    return shape1
1002
1003
1004Utility_Functions = ""
1005
1006
1007def clear_window(keep_grid=True):
1008    """
1009    A function that deletes everything from the window.
1010
1011    Args:
1012        keep_grid (`bool`): Whether or not to keep the grid.
1013    """
1014    all_shapes = _a_canvas.find_all()
1015
1016    for shape in all_shapes
1017        tags = _a_canvas.gettags(shape)
1018        if "grid" in tags and keep_grid
1019            continue
1020        _a_canvas.delete(shape)
1021
1022    global _resize_enabled
1023    _resize_enabled = True
1024
1025
1026def distance(point1, point2):
1027    """
1028    A reporter function calculates the distance between two `(x, y)` coordinates.
1029
1030    Args:
1031        point1 (`tuple`): The first `(x, y)` coordinate.
1032        point2 (`tuple`): The second `(x, y)` coordinate.
1033
1034    Returns:
1035         A `float` representing the distance between the two points.
1036    """
1037    return sqrt(((point1[0] - point2[0])  2) + ((point1[1] - point2[1])  2))
1038
1039
1040def does_tag_exist(tag):
1041    """
1042    Returns `True` if a given tag exists otherwise returns `False`.
1043
1044    Args:
1045        `tag` (`str`): [Required] The tag of the object to lookup.
1046
1047    """
1048    result = _a_canvas.find_withtag(tag)
1049
1050    if result
1051        return True
1052    else
1053        return False
1054
1055
1056def get_bottom(shape):
1057    """
1058    A reporter function calculates the maximum y-value of a given shape (since the y-axis is flipped).
1059
1060    Args:
1061        shape (`Shape` or Tag): The shape in question.
1062
1063    Returns:
1064         A `int` representing the maximum y-coordinate of the shape.
1065    """
1066    bbox = _safe_bbox(shape)
1067    return bbox[3]
1068
1069
1070def get_center(shape):
1071    """
1072    A reporter function calculates the a coordinate at the center of some shape.
1073
1074    Args:
1075        shape (`Shape` or Tag): The shape in question.
1076
1077    Returns:
1078         A `tuple` representing center of the given shape.
1079    """
1080    bbox = _safe_bbox(shape)
1081
1082    if bbox is None
1083        raise Exception(
1084            f"We couldn"t find the shape with id/tag {shape}. Make sure it exists!"
1085        )
1086
1087    return (((bbox[2] + bbox[0]) / 2), ((bbox[1] + bbox[3]) / 2))
1088
1089
1090def get_colors(shape_or_shapes):
1091    """
1092    A reporter function that returns all the colors associated with a tag or list of tags.
1093
1094    Args:
1095        shape_or_shapes (`str`/`Shape` or `List`): the shape/tag or list of shapes/tags you"d like to find the colors of
1096
1097    Returns:
1098        A `List` containing all unique colors associated with that tag(s)
1099    """
1100    all_shapes = []
1101    if not isinstance(shape_or_shapes, ):
1102        shape_or_shapes = [shape_or_shapes]
1103    for shape in shape_or_shapes
1104        all_shapes += _a_canvas.find_withtag(shape)
1105
1106    all_colors = []
1107    for shape in all_shapes
1108        color = _a_canvas.itemcget(shape, "fill")
1109        if color not in all_colors
1110            all_colors.append(color)
1111
1112    return all_colors
1113
1114
1115def get_height(shape):
1116    """
1117    A reporter function calculates the height of some given shape.
1118
1119    Args:
1120        shape (`Shape` or Tag): The shape in question.
1121
1122    Returns:
1123         A `int` representing the height of the shape.
1124    """
1125    bbox = _safe_bbox(shape)
1126    return bbox[3] - bbox[1] - 1
1127
1128
1129def get_left(shape):
1130    """
1131    A reporter function calculates the minimum x-value of a given shape.
1132
1133    Args:
1134        shape (`Shape` or Tag): The shape in question.
1135
1136    Returns:
1137         A `int` representing the minimum x-coordinate of the shape.
1138    """
1139    bbox = _safe_bbox(shape)
1140    return bbox[0]
1141
1142
1143def get_right(shape):
1144    """
1145    A reporter function calculates the maximum x-value of a given shape.
1146
1147    Args:
1148        shape (`Shape` or Tag): The shape in question.
1149
1150    Returns:
1151         A `int` representing the maximum x-coordinate of the shape.
1152    """
1153    bbox = _safe_bbox(shape)
1154    return bbox[2]
1155
1156
1157def get_tag_from_event(event, precision=25):
1158    """
1159    Tries to return a tag of an object at a given mouse-event.
1160
1161    Args:
1162        event (`Event`): Must be a mouse event otherwise we"ll give back an error.
1163        precision (`int`): How precise in number of pixels does a user have be in order to "select" an object
1164
1165    Returns a blank string `""` if no shapes are found closer than `precision`.
1166    """
1167
1168    if (event.type) not in [4, 6]:
1169        raise Exception(f"Received an event that isn"t a mouse event: {event}")
1170
1171    try
1172        x = event.x
1173        y = event.y
1174        shape_id = _a_canvas.find_closest(x, y)  # get the top shape
1175        if shape_id and distance(get_center(shape_id), (x, y)) < precision
1176            tags = _a_canvas.gettags(shape_id)
1177            if len(tags) > 0
1178                return tags[0]
1179        return ""
1180
1181    except
1182        raise Exception(
1183            "No tag found! Maybe you passed us an event that isn"t a mouse event?"
1184        )
1185
1186
1187def get_top(shape):
1188    """
1189    A reporter function calculates the minimum y-value of a given shape (since the y-axis is flipped).
1190
1191    Args:
1192        shape (`Shape` or Tag): The shape in question.
1193
1194    Returns:
1195         A `int` representing the minimum y-coordinate of the shape.
1196    """
1197    bbox = _safe_bbox(shape)
1198    return bbox[1]
1199
1200
1201def get_width(shape):
1202    """
1203    A reporter function calculates the width of some given shape.
1204
1205    Args:
1206        shape (`Shape` or Tag): The shape in question.
1207
1208    Returns:
1209         An `int` representing width of the shape.
1210    """
1211    bbox = _safe_bbox(shape)
1212    return bbox[2] - bbox[0] - 1
1213
1214
1215def get_window_height():
1216    """
1217    A reporter function that returns the current height of the window.
1218
1219    Returns:
1220         An `int` representing height of the window.
1221    """
1222    return _a_canvas.winfo_height()
1223
1224
1225def get_window_width():
1226    """
1227    A reporter function that returns the current width of the window.
1228
1229    Returns:
1230         An `int` representing width of the window.
1231    """
1232    return _a_canvas.winfo_width()
1233
1234
1235def interpolate_colors(color1, color2, frac):
1236    """
1237    A reporter function that generates a new color between two given colors.
1238    Args:
1239        color1 (`str`): The path of the file to wrap
1240        color2 (`str`): The path of the file to wrap
1241        frac (`float`): What fraction of each color to take. An input of 0 returns
1242            color1, an input of 1 returns color2, an input of 0.5 returns a color
1243            perfectly between the two.
1244
1245    Returns:
1246         A color (as a hex `str`) to be used elsewhere
1247    """
1248    if "#" not in color1
1249        color1 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color1)))
1250    else
1251        color1 = _tupelize_color(color1)
1252    if "#" not in color2
1253        color2 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color2)))
1254    else
1255        color2 = _tupelize_color(color2)
1256    return _interpolate_tuple(color1, color2, frac)
1257
1258
1259def random_color():
1260    """
1261    Returns a random color as a `string` to be used.
1262    It does not accept any inputs.
1263    """
1264    r = lambda randint(0, 255)
1265    return "#%02X%02X%02X" % (r(), r(), r())
1266
1267
1268def listen_for(event_str, handler_function, override=False):
1269    """
1270    Sets up a listener for a given event on our window.
1271
1272    Args:
1273        event_str (`str`): The magic string that represents this event in the window
1274        handler_function (`func`): The name (not a string though) of the function you want called when the event his heard
1275        override (`bool`): Only use this if you speak to Prof. Bain and he recommends it.
1276
1277    The supported events are:
1278      * `"LEFT-CLICK"`: Left mouse click
1279      * `"RIGHT-CLICK"`: Right mouse click
1280      * `"ALT-CLICK"`: If you"re using a PC, this event might instead work for Right Click
1281      * `"LEFT-DRAG"`: Left mouse clicked and dragged on the screen
1282      * `"RIGHT-DRAG"`: Right mouse clicked and dragged on the screen
1283      * `"ALT-DRAG"`: For PCs, this event might instead work for RIGHT-DRAG
1284      * `"DOUBLE-LEFT"`: Left mouse double click
1285      * `"DOUBLE-RIGHT"`: Right mouse double click
1286      * `"DOUBLE-ALT"`: For PCs, this event might instead work for DOUBLE-RIGHT
1287      * `"KEY"`: The catch-all event for Keyboard presses
1288    """
1289
1290    event_translator = {
1291        "LEFT-CLICK" "<Button-1>",
1292        "RIGHT-CLICK" "<Button-2>",
1293        "ALT-CLICK" "<Button-3>",
1294        "LEFT-DRAG" "<B1-Motion>",
1295        "RIGHT-DRAG" "<B2-Motion>",
1296        "ALT-DRAG" "<B3-Motion>",
1297        "DOUBLE-LEFT" "<Double-Button-1>",
1298        "DOUBLE-RIGHT" "<Double-Button-2>",
1299        "DOUBLE-ALT" "<Double-Button-3>",
1300        "KEY" "<Key>",
1301    }
1302
1303    if event_str not in event_translator and not override
1304        raise (
1305            TypeError(
1306                f"The event you entered, {event_str}, isn"t supported. Here are the supported events: {[i for i in event_translator]}"
1307            )
1308        )
1309
1310    event = event_translator[event_str]
1311    
1312    listen_for.tracker.add(event_str)
1313
1314    _a_canvas.bind(event, handler_function)
1315
1316
1317listen_for.tracker = set()
1318
1319def setup_shapes(title, background="white", include_grid=True, width=600, height=600):
1320    """
1321    A static function that sets up the pop-up window. You can specify the size of the window here.
1322
1323    However, you should NOT add any calls to this function unless Prof. Bain specifically tells you to!
1324
1325    Args:
1326        title (`str`): The title of the pop-up window.
1327        background (`str`): A valid color as a string to be used as the background color.
1328        include_grid (`bool`): Whether or not to draw the grid.
1329        width (`int` or `str`): How wide the window should appear (advanced: use the string "FULLWIDTH" to maximize the width)
1330        height (`int` or `str`): How wide the window should appear (advanced: use the string "FULLHEIGHT" to maximize the width)
1331    """
1332
1333    global _a_canvas
1334    gui = Tk()
1335    gui.title(title)
1336
1337    if width == "FULLWIDTH"
1338        width = gui.winfo_screenwidth()
1339
1340    if height == "FULLHEIGHT"
1341        height = gui.winfo_screenheight()
1342
1343    _a_canvas = Canvas(gui, background=background, width=width, height=height)
1344    _a_canvas.pack()
1345    if include_grid
1346        grid(width, height)
1347
1348    _a_canvas.focus_set()
1349    return _a_canvas
1350
1351
1352def update():
1353    """
1354    A static function that sets up the pop-up window. DO NOT USE THIS FUNCTION unless Prof. Bain explicitly says to use it.
1355    """
1356    _a_canvas.update()
1357
1358
1359def _safe_color(color ):
1360    color = color.strip()
1361    # Could also do some other verifications here...
1362    return color
1363
1364
1365def _tupelize_color(color):
1366    R = (color[13], 16)
1367    G = (color[35], 16)
1368    B = (color[57], 16)
1369    return R, G, B
1370
1371
1372def _interpolate_tuple(startcolor, goalcolor, frac):
1373    R = startcolor[0]
1374    G = startcolor[1]
1375    B = startcolor[2]
1376
1377    targetR = goalcolor[0]
1378    targetG = goalcolor[1]
1379    targetB = goalcolor[2]
1380
1381    DiffR = targetR - R
1382    DiffG = targetG - G
1383    DiffB = targetB - B
1384
1385    iR = (R + (DiffR * frac))
1386    iG = (G + (DiffG * frac))
1387    iB = (B + (DiffB * frac))
1388
1389    hR = hex(iR).replace("0x", "")
1390    hG = hex(iG).replace("0x", "")
1391    hB = hex(iB).replace("0x", "")
1392
1393    if len(hR) == 1
1394        hR = "0" + hR
1395    if len(hB) == 1
1396        hB = "0" + hB
1397    if len(hG) == 1
1398        hG = "0" + hG
1399
1400    color = ("#" + hR + hG + hB).upper()
1401
1402    return color
1403
1404
1405def _polar_to_cartesian(r, theta):
1406    return (r * cos(theta)), (r * sin(theta))
1407
1408
1409def _get_outline(shape):
1410    """
1411    A reporter function that takes in a shape and calls the various helper functions to generate
1412    a sort of "summary" of that particular shape and returns it in the form of a dictionary.
1413
1414    Args:
1415        shape (`Shape` or Tag): The shape in question.
1416
1417    Returns:
1418        a `Dictionary` with the various properties of the shape
1419    """
1420
1421    return {
1422        "center" get_center(shape),
1423        "left" get_left(shape),
1424        "right" get_right(shape),
1425        "top" get_top(shape),
1426        "bottom" get_bottom(shape),
1427    }
1428
1429
1430def _draw_row(row, top_left, colors, pixel=25, tag=""):
1431    """
1432    Draws a single row of some pixel art.
1433
1434    Args:
1435        row (sequence): the row of artwork to draw
1436        top_left (`tuple`): the top left coordinate of the pixel art
1437        color (sequence): the colors to use for each square
1438        pixel (`int`, optional): how big each individual pixel should be
1439        tag (`str`, optional): the tag to assign to every square in the row
1440    """
1441    x = top_left[0]
1442    y = top_left[1]
1443    for cell in row
1444        if cell != 0
1445            square((x, y), pixel, color=colors[cell], tag=tag)
1446        x += pixel
1447
1448
1449def _safe_bbox(shape):
1450    try
1451        bbox = _a_canvas.bbox(shape)
1452        if bbox is None
1453            Exception(
1454                f"We couldn"t find the shape with tag/id: {shape}. Make sure this shape exists!"
1455            )
1456        return bbox
1457    except
1458        raise Exception(
1459            f"We couldn"t find the shape with tag/id: {shape}. Make sure this shape exists!"
1460        )
Shape_Drawing_Functions = ""
def arc( points=[], width=5, color="hot pink", line_steps=15, tag="",):
32def arc(points=[], width=5, color="hot pink", line_steps=15, tag="", ):
33    """
34    A reporter function that draws an arc ("curve") given a list of points.
35    Args:
36        points (`list`): The points outlining the curve; this should be a list of tuples (coordinates).
37            Make sure to give it at least 3 (x,y) coordinates that aren"t a straight line!
38        color (`str`): What color to make the shape.
39        tag (`str`): The tag to assign to the shape.
40
41    Returns:
42        `Shape`: The arc that was created.
43    """
44    return _a_canvas.create_line(
45        points,
46        width=width,
47        fill=color,
48        splinesteps=line_steps,
49        smooth=True,
50        tags=tag,
51        ,
52    )

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 car( top_left=(0, 0), size=100, body_color="#3D9970", wheel_color="black", tag=""):
55def car(top_left=(0, 0), size=100, body_color="#3D9970", wheel_color="black", tag=""):
56    """
57    Draws a cool car.
58
59    Args:
60        top_left (`tuple`): A coordinate at which to draw the car.
61        body_color (`str`): Color to make the body of the car.
62        wheel_color (`str`): Color to make the wheel of the car.
63        tag (`str`): The tag to assign to the shape.
64    """
65    x, y = top_left
66    rectangle((x + 5 * size / 10, y), size, size / 10 * 4, color=body_color, tag=tag)
67    rectangle(
68        (x, y + size - 7 * size / 10),
69        size * 2,
70        size / 10 * 4.5,
71        color=body_color,
72        tag=tag,
73    )
74    circle(
75        (x + 5 * size / 10, y + size - size / 5), size / 5, color=wheel_color, tag=tag
76    )
77    circle(
78        (x + 15 * size / 10, y + size - size / 5), size / 5, color=wheel_color, tag=tag
79    )

Draws a cool car.

Arguments:
  • top_left (tuple): A coordinate at which to draw the car.
  • body_color (str): Color to make the body of the car.
  • wheel_color (str): Color to make the wheel of the car.
  • tag (str): The tag to assign to the shape.
def circle( center=(0, 0), radius=25, color="hot pink", outline="", tag="",):
82def circle(center=(0, 0), radius=25, color="hot pink", outline="", tag="", ):
83    """
84    A reporter function that draws a circle.
85    Args:
86        center (`tuple`): A coordinate representing the center of the shape.
87        radius (`int`): Specifies the circle"s radius.
88        color (`str`): What color to draw the shape.
89        outline (`str`): What color should the border of the shape be.
90        tag (`str`): The tag to assign to the shape.
91
92    Returns:
93        `Shape`: The circle that was created.
94    """
95    return oval(
96        center=center, radius_x=radius, radius_y=radius, color=color, tag=tag, 
97    )

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 cloud(center=(0, 0), size=30, color="white", tag=""):
100def cloud(center=(0, 0), size=30, color="white", tag=""):
101    """
102    Reporter function that draws a cloud to the screen.
103    Args:
104        center (`tuple`): the point on which to center the cloud
105        size (`int`): how big (roughly) the cloud is drawn
106        color (`str`): which determines the color of the cloud
107        tag (`str`): to give the cloud a name
108
109    Returns:
110        `Shape`: The cloud that was created.
111    """
112    for i in range(10):
113        x_offset = randint((-1 * size * 1.333), (size * 1.333))
114        y_offset = randint(0, (size * 0.667))
115        circle(
116            center=(center[0] + x_offset, center[1] + y_offset),
117            radius=randint((size * 0.667), (size * 1.667)),
118            color=color,
119            tag=tag,
120        )
121    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 diamond( center=(0, 0), width=25, height=50, color="hot pink", outline="", tag="",):
124def diamond(
125    center=(0, 0), width=25, height=50, color="hot pink", outline="", tag="", 
126):
127    """
128    A reporter function that draws a rectangle.
129    Args:
130        center (`tuple`): A coordinate representing the center of the shape.
131        width (`int`): How wide to draw the shape.
132        height (`int`): How tall to draw the shape.
133        color (`str`): What color to draw the shape.
134        outline (`str`): What color should the border of the shape be.
135        tag (`str`): The tag to assign to the shape.
136
137    Returns:
138        `Shape`: The shape that was created.
139    """
140    point_0 = (center[0] - width / 2, center[1])
141    point_1 = (center[0], center[1] - height / 2)
142    point_2 = (center[0] + width / 2, center[1])
143    point_3 = (center[0], center[1] + height / 2)
144    return _a_canvas.create_polygon(
145        point_0,
146        point_1,
147        point_2,
148        point_3,
149        fill=_safe_color(color),
150        tags=tag,
151        outline=outline,
152        ,
153    )

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 grid(width=None, height=None, interval=100, show_labels=True):
156def grid(width=None, height=None, interval=100, show_labels=True):
157    """
158    Draws a grid on a screen with intervals of 100.
159
160    Args:
161        width (`int`): The width of the grid to draw (defaults to the whole window)
162        height (`int`): The height of the grid to draw (defaults to the whole window)
163        interval (`int`): The interval to draw the grid on.
164        show_labels (`bool`): Whether or not to show coordinate labels.
165
166    """
167
168    if width is None
169        width = get_window_width()
170
171    if height is None
172        height = get_window_height()
173
174    # Creates all vertical lines at intervals of 100
175    for i in range(0, width, interval):
176        _a_canvas.create_line(i, 0, i, height, tag="grid", fill="black")
177    # Creates all horizontal lines at intervals of 100
178    for i in range(0, height, interval):
179        _a_canvas.create_line(0, i, width, i, tag="grid", fill="black")
180
181    if show_labels
182        # Creates axis labels
183        offset = 2
184        for y in range(0, height, interval):
185            for x in range(0, width, interval):
186                _a_canvas.create_oval(
187                    x - offset,
188                    y - offset,
189                    x + offset,
190                    y + offset,
191                    fill="black",
192                    tag="grid",
193                )
194                _a_canvas.create_text(
195                    x + offset,
196                    y + offset,
197                    text="({0}, {1})".format(x, y),
198                    anchor="nw",
199                    font=("Purisa", 8),
200                    fill="black",
201                    tag="grid",
202                )

Draws a grid on a screen with intervals of 100.

Arguments:
  • width (int): The width of the grid to draw (defaults to the whole window)
  • height (int): The height of the grid to draw (defaults to the whole window)
  • interval (int): The interval to draw the grid on.
  • show_labels (bool): Whether or not to show coordinate labels.
def image( image_path, position=(200, 200), rotation=None, scale=None, tag="",):
208def image(image_path, position=(200, 200), rotation=None, scale=None, tag="", ):
209    """
210    Draws a given image on the screen. NOTE: Requires the `pillow` package to be installed - contact
211    Prof. Bain or post on edSTEM if you"d like more details!
212
213    Args:
214        image_path (`str`): Location of the image file on your computer.
215        position (`tuple`): A coordinate at which to render the image.
216        rotation (`int`): A number of degrees to rotate the given image.
217        scale (`int`): A scaling factor to multiply the image size by.
218        tag (`str`): A string representing the "name" fo this shape.
219    """
220    # import PIL libraries
221    from PIL import Image, ImageTk
222
223    anchor = "nw"
224
225    import os
226
227    # 1. create PIL image and apply any image transformations:
228    dir_path = os.path.dirname(os.path.realpath(__file__))
229    image_path = os.path.join(dir_path, image_path)
230    pil_image = Image.open(image_path)
231    if scale
232        size = (round(pil_image.size[0] * scale), round(pil_image.size[1] * scale))
233        pil_image = pil_image.resize(size)
234    if rotation
235        pil_image = pil_image.rotate(rotation)  # note: returns a copy
236
237    # 2. convert to tkinter-compatible image format:
238    tkinter_image = ImageTk.PhotoImage(pil_image)
239    _cache.append(
240        tkinter_image
241    )  # workaround for known tkinter bug: http://effbot.org/pyfaq/why-do-my-tkinter-images-not-appear.htm
242
243    # 3. draw image on canvas:
244    _a_canvas.create_image(
245        *position, image=tkinter_image, anchor=anchor, tags=tag, 
246    )

Draws a given image on the screen. NOTE: Requires the pillow package to be installed - contact Prof. Bain or post on edSTEM if you'd like more details!

Arguments:
  • image_path (str): Location of the image file on your computer.
  • position (tuple): A coordinate at which to render the image.
  • rotation (int): A number of degrees to rotate the given image.
  • scale (int): A scaling factor to multiply the image size by.
  • tag (str): A string representing the "name" fo this shape.
def line(points=[], curvy=False, color="hot pink", tag="", ):
249def line(points=[], curvy=False, color="hot pink", tag="", ):
250    """
251    A reporter function that draws a line given a list of points.
252    Args:
253        points (`list`): The points that define the line; this should be a list of tuples (coordinates).
254        curvy (`bool`): Makes a curvy line instead.
255        color (`str`): What color to make the shape.
256        tag (`str`): The tag to assign to the shape.
257
258    Returns:
259        `Shape`: The line that was created.
260    """
261    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 oval( center=(0, 0), radius_x=25, radius_y=50, color="hot pink", outline="", tag="",):
264def oval(
265    center=(0, 0),
266    radius_x=25,
267    radius_y=50,
268    color="hot pink",
269    outline="",
270    tag="",
271    ,
272):
273    """
274    A reporter function that draws an oval.
275    Args:
276        center (`tuple`): A coordinate representing the center of the shape.
277        radius_x (`int`): Specifies the oval"s radius on the x-axis.
278        radius_y (`int`): Specifies the oval"s radius on the y-axis.
279        color (`str`): What color to draw the shape.
280        outline (`str`): What color should the border of the shape be.
281        tag (`str`): The tag to assign to the shape.
282
283    Returns:
284        `Shape`: The oval that was created.
285    """
286    x = center[0]
287    y = center[1]
288    x0, y0, x1, y1 = (x - radius_x, y - radius_y, x + radius_x, y + radius_y)
289    steps = 100
290    # major and minor axes
291    a = (x1 - x0) / 2.0
292    b = (y1 - y0) / 2.0
293    # center
294    xc = x0 + a
295    yc = y0 + b
296    point_list = []
297    # create the oval as a list of points
298    for i in range(steps):
299        # Calculate the angle for this step
300        theta = (pi * 2) * (float(i) / steps)
301        x = a * cos(theta)
302        y = b * sin(theta)
303        point_list.append(round(x + xc))
304        point_list.append(round(y + yc))
305
306    return _a_canvas.create_polygon(
307        point_list, fill=_safe_color(color), tags=tag, 
308    )

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 pixel_art(top_left, artwork, palette, pixel=10, tag=""):
311def pixel_art(top_left, artwork, palette, pixel=10, tag=""):
312    """
313    Draws a pixel art design!
314
315    Args:
316        top_left (`tuple`): the top left coordinate of the pixel art
317        artwork (sequence of sequences): the art to draw
318        palette (sequence): the palette of colors to use for each different square
319        pixel (`int`, optional): how big each individual pixel should be
320        tag (`str`, optional): the tag to assign to every square in the row
321
322    Note: this doesn"t return anything so make sure to use a tag if you want to animate / modify.
323    """
324    x = top_left[0]
325    y = top_left[1]
326    for row in artwork
327        # draw each row at the specified (x, y) position:
328        _draw_row(row, (x, y), colors=palette, pixel=pixel, tag=tag)
329        # ...and don"t forget to shift the y-value down by the proper
330        #  amount so that the next row won"t draw on top of the first one:
331        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 polygon(points=[], color="hot pink", outline="", tag="", ):
334def polygon(points=[], color="hot pink", outline="", tag="", ):
335    """
336    A reporter function that draws a polygon given a list of points.
337    Args:
338        points (`list`): The points outlining the polygon; this should be a list of tuples (coordinates).
339            defaults to an empty list.
340        outline (`str`): What color should the border of the shape be.
341        color (`str`): What color to make the shape.
342
343    Returns:
344        `Shape`: The polygon that was created.
345    """
346    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 rectangle( top_left=(0, 0), width=25, height=50, color="hot pink", outline="", tag="",):
349def rectangle(
350    top_left=(0, 0), width=25, height=50, color="hot pink", outline="", tag="", 
351):
352    """
353    A reporter function that draws a rectangle.
354    Args:
355        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
356        width (`int`): How wide to draw the shape.
357        height (`int`): How tall to draw the shape.
358        color (`str`): What color to draw the shape.
359        outline (`str`): What color should the border of the shape be.
360        tag (`str`): The tag to assign to the shape.
361
362    Returns:
363        `Shape`: The rectangle that was created.
364    """
365    point_0 = top_left
366    point_1 = (top_left[0] + width, top_left[1])
367    point_2 = (top_left[0] + width, top_left[1] + height)
368    point_3 = (top_left[0], top_left[1] + height)
369    return _a_canvas.create_polygon(
370        point_0, point_1, point_2, point_3, fill=_safe_color(color), tags=tag, 
371    )

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 spiral( center=(0, 0), width=100, roughness=0.01, start=0, spirals=5, line_width=1,):
374def spiral(
375    center=(0, 0), width=100, roughness=0.01, start=0, spirals=5, line_width=1, 
376):
377    """
378    A reporter function that draws a spiral.
379    Args:
380        center (`tuple`): A coordinate representing the center of the shape.
381        width (`int`): Specifies the total width of the spiral.
382        roughness (`float`): Controls how spiral-y the shape is (lower is less spiral-y)
383        start (`int`): Where on the spiral to start drawing.
384        spirals (`int`): How many loops to draw.
385        line_width (`int`): How wide for the line to be drawn.
386        tag (`str`): The tag to assign to the shape.
387
388    Returns:
389        `Shape`: The spiral that was created.
390    """
391    theta = 0.0
392    r = start
393    all_points = []
394    prev_pos = _polar_to_cartesian(r, theta)
395    distance = width / 4 / pi / spirals
396    all_points.append((prev_pos[0] + center[0], prev_pos[1] + center[1]))
397    while theta < 2 * spirals * pi
398        theta += roughness
399        r = start + distance * theta
400        pos = _polar_to_cartesian(r, theta)
401        all_points.append((pos[0] + center[0], pos[1] + center[1]))
402
403    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 square( top_left=(0, 0), size=25, color="hot pink", outline="", tag="",):
406def square(top_left=(0, 0), size=25, color="hot pink", outline="", tag="", ):
407    """
408    A reporter function that draws a square.
409    Args:
410        top_left (`tuple`): A coordinate representing the top left-hand corner of the shape.
411        size (`int`): How big to draw the shape.
412        color (`str`): What color to draw the shape.
413        outline (`str`): What color should the border of the shape be.
414        tag (`str`): The tag to assign to the shape.
415
416    Returns:
417        `Shape`: The square that was created.
418    """
419    return rectangle(
420        top_left=top_left, width=size, height=size, color=color, tag=tag, 
421    )

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 star( center=(0, 0), radius=50, color="hot pink", outer_radius=75, points=5, outline="", tag="",):
424def star(
425    center=(0, 0),
426    radius=50,
427    color="hot pink",
428    outer_radius=75,
429    points=5,
430    outline="",
431    tag="",
432    ,
433):
434    """
435    A reporter function that draws a star.
436    Args:
437        center (`tuple`): A coordinate representing the center of the shape.
438        radius (`int`): Specifies the radius of the inside part of the star.
439        color (`str`): Specifies the color of the star.
440        outer_radius (`int`): Specifies the radius of the outside part of the star.
441        points (`int`): Specifies the number of points for the star.
442        outline (`str`): What color should the border of the shape be.
443        tag (`str`): The tag to assign to the shape.
444
445    Returns:
446        `Shape`: The star that was created.
447    """
448    arc_segment = 360 / points
449    vertices = []
450    for i in range(points):
451        inner_point = (
452            radius * cos(radians(arc_segment * i)) + center[0],
453            -1 * radius * sin(radians(arc_segment * i)) + center[1],
454        )
455        vertices.append(inner_point)
456        outer_point = (
457            outer_radius * cos(radians(arc_segment * i + arc_segment / 2)) + center[0],
458            -1 * outer_radius * sin(radians(arc_segment * i + arc_segment / 2))
459            + center[1],
460        )
461        vertices.append(outer_point)
462    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 text( top_left=(0, 0), text="", font=("Purisa", 32), color="black", tag="",):
465def text(
466    top_left=(0, 0), text="", font=("Purisa", 32), color="black", tag="", 
467):
468    """
469    A reporter function that draws text to the screen
470    Args:
471        top_left (`tuple`): coordinate pair to specify the location.
472        text (`str`): What text to draw.
473        font (`tuple`): A tuple where the first element is a string for the font name and the second is an
474           int with the font size.
475        color (`str`): What color should the text be.
476        tag (`str`): The name to tag this thing with.
477
478    Returns:
479        `Shape`: The text that was created.
480    """
481    return _a_canvas.create_text(
482        top_left, text=text, font=font, fill=color, tags=tag, 
483    )

A reporter function that draws text to the screen

Arguments:
  • top_left (tuple): coordinate pair to specify the location.
  • text (str): What text to draw.
  • font (tuple): A tuple where the first element is a string for the font name and the second is an int with the font size.
  • color (str): What color should the text be.
  • tag (str): The name to tag this thing with.
Returns:

Shape: The text that was created.

def triangle( bottom_center=(0, 0), width=25, top_shift=0, height=0, color="hot pink", outline="", tag="",):
486def triangle(
487    bottom_center=(0, 0),
488    width=25,
489    top_shift=0,
490    height=0,
491    color="hot pink",
492    outline="",
493    tag="",
494    ,
495):
496    """
497    A reporter function that draws a triangle.
498    Args:
499        bottom_center (`tuple`): A coordinate representing the bottom center of the shape.
500        width (`int`): Specifies the width of the base of the triangle.
501        top_shift (`int`): Specifies the how far to the left or right to shift the top of
502            the triangle from the bottom center.
503        height (`int`): Specifies the triangle"s height.
504        color (`str`): What color to draw the shape.
505        outline (`str`): What color should the border of the shape be.
506        tag (`str`): The tag to assign to the shape.
507
508    Returns:
509        `Shape`: The triangle that was created.
510    """
511    if height == 0
512        height = width * sqrt(3) / 2
513    point_0 = (bottom_center[0] - width / 2, bottom_center[1])
514    point_1 = (bottom_center[0] + width / 2, bottom_center[1])
515    point_2 = (bottom_center[0] + top_shift, bottom_center[1] - height)
516
517    return _a_canvas.create_polygon(
518        point_0, point_1, point_2, fill=_safe_color(color), tags=tag, 
519    )

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 wedge( center=(0, 0), radius=25, angle=180, color="hot pink", outline="", tag="",):
522def wedge(
523    center=(0, 0), radius=25, angle=180, color="hot pink", outline="", tag="", 
524):
525    """
526    A reporter function that draws a circle.
527    Args:
528        center (`tuple`): A coordinate representing the center of the shape.
529        radius (`int`): Specifies the circle"s radius.
530        angle (`int`): A number between 0 and 360 that specifies how much of the circle to draw.
531        color (`str`): What color to draw the shape.
532        outline (`str`): What color should the border of the shape be.
533        tag (`str`): The tag to assign to the shape.
534
535    Returns:
536        `Shape`: The wedge that was created.
537    """
538    point_list = [center[0], center[1]]
539    for i in range(0, 0 + angle):
540        x1 = center[0] + radius * cos(radians(i))
541        point_list.append(x1)
542        y1 = center[1] + radius * sin(radians(i))
543        point_list.append(y1)
544
545    point_list.append(center[0])
546    point_list.append(center[1])
547
548    return _a_canvas.create_polygon(
549        point_list, fill=_safe_color(color), outline=outline, tags=tag, 
550    )

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.

Shape_Modifier_Functions = ""
def above(shape1, shape2, offset_x=0, offset_y=0):
556def above(shape1, shape2, offset_x=0, offset_y=0):
557    """
558    A reporter function that places shape1 above shape2 (vertically). It does this by moving shape 1"s center
559    to shape 2"s center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
560    specified offset.
561
562    Args:
563        shape1 (`Shape` or Tag): The first shape to use.
564        shape2 (`Shape` or Tag): The second shape to use.
565        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
566        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
567
568    Returns:
569        `Shape`: The modified shape1.
570    """
571    overlay(shape1, shape2)
572    _a_canvas.move(
573        shape1,
574        0 + offset_x,
575        -1 * (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
576    )
577    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 align(shape1, shape2, via="middle", offset_x=0, offset_y=0):
580def align(shape1, shape2, via="middle", offset_x=0, offset_y=0):
581    """
582    A reporter function that aligns `shape1` with `shape2`. It does this by moving `shape1` to align with
583    whatever property of `shape2` is selected with the `via` input.
584
585    Args:
586        shape1 (`Shape` or Tag): The first shape to use.
587        shape2 (`Shape` or Tag): The second shape to use.
588        via (`str`): Has to be one of, the following options: `"center"` (horizontal center),
589            `"middle"` (vertical center), `"top"`, `"bottom"`, `"left"`, or `"right"`
590        offset_x (`int`): How much to shift in the x-axis after alignment
591        offset_y (`int`): How much to shift in the y-axis after alignment
592
593    Returns:
594        `Shape`: The modified shape1.
595    """
596    via_options = ["center", "middle", "top", "bottom", "left", "right"]
597    if via not in via_options
598        raise ValueError(
599            "The via input must be one of "
600            + (via_options)
601            + " but instead we found "
602            + (via)
603        )
604
605    outline1 = _get_outline(shape1)
606    outline2 = _get_outline(shape2)
607
608    if via == "center"
609        _a_canvas.move(
610            shape1, (outline2["center"][0] - outline1["center"][0]) + offset_x, offset_y
611        )
612
613    elif via == "middle"
614        _a_canvas.move(
615            shape1, offset_x, (outline2["center"][1] - outline1["center"][1]) + offset_y
616        )
617
618    elif via == "top"
619        _a_canvas.move(shape1, offset_x, (outline2["top"] - outline1["top"]) + offset_y)
620
621    elif via == "bottom"
622        _a_canvas.move(
623            shape1, offset_x, (outline2["bottom"] - outline1["bottom"]) + offset_y
624        )
625
626    elif via == "left"
627        _a_canvas.move(
628            shape1, (outline2["left"] - outline1["left"]) + offset_x, offset_y
629        )
630
631    elif via == "right"
632        _a_canvas.move(
633            shape1, (outline2["right"] - outline1["right"]) + offset_x, offset_y
634        )
635
636    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 beside(shape1, shape2, offset_x=0, offset_y=0):
639def beside(shape1, shape2, offset_x=0, offset_y=0):
640    """
641    A reporter function that places shape1 beside shape2 (horizontally). It does this by moving shape 1"s center
642    to shape 2"s center, moving shape 1 in the x-direction the exact width of shape 2, and then applying any
643    specified offset.
644
645    Args:
646        shape1 (`Shape` or Tag): The first shape to use.
647        shape2 (`Shape` or Tag): The second shape to use.
648        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
649        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
650
651    Returns:
652        `Shape`: The modified shape1.
653    """
654    overlay(shape1, shape2)
655    _a_canvas.move(
656        shape1,
657        (get_width(shape2) + get_width(shape1)) / 2 + offset_x,
658        0 + offset_y,
659    )
660    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):
663def below(shape1, shape2, offset_x=0, offset_y=0):
664    """
665    A reporter function that places shape1 below shape2 (vertically). It does this by moving shape 1"s center
666    to shape 2"s center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
667    specified offset.
668
669    Args:
670        shape1 (`Shape` or Tag): The first shape to use.
671        shape2 (`Shape` or Tag): The second shape to use.
672        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
673        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
674
675    Returns:
676        `Shape`: The modified shape1.
677    """
678    overlay(shape1, shape2)
679    _a_canvas.move(
680        shape1,
681        0 + offset_x,
682        (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
683    )
684    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 change_color(shape, color):
687def change_color(shape, color):
688    """
689    Change the fill color of a tagged object.
690
691    Args:
692        shape (`Shape` or Tag): The shape or tag to re-fill.
693        color (`str`): A color name or hex code to re-fill with.
694    """
695    ids = _a_canvas.find_withtag(shape)
696    for id in ids
697        _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 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 assign_tag(shape, tag):
710def assign_tag(shape, tag):
711    """
712    A function that assigns a `Shape` or other tagged object a new tag. This will
713    overwrite any existing tag that matches the provided `tag` argument. This means that if you have
714    a shape with multiple tags, _this function will only overwrite that one tag_. You would need to run
715    the function multiple times to rewrite the remaining tags.
716
717    Args:
718        shape (`Shape` or Tag): The shape to which you"d like to assign a new tag
719        tag (`str`): A new valid tag for this shape.
720
721    """
722    ids = _a_canvas.find_withtag(shape)
723    for id in ids
724        the_tags = (_a_canvas.gettags(id))        
725        if shape in the_tags # if it has a tag replace it
726            index = the_tags.index(shape)
727            the_tags[index] = tag
728        else # otherwise it didn"t have a tag
729            the_tags.append(tag)
730        _a_canvas.itemconfig(id, tags=the_tags)

A function that assigns a Shape or other tagged object a new tag. This will overwrite any existing tag that matches the provided tag argument. This means that if you have a shape with multiple tags, _this function will only overwrite that one tag_. You would need to run the function multiple times to rewrite the remaining tags.

Arguments:
  • shape (Shape or Tag): The shape to which you'd like to assign a new tag
  • tag (str): A new valid tag for this shape.
def duplicate(shape, color=None):
733def duplicate(shape, color=None):
734    """
735    A reporter function that perfectly copies a shape and returns that copy.
736
737    Args:
738        shape (`Shape` or Tag): The shape to duplicate.
739        color (`str`): A new color to use with the duplicated shape.
740
741    Returns:
742        `Shape`: The new duplicated shape.
743    """
744    shape_type = _a_canvas.type(shape)
745    shape_config = _a_canvas.itemconfig(shape)
746    shape_coords = _a_canvas.coords(shape)
747    the_copy = None
748    if shape_type == "polygon"
749        new_config = {key shape_config[key][-1] for key in shape_config.keys()}
750        if color != None
751            new_config["fill"] = color
752        the_copy = _a_canvas.create_polygon(shape_coords, new_config)
753        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):
756def mirror(shape):
757    """
758    A function that takes a shape and flips it across its vertical
759    axis, returning the modified shape.
760
761    Args:
762        shape (`Shape` or Tag): The shape in question.
763
764    """
765    center = get_center(shape)[0]
766    shape_ids = _a_canvas.find_withtag(shape)
767    for shape_id in shape_ids
768        flipped_coordinates = []
769        shape_coords = _a_canvas.coords(shape_id)
770        counter = 0
771        for num in shape_coords
772            if counter % 2 == 0
773                if num < center
774                    flipped_coordinates.append(num + 2 * (center - num))
775                elif num > center
776                    flipped_coordinates.append(num - 2 * (num - center))
777                else
778                    flipped_coordinates.append(num)
779            else
780                flipped_coordinates.append(num)
781            counter += 1
782        _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 move(shape, x_shift=0, y_shift=0):
785def move(shape, x_shift=0, y_shift=0):
786    """
787    Purpose: Move the x and y position of all shapes that have been tagged
788    with the tag argument
789
790    Args:
791        shape (`Shape` or Tag): The shape in question.
792        x_shift (`int`; optional): amount to move in the x direction
793        y_shift (`int`; optional): amount to move in the y direction
794    """
795    shape_ids = _a_canvas.find_withtag(shape)
796    for id in shape_ids
797        _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 move_to(tag, to, anchor="center"):
800def move_to(tag, to, anchor="center"):
801    """
802    Move the given tagged item to a particular `point` maintaining some `anchor`.
803    Note: this is NOT the same as the `move` function which moves an object by a specific amount.
804
805    Args:
806        tag (Shape or `str`): the shape (or shapes) to move
807        to (`tuple`): the `(x, y)` coordinate to which you wish to move the tagged object
808        anchor (`str`): which point on the shape do you want to move toward the given tuple. You can
809            use either `"center"` (default), `"top_left"`, `"top_right"`, `"bottom_left"`, or `"bottom_right"`.
810    """
811    anchor_options = ["center", "top_left", "top_right", "bottom_left", "bottom_right"]
812    if anchor not in anchor_options
813        raise ValueError(
814            "The anchor input must be one of "
815            + (anchor_options)
816            + " but instead we found "
817            + (anchor)
818        )
819
820    outline = _get_outline(tag)
821    delta_x = 0
822    delta_y = 0
823
824    if anchor == "top_left"
825        delta_x = to[0] - outline["left"]
826        delta_y = to[1] - outline["top"]
827    elif anchor == "top_right"
828        delta_x = to[0] - outline["right"]
829        delta_y = to[1] - outline["top"]
830    elif anchor == "bottom_right"
831        delta_x = to[0] - outline["right"]
832        delta_y = to[1] - outline["bottom"]
833    elif anchor == "bottom_left"
834        delta_x = to[0] - outline["left"]
835        delta_y = to[1] - outline["bottom"]
836    elif anchor == "center"
837        delta_x = to[0] - outline["center"][0]
838        delta_y = to[1] - outline["center"][1]
839
840    _a_canvas.move(tag, delta_x, delta_y)

Move the given tagged item to a particular point maintaining some anchor. Note: this is NOT the same as the move function which moves an object by a specific amount.

Arguments:
  • tag (Shape or str): the shape (or shapes) to move
  • to (tuple): the (x, y) coordinate to which you wish to move the tagged object
  • anchor (str): which point on the shape do you want to move toward the given tuple. You can use either "center" (default), "top_left", "top_right", "bottom_left", or "bottom_right".
def overlay(shape1, shape2, offset_x=0, offset_y=0):
843def overlay(shape1, shape2, offset_x=0, offset_y=0):
844    """
845    A reporter function that overlays shape1 onto shape2. It does this by moving shape 1"s center
846    to shape 2"s center, and then applying any specified offset.
847    Args:
848        shape1 (`Shape` or Tag): The first shape to use.
849        shape2 (`Shape` or Tag): The second shape to use.
850        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
851        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
852
853    Returns:
854        `Shape`: The modified shape1.
855    """
856    center1 = get_center(shape1)
857    center2 = get_center(shape2)
858    _a_canvas.move(
859        shape1,
860        (center2[0] - center1[0]) + offset_x,
861        (center2[1] - center1[1]) + offset_y,
862    )
863    _a_canvas.tag_raise(shape1, shape2)
864    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 portion(shape, start=0, end=0.5):
867def portion(shape, start=0, end=0.5):
868    """
869    Purpose: Take a slice or portion of some already created shape.
870
871    Args:
872        shape (`Shape` or Tag): The shape to take a portion of
873        start (`float`): A number between 0 and 1 representing where to start the slice.
874        end (`float`): A number between 0 and 1 representing where to end the slice.
875
876    For example, taking a portion from 0 to 0.5 of a circle would result in a semi-circle.
877
878    Note: this function is experimental. It might produce unexpected results!
879    """
880    all_shapes = _a_canvas.find_withtag(shape)
881
882    for a_shape in all_shapes
883        coords = _a_canvas.coords(a_shape)
884
885        start_coord = floor(start * len(coords))
886        if start_coord % 2 == 1
887            start_coord = start_coord - 1  # need to start with an x,y pair
888        end_coord = floor(end * len(coords))
889        if end_coord % 2 == 1
890            end_coord = end_coord - 1  # need to end with an x,y pair
891
892        # slice is up to not including so get the last x,y pair
893        new_coords = coords[start_coord  end_coord + 2]
894
895        # loop shape back in on itself
896        new_coords.append(new_coords[0])
897        new_coords.append(new_coords[1])
898
899        # set the coordinates:
900        _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_back(shape):
903def put_in_back(shape):
904    """
905    A function that "lowers" a shape to the "bottom" of the screen."
906
907    Args:
908        shape (`Shape` or Tag): The shape in question.
909    """
910    _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 put_in_front(shape):
913def put_in_front(shape):
914    """
915    A function that "raises" a shape to the "top" of the screen."
916
917    Args:
918        shape (`Shape` or Tag): The shape in question.
919    """
920    _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 rotate(shape, degrees=5, origin=None):
923def rotate(shape, degrees=5, origin=None):
924    """
925    A reporter function that takes a shape and rotates it by a specified amount around a specified point.
926    It does this by interpolating a polygon around the shape and calculating the shifts of individual
927    points on the edge of the polygon.
928
929    Args:
930        shape (`Shape` or Tag): The shape to rotate.
931        degrees (`int`): The number of degrees to rotate the shape.
932        origin (`tuple`): An `(x,y)` coordinate about which to perform the rotation. Defaults to the center
933            of the given shape.
934
935    Returns:
936        `Shape`: The modified shape.
937    """
938    if origin is None
939        origin = get_center(shape)
940
941    theta = radians(degrees)
942    ox, oy = origin
943
944    all_shapes = _a_canvas.find_withtag(shape)
945
946    for a_shape in all_shapes
947        coords = _a_canvas.coords(a_shape)
948        # update coordinates:
949        for i in range(0, len(coords), 2):
950            px, py = coords[i], coords[i + 1]
951            qx = cos(theta) * (px - ox) - sin(theta) * (py - oy) + ox
952            qy = sin(theta) * (px - ox) + cos(theta) * (py - oy) + oy
953            coords[i] = qx
954            coords[i + 1] = qy
955        # set the coordinates:
956        _a_canvas.coords(a_shape, coords)
957
958    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 scale(shape, x_scale=1.0, y_scale=1.0):
961def scale(shape, x_scale=1.0, y_scale=1.0):
962    """
963    A function that takes a given `Shape` or tag and scales it on either/both the x and y-axis.
964
965    The two optional inputs accept floats between 0.0 and 1.0. Values greater than 1 will cause
966    the shape to grow along that access. Values less than 1.0 will cause the shape to shrink.
967
968    Args:
969        shape (`Shape` or Tag): The shape or tag to re-fill.
970        x_scale (`float`): How much to scale in the x-axis.
971        y_scale (`float`): How much to scale in the y-axis.
972    """
973    ids = _a_canvas.find_withtag(shape)
974
975    coord = get_center(shape)
976
977    for i in ids
978        _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 underlay(shape1, shape2, offset_x=0, offset_y=0):
 981def underlay(shape1, shape2, offset_x=0, offset_y=0):
 982    """
 983    A reporter function that underlays shape1 beneath shape2. It does this by moving shape 1"s center
 984    to shape 2"s center, and then applying any specified offset.
 985    Args:
 986        shape1 (`Shape` or Tag): The first shape to use.
 987        shape2 (`Shape` or Tag): The second shape to use.
 988        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
 989        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
 990
 991    Returns:
 992        `Shape`: The modified shape1.
 993    """
 994    center1 = get_center(shape1)
 995    center2 = get_center(shape2)
 996    _a_canvas.move(
 997        shape1,
 998        (center2[0] - center1[0]) + offset_x,
 999        (center2[1] - center1[1]) + offset_y,
1000    )
1001    _a_canvas.tag_lower(shape1, shape2)
1002    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.

Utility_Functions = ""
def clear_window(keep_grid=True):
1008def clear_window(keep_grid=True):
1009    """
1010    A function that deletes everything from the window.
1011
1012    Args:
1013        keep_grid (`bool`): Whether or not to keep the grid.
1014    """
1015    all_shapes = _a_canvas.find_all()
1016
1017    for shape in all_shapes
1018        tags = _a_canvas.gettags(shape)
1019        if "grid" in tags and keep_grid
1020            continue
1021        _a_canvas.delete(shape)
1022
1023    global _resize_enabled
1024    _resize_enabled = True

A function that deletes everything from the window.

Arguments:
  • keep_grid (bool): Whether or not to keep the grid.
def distance(point1, point2):
1027def distance(point1, point2):
1028    """
1029    A reporter function calculates the distance between two `(x, y)` coordinates.
1030
1031    Args:
1032        point1 (`tuple`): The first `(x, y)` coordinate.
1033        point2 (`tuple`): The second `(x, y)` coordinate.
1034
1035    Returns:
1036         A `float` representing the distance between the two points.
1037    """
1038    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 does_tag_exist(tag):
1041def does_tag_exist(tag):
1042    """
1043    Returns `True` if a given tag exists otherwise returns `False`.
1044
1045    Args:
1046        `tag` (`str`): [Required] The tag of the object to lookup.
1047
1048    """
1049    result = _a_canvas.find_withtag(tag)
1050
1051    if result
1052        return True
1053    else
1054        return False

Returns True if a given tag exists otherwise returns False.

Arguments:
  • tag (str): [Required] The tag of the object to lookup.
def get_bottom(shape):
1057def get_bottom(shape):
1058    """
1059    A reporter function calculates the maximum y-value of a given shape (since the y-axis is flipped).
1060
1061    Args:
1062        shape (`Shape` or Tag): The shape in question.
1063
1064    Returns:
1065         A `int` representing the maximum y-coordinate of the shape.
1066    """
1067    bbox = _safe_bbox(shape)
1068    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_center(shape):
1071def get_center(shape):
1072    """
1073    A reporter function calculates the a coordinate at the center of some shape.
1074
1075    Args:
1076        shape (`Shape` or Tag): The shape in question.
1077
1078    Returns:
1079         A `tuple` representing center of the given shape.
1080    """
1081    bbox = _safe_bbox(shape)
1082
1083    if bbox is None
1084        raise Exception(
1085            f"We couldn"t find the shape with id/tag {shape}. Make sure it exists!"
1086        )
1087
1088    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_colors(shape_or_shapes):
1091def get_colors(shape_or_shapes):
1092    """
1093    A reporter function that returns all the colors associated with a tag or list of tags.
1094
1095    Args:
1096        shape_or_shapes (`str`/`Shape` or `List`): the shape/tag or list of shapes/tags you"d like to find the colors of
1097
1098    Returns:
1099        A `List` containing all unique colors associated with that tag(s)
1100    """
1101    all_shapes = []
1102    if not isinstance(shape_or_shapes, ):
1103        shape_or_shapes = [shape_or_shapes]
1104    for shape in shape_or_shapes
1105        all_shapes += _a_canvas.find_withtag(shape)
1106
1107    all_colors = []
1108    for shape in all_shapes
1109        color = _a_canvas.itemcget(shape, "fill")
1110        if color not in all_colors
1111            all_colors.append(color)
1112
1113    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_height(shape):
1116def get_height(shape):
1117    """
1118    A reporter function calculates the height of some given shape.
1119
1120    Args:
1121        shape (`Shape` or Tag): The shape in question.
1122
1123    Returns:
1124         A `int` representing the height of the shape.
1125    """
1126    bbox = _safe_bbox(shape)
1127    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_left(shape):
1130def get_left(shape):
1131    """
1132    A reporter function calculates the minimum x-value of a given shape.
1133
1134    Args:
1135        shape (`Shape` or Tag): The shape in question.
1136
1137    Returns:
1138         A `int` representing the minimum x-coordinate of the shape.
1139    """
1140    bbox = _safe_bbox(shape)
1141    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):
1144def get_right(shape):
1145    """
1146    A reporter function calculates the maximum x-value of a given shape.
1147
1148    Args:
1149        shape (`Shape` or Tag): The shape in question.
1150
1151    Returns:
1152         A `int` representing the maximum x-coordinate of the shape.
1153    """
1154    bbox = _safe_bbox(shape)
1155    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_tag_from_event(event, precision=25):
1158def get_tag_from_event(event, precision=25):
1159    """
1160    Tries to return a tag of an object at a given mouse-event.
1161
1162    Args:
1163        event (`Event`): Must be a mouse event otherwise we"ll give back an error.
1164        precision (`int`): How precise in number of pixels does a user have be in order to "select" an object
1165
1166    Returns a blank string `""` if no shapes are found closer than `precision`.
1167    """
1168
1169    if (event.type) not in [4, 6]:
1170        raise Exception(f"Received an event that isn"t a mouse event: {event}")
1171
1172    try
1173        x = event.x
1174        y = event.y
1175        shape_id = _a_canvas.find_closest(x, y)  # get the top shape
1176        if shape_id and distance(get_center(shape_id), (x, y)) < precision
1177            tags = _a_canvas.gettags(shape_id)
1178            if len(tags) > 0
1179                return tags[0]
1180        return ""
1181
1182    except
1183        raise Exception(
1184            "No tag found! Maybe you passed us an event that isn"t a mouse event?"
1185        )

Tries to return a tag of an object at a given mouse-event.

Arguments:
  • event (Event): Must be a mouse event otherwise we'll give back an error.
  • precision (int): How precise in number of pixels does a user have be in order to "select" an object

Returns a blank string "" if no shapes are found closer than precision.

def get_top(shape):
1188def get_top(shape):
1189    """
1190    A reporter function calculates the minimum y-value of a given shape (since the y-axis is flipped).
1191
1192    Args:
1193        shape (`Shape` or Tag): The shape in question.
1194
1195    Returns:
1196         A `int` representing the minimum y-coordinate of the shape.
1197    """
1198    bbox = _safe_bbox(shape)
1199    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_width(shape):
1202def get_width(shape):
1203    """
1204    A reporter function calculates the width of some given shape.
1205
1206    Args:
1207        shape (`Shape` or Tag): The shape in question.
1208
1209    Returns:
1210         An `int` representing width of the shape.
1211    """
1212    bbox = _safe_bbox(shape)
1213    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 get_window_height():
1216def get_window_height():
1217    """
1218    A reporter function that returns the current height of the window.
1219
1220    Returns:
1221         An `int` representing height of the window.
1222    """
1223    return _a_canvas.winfo_height()

A reporter function that returns the current height of the window.

Returns:

An int representing height of the window.

def get_window_width():
1226def get_window_width():
1227    """
1228    A reporter function that returns the current width of the window.
1229
1230    Returns:
1231         An `int` representing width of the window.
1232    """
1233    return _a_canvas.winfo_width()

A reporter function that returns the current width of the window.

Returns:

An int representing width of the window.

def interpolate_colors(color1, color2, frac):
1236def interpolate_colors(color1, color2, frac):
1237    """
1238    A reporter function that generates a new color between two given colors.
1239    Args:
1240        color1 (`str`): The path of the file to wrap
1241        color2 (`str`): The path of the file to wrap
1242        frac (`float`): What fraction of each color to take. An input of 0 returns
1243            color1, an input of 1 returns color2, an input of 0.5 returns a color
1244            perfectly between the two.
1245
1246    Returns:
1247         A color (as a hex `str`) to be used elsewhere
1248    """
1249    if "#" not in color1
1250        color1 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color1)))
1251    else
1252        color1 = _tupelize_color(color1)
1253    if "#" not in color2
1254        color2 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color2)))
1255    else
1256        color2 = _tupelize_color(color2)
1257    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 random_color():
1260def random_color():
1261    """
1262    Returns a random color as a `string` to be used.
1263    It does not accept any inputs.
1264    """
1265    r = lambda randint(0, 255)
1266    return "#%02X%02X%02X" % (r(), r(), r())

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

def listen_for(event_str, handler_function, override=False):
1269def listen_for(event_str, handler_function, override=False):
1270    """
1271    Sets up a listener for a given event on our window.
1272
1273    Args:
1274        event_str (`str`): The magic string that represents this event in the window
1275        handler_function (`func`): The name (not a string though) of the function you want called when the event his heard
1276        override (`bool`): Only use this if you speak to Prof. Bain and he recommends it.
1277
1278    The supported events are:
1279      * `"LEFT-CLICK"`: Left mouse click
1280      * `"RIGHT-CLICK"`: Right mouse click
1281      * `"ALT-CLICK"`: If you"re using a PC, this event might instead work for Right Click
1282      * `"LEFT-DRAG"`: Left mouse clicked and dragged on the screen
1283      * `"RIGHT-DRAG"`: Right mouse clicked and dragged on the screen
1284      * `"ALT-DRAG"`: For PCs, this event might instead work for RIGHT-DRAG
1285      * `"DOUBLE-LEFT"`: Left mouse double click
1286      * `"DOUBLE-RIGHT"`: Right mouse double click
1287      * `"DOUBLE-ALT"`: For PCs, this event might instead work for DOUBLE-RIGHT
1288      * `"KEY"`: The catch-all event for Keyboard presses
1289    """
1290
1291    event_translator = {
1292        "LEFT-CLICK" "<Button-1>",
1293        "RIGHT-CLICK" "<Button-2>",
1294        "ALT-CLICK" "<Button-3>",
1295        "LEFT-DRAG" "<B1-Motion>",
1296        "RIGHT-DRAG" "<B2-Motion>",
1297        "ALT-DRAG" "<B3-Motion>",
1298        "DOUBLE-LEFT" "<Double-Button-1>",
1299        "DOUBLE-RIGHT" "<Double-Button-2>",
1300        "DOUBLE-ALT" "<Double-Button-3>",
1301        "KEY" "<Key>",
1302    }
1303
1304    if event_str not in event_translator and not override
1305        raise (
1306            TypeError(
1307                f"The event you entered, {event_str}, isn"t supported. Here are the supported events: {[i for i in event_translator]}"
1308            )
1309        )
1310
1311    event = event_translator[event_str]
1312    
1313    listen_for.tracker.add(event_str)
1314
1315    _a_canvas.bind(event, handler_function)

Sets up a listener for a given event on our window.

Arguments:
  • event_str (str): The magic string that represents this event in the window
  • handler_function (func): The name (not a string though) of the function you want called when the event his heard
  • override (bool): Only use this if you speak to Prof. Bain and he recommends it.
The supported events are:
  • "LEFT-CLICK": Left mouse click
  • "RIGHT-CLICK": Right mouse click
  • "ALT-CLICK": If you're using a PC, this event might instead work for Right Click
  • "LEFT-DRAG": Left mouse clicked and dragged on the screen
  • "RIGHT-DRAG": Right mouse clicked and dragged on the screen
  • "ALT-DRAG": For PCs, this event might instead work for RIGHT-DRAG
  • "DOUBLE-LEFT": Left mouse double click
  • "DOUBLE-RIGHT": Right mouse double click
  • "DOUBLE-ALT": For PCs, this event might instead work for DOUBLE-RIGHT
  • "KEY": The catch-all event for Keyboard presses
def setup_shapes(title, background="white", include_grid=True, width=600, height=600):
1320def setup_shapes(title, background="white", include_grid=True, width=600, height=600):
1321    """
1322    A static function that sets up the pop-up window. You can specify the size of the window here.
1323
1324    However, you should NOT add any calls to this function unless Prof. Bain specifically tells you to!
1325
1326    Args:
1327        title (`str`): The title of the pop-up window.
1328        background (`str`): A valid color as a string to be used as the background color.
1329        include_grid (`bool`): Whether or not to draw the grid.
1330        width (`int` or `str`): How wide the window should appear (advanced: use the string "FULLWIDTH" to maximize the width)
1331        height (`int` or `str`): How wide the window should appear (advanced: use the string "FULLHEIGHT" to maximize the width)
1332    """
1333
1334    global _a_canvas
1335    gui = Tk()
1336    gui.title(title)
1337
1338    if width == "FULLWIDTH"
1339        width = gui.winfo_screenwidth()
1340
1341    if height == "FULLHEIGHT"
1342        height = gui.winfo_screenheight()
1343
1344    _a_canvas = Canvas(gui, background=background, width=width, height=height)
1345    _a_canvas.pack()
1346    if include_grid
1347        grid(width, height)
1348
1349    _a_canvas.focus_set()
1350    return _a_canvas

A static function that sets up the pop-up window. You can specify the size of the window here.

However, you should NOT add any calls to this function unless Prof. Bain specifically tells you to!

Arguments:
  • title (str): The title of the pop-up window.
  • background (str): A valid color as a string to be used as the background color.
  • include_grid (bool): Whether or not to draw the grid.
  • width (int or str): How wide the window should appear (advanced: use the string "FULLWIDTH" to maximize the width)
  • height (int or str): How wide the window should appear (advanced: use the string "FULLHEIGHT" to maximize the width)
def update():
1353def update():
1354    """
1355    A static function that sets up the pop-up window. DO NOT USE THIS FUNCTION unless Prof. Bain explicitly says to use it.
1356    """
1357    _a_canvas.update()

A static function that sets up the pop-up window. DO NOT USE THIS FUNCTION unless Prof. Bain explicitly says to use it.