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

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

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="",):
78def circle(center=(0, 0), radius=25, color="hot pink", outline="", tag="", ):
79    """
80    A reporter function that draws a circle.
81    Args:
82        center (`tuple`): A coordinate representing the center of the shape.
83        radius (`int`): Specifies the circle"s radius.
84        color (`str`): What color to draw the shape.
85        outline (`str`): What color should the border of the shape be.
86        tag (`str`): The tag to assign to the shape.
87
88    Returns:
89        `Shape`: The circle that was created.
90    """
91    return oval(
92        center=center, radius_x=radius, radius_y=radius, color=color, tag=tag, 
93    )

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

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

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

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

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

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

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

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

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

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):
552def above(shape1, shape2, offset_x=0, offset_y=0):
553    """
554    A reporter function that places shape1 above shape2 (vertically). It does this by moving shape 1"s center
555    to shape 2"s center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
556    specified offset.
557
558    Args:
559        shape1 (`Shape` or Tag): The first shape to use.
560        shape2 (`Shape` or Tag): The second shape to use.
561        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
562        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
563
564    Returns:
565        `Shape`: The modified shape1.
566    """
567    overlay(shape1, shape2)
568    _a_canvas.move(
569        shape1,
570        0 + offset_x,
571        -1 * (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
572    )
573    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):
576def align(shape1, shape2, via="middle", offset_x=0, offset_y=0):
577    """
578    A reporter function that aligns `shape1` with `shape2`. It does this by moving `shape1` to align with
579    whatever property of `shape2` is selected with the `via` input.
580
581    Args:
582        shape1 (`Shape` or Tag): The first shape to use.
583        shape2 (`Shape` or Tag): The second shape to use.
584        via (`str`): Has to be one of, the following options: `"center"` (horizontal center),
585            `"middle"` (vertical center), `"top"`, `"bottom"`, `"left"`, or `"right"`
586        offset_x (`int`): How much to shift in the x-axis after alignment
587        offset_y (`int`): How much to shift in the y-axis after alignment
588
589    Returns:
590        `Shape`: The modified shape1.
591    """
592    via_options = ["center", "middle", "top", "bottom", "left", "right"]
593    if via not in via_options
594        raise ValueError(
595            "The via input must be one of "
596            + (via_options)
597            + " but instead we found "
598            + (via)
599        )
600
601    outline1 = _get_outline(shape1)
602    outline2 = _get_outline(shape2)
603
604    if via == "center"
605        _a_canvas.move(
606            shape1, (outline2["center"][0] - outline1["center"][0]) + offset_x, offset_y
607        )
608
609    elif via == "middle"
610        _a_canvas.move(
611            shape1, offset_x, (outline2["center"][1] - outline1["center"][1]) + offset_y
612        )
613
614    elif via == "top"
615        _a_canvas.move(shape1, offset_x, (outline2["top"] - outline1["top"]) + offset_y)
616
617    elif via == "bottom"
618        _a_canvas.move(
619            shape1, offset_x, (outline2["bottom"] - outline1["bottom"]) + offset_y
620        )
621
622    elif via == "left"
623        _a_canvas.move(
624            shape1, (outline2["left"] - outline1["left"]) + offset_x, offset_y
625        )
626
627    elif via == "right"
628        _a_canvas.move(
629            shape1, (outline2["right"] - outline1["right"]) + offset_x, offset_y
630        )
631
632    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):
635def beside(shape1, shape2, offset_x=0, offset_y=0):
636    """
637    A reporter function that places shape1 beside shape2 (horizontally). It does this by moving shape 1"s center
638    to shape 2"s center, moving shape 1 in the x-direction the exact width of shape 2, and then applying any
639    specified offset.
640
641    Args:
642        shape1 (`Shape` or Tag): The first shape to use.
643        shape2 (`Shape` or Tag): The second shape to use.
644        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
645        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
646
647    Returns:
648        `Shape`: The modified shape1.
649    """
650    overlay(shape1, shape2)
651    _a_canvas.move(
652        shape1,
653        (get_width(shape2) + get_width(shape1)) / 2 + offset_x,
654        0 + offset_y,
655    )
656    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):
659def below(shape1, shape2, offset_x=0, offset_y=0):
660    """
661    A reporter function that places shape1 below shape2 (vertically). It does this by moving shape 1"s center
662    to shape 2"s center, moving shape 1 in the y-direction the exact height of shape 2, and then applying any
663    specified offset.
664
665    Args:
666        shape1 (`Shape` or Tag): The first shape to use.
667        shape2 (`Shape` or Tag): The second shape to use.
668        offset_x (`int`): How much to shift shape 2 in the x-direction after moving it.
669        offset_y (`int`): How much to shift shape 2 in the x-direction after moving it.
670
671    Returns:
672        `Shape`: The modified shape1.
673    """
674    overlay(shape1, shape2)
675    _a_canvas.move(
676        shape1,
677        0 + offset_x,
678        (get_height(shape2) + get_height(shape1)) / 2 + offset_y,
679    )
680    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):
683def change_color(shape, color):
684    """
685    Change the fill color of a tagged object.
686
687    Args:
688        shape (`Shape` or Tag): The shape or tag to re-fill.
689        color (`str`): A color name or hex code to re-fill with.
690    """
691    ids = _a_canvas.find_withtag(shape)
692    for id in ids
693        _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):
696def delete(shape):
697    """
698    A function that deletes a shape from our screen.
699
700    Args:
701        shape (`Shape` or Tag): The shape to delete.
702    """
703    _a_canvas.delete(shape)

A function that deletes a shape from our screen.

Arguments:
  • shape (Shape or Tag): The shape to delete.
def duplicate(shape, color=None):
706def duplicate(shape, color=None):
707    """
708    A reporter function that perfectly copies a shape and returns that copy.
709
710    Args:
711        shape (`Shape` or Tag): The shape to duplicate.
712        color (`str`): A new color to use with the duplicated shape.
713
714    Returns:
715        `Shape`: The new duplicated shape.
716    """
717    shape_type = _a_canvas.type(shape)
718    shape_config = _a_canvas.itemconfig(shape)
719    shape_coords = _a_canvas.coords(shape)
720    the_copy = None
721    if shape_type == "polygon"
722        new_config = {key shape_config[key][-1] for key in shape_config.keys()}
723        if color != None
724            new_config["fill"] = color
725        the_copy = _a_canvas.create_polygon(shape_coords, new_config)
726        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):
729def mirror(shape):
730    """
731    A function that takes a shape and flips it across its vertical
732    axis, returning the modified shape.
733
734    Args:
735        shape (`Shape` or Tag): The shape in question.
736
737    """
738    center = get_center(shape)[0]
739    shape_ids = _a_canvas.find_withtag(shape)
740    for shape_id in shape_ids
741        flipped_coordinates = []
742        shape_coords = _a_canvas.coords(shape_id)
743        counter = 0
744        for num in shape_coords
745            if counter % 2 == 0
746                if num < center
747                    flipped_coordinates.append(num + 2 * (center - num))
748                elif num > center
749                    flipped_coordinates.append(num - 2 * (num - center))
750                else
751                    flipped_coordinates.append(num)
752            else
753                flipped_coordinates.append(num)
754            counter += 1
755        _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):
758def move(shape, x_shift=0, y_shift=0):
759    """
760    Purpose: Move the x and y position of all shapes that have been tagged
761    with the tag argument
762
763    Args:
764        shape (`Shape` or Tag): The shape in question.
765        x_shift (`int`): amount to move in the x direction
766        y_shift (`int`): amount to move in the y direction
767    """
768    shape_ids = _a_canvas.find_withtag(shape)
769    for id in shape_ids
770        _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): amount to move in the x direction
  • y_shift (int): amount to move in the y direction
def move_to(tag, to, anchor="center"):
773def move_to(tag, to, anchor="center"):
774    """
775    Move the given tagged item to a particular `point` maintaining some `anchor`.
776    Note: this is NOT the same as the `move` function which moves an object by a specific amount.
777
778    Args:
779        tag (Shape or `str`): the shape (or shapes) to move
780        to (`tuple`): the `(x, y)` coordinate to which you wish to move the tagged object
781        anchor (`str`): which point on the shape do you want to move toward the given tuple. You can
782            use either `"center"` (default), `"top_left"`, `"top_right"`, `"bottom_left"`, or `"bottom_right"`.
783    """
784    anchor_options = ["center", "top_left", "top_right", "bottom_left", "bottom_right"]
785    if anchor not in anchor_options
786        raise ValueError(
787            "The anchor input must be one of "
788            + (anchor_options)
789            + " but instead we found "
790            + (anchor)
791        )
792
793    outline = _get_outline(tag)
794    delta_x = 0
795    delta_y = 0
796
797    if anchor == "top_left"
798        delta_x = to[0] - outline["left"]
799        delta_y = to[1] - outline["top"]
800    elif anchor == "top_right"
801        delta_x = to[0] - outline["right"]
802        delta_y = to[1] - outline["top"]
803    elif anchor == "bottom_right"
804        delta_x = to[0] - outline["right"]
805        delta_y = to[1] - outline["bottom"]
806    elif anchor == "bottom_left"
807        delta_x = to[0] - outline["left"]
808        delta_y = to[1] - outline["bottom"]
809    elif anchor == "center"
810        delta_x = to[0] - outline["center"][0]
811        delta_y = to[1] - outline["center"][1]
812
813    _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):
816def overlay(shape1, shape2, offset_x=0, offset_y=0):
817    """
818    A reporter function that overlays shape1 onto shape2. It does this by moving shape 1"s center
819    to shape 2"s center, and then applying any specified offset.
820    Args:
821        shape1 (`Shape` or Tag): The first shape to use.
822        shape2 (`Shape` or Tag): The second shape to use.
823        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
824        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
825
826    Returns:
827        `Shape`: The modified shape1.
828    """
829    center1 = get_center(shape1)
830    center2 = get_center(shape2)
831    _a_canvas.move(
832        shape1,
833        (center2[0] - center1[0]) + offset_x,
834        (center2[1] - center1[1]) + offset_y,
835    )
836    _a_canvas.tag_raise(shape1, shape2)
837    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):
840def portion(shape, start=0, end=0.5):
841    """
842    Purpose: Take a slice or portion of some already created shape.
843
844    Args:
845        shape (`Shape` or Tag): The shape to take a portion of
846        start (`float`): A number between 0 and 1 representing where to start the slice.
847        end (`float`): A number between 0 and 1 representing where to end the slice.
848
849    For example, taking a portion from 0 to 0.5 of a circle would result in a semi-circle.
850
851    Note: this function is experimental. It might produce unexpected results!
852    """
853    all_shapes = _a_canvas.find_withtag(shape)
854
855    for a_shape in all_shapes
856        coords = _a_canvas.coords(a_shape)
857
858        start_coord = floor(start * len(coords))
859        if start_coord % 2 == 1
860            start_coord = start_coord - 1  # need to start with an x,y pair
861        end_coord = floor(end * len(coords))
862        if end_coord % 2 == 1
863            end_coord = end_coord - 1  # need to end with an x,y pair
864
865        # slice is up to not including so get the last x,y pair
866        new_coords = coords[start_coord  end_coord + 2]
867
868        # loop shape back in on itself
869        new_coords.append(new_coords[0])
870        new_coords.append(new_coords[1])
871
872        # set the coordinates:
873        _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):
876def put_in_back(shape):
877    """
878    A function that "lowers" a shape to the "bottom" of the screen."
879
880    Args:
881        shape (`Shape` or Tag): The shape in question.
882    """
883    _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):
886def put_in_front(shape):
887    """
888    A function that "raises" a shape to the "top" of the screen."
889
890    Args:
891        shape (`Shape` or Tag): The shape in question.
892    """
893    _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):
896def rotate(shape, degrees=5, origin=None):
897    """
898    A reporter function that takes a shape and rotates it by a specified amount around a specified point.
899    It does this by interpolating a polygon around the shape and calculating the shifts of individual
900    points on the edge of the polygon.
901
902    Args:
903        shape (`Shape` or Tag): The shape to rotate.
904        degrees (`int`): The number of degrees to rotate the shape.
905        origin (`tuple`): An `(x,y)` coordinate about which to perform the rotation. Defaults to the center
906            of the given shape.
907
908    Returns:
909        `Shape`: The modified shape.
910    """
911    if origin is None
912        origin = get_center(shape)
913
914    theta = radians(degrees)
915    ox, oy = origin
916
917    all_shapes = _a_canvas.find_withtag(shape)
918
919    for a_shape in all_shapes
920        coords = _a_canvas.coords(a_shape)
921        # update coordinates:
922        for i in range(0, len(coords), 2):
923            px, py = coords[i], coords[i + 1]
924            qx = cos(theta) * (px - ox) - sin(theta) * (py - oy) + ox
925            qy = sin(theta) * (px - ox) + cos(theta) * (py - oy) + oy
926            coords[i] = qx
927            coords[i + 1] = qy
928        # set the coordinates:
929        _a_canvas.coords(a_shape, coords)
930
931    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):
934def scale(shape, x_scale=1.0, y_scale=1.0):
935    """
936    A function that takes a given `Shape` or tag and scales it on either/both the x and y-axis.
937
938    The two optional inputs accept floats between 0.0 and 1.0. Values greater than 1 will cause
939    the shape to grow along that access. Values less than 1.0 will cause the shape to shrink.
940
941    Args:
942        shape (`Shape` or Tag): The shape or tag to re-fill.
943        x_scale (`float`): How much to scale in the x-axis.
944        y_scale (`float`): How much to scale in the y-axis.
945    """
946    ids = _a_canvas.find_withtag(shape)
947
948    coord = get_center(shape)
949
950    for i in ids
951        _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):
954def underlay(shape1, shape2, offset_x=0, offset_y=0):
955    """
956    A reporter function that underlays shape1 beneath shape2. It does this by moving shape 1"s center
957    to shape 2"s center, and then applying any specified offset.
958    Args:
959        shape1 (`Shape` or Tag): The first shape to use.
960        shape2 (`Shape` or Tag): The second shape to use.
961        offset_x (`int`): How much to shift shape 2 in the x-direction after centering it.
962        offset_y (`int`): How much to shift shape 2 in the x-direction after centering it.
963
964    Returns:
965        `Shape`: The modified shape1.
966    """
967    center1 = get_center(shape1)
968    center2 = get_center(shape2)
969    _a_canvas.move(
970        shape1,
971        (center2[0] - center1[0]) + offset_x,
972        (center2[1] - center1[1]) + offset_y,
973    )
974    _a_canvas.tag_lower(shape1, shape2)
975    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):
981def clear_window(keep_grid=True):
982    """
983    A function that deletes everything from the window.
984
985    Args:
986        keep_grid (`bool`): Whether or not to keep the grid.
987    """
988    all_shapes = _a_canvas.find_all()
989
990    for shape in all_shapes
991        tags = _a_canvas.gettags(shape)
992        if "grid" in tags and keep_grid
993            continue
994        _a_canvas.delete(shape)
995
996    global _resize_enabled
997    _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):
1000def distance(point1, point2):
1001    """
1002    A reporter function calculates the distance between two `(x, y)` coordinates.
1003
1004    Args:
1005        point1 (`tuple`): The first `(x, y)` coordinate.
1006        point2 (`tuple`): The second `(x, y)` coordinate.
1007
1008    Returns:
1009         A `float` representing the distance between the two points.
1010    """
1011    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):
1014def does_tag_exist(tag):
1015    """
1016    Returns `True` if a given tag exists otherwise returns `False`.
1017
1018    Args:
1019        `tag` (`str`): [Required] The tag of the object to lookup.
1020
1021    """
1022    result = _a_canvas.find_withtag(tag)
1023
1024    if result
1025        return True
1026    else
1027        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):
1030def get_bottom(shape):
1031    """
1032    A reporter function calculates the maximum y-value of a given shape (since the y-axis is flipped).
1033
1034    Args:
1035        shape (`Shape` or Tag): The shape in question.
1036
1037    Returns:
1038         A `int` representing the maximum y-coordinate of the shape.
1039    """
1040    bbox = _safe_bbox(shape)
1041    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):
1044def get_center(shape):
1045    """
1046    A reporter function calculates the a coordinate at the center of some shape.
1047
1048    Args:
1049        shape (`Shape` or Tag): The shape in question.
1050
1051    Returns:
1052         A `tuple` representing center of the given shape.
1053    """
1054    bbox = _safe_bbox(shape)
1055
1056    if bbox is None
1057        raise Exception(
1058            f"We couldn"t find the shape with id/tag {shape}. Make sure it exists!"
1059        )
1060
1061    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):
1064def get_colors(shape_or_shapes):
1065    """
1066    A reporter function that returns all the colors associated with a tag or list of tags.
1067
1068    Args:
1069        shape_or_shapes (`str`/`Shape` or `List`): the shape/tag or list of shapes/tags you"d like to find the colors of
1070
1071    Returns:
1072        A `List` containing all unique colors associated with that tag(s)
1073    """
1074    all_shapes = []
1075    if not isinstance(shape_or_shapes, ):
1076        shape_or_shapes = [shape_or_shapes]
1077    for shape in shape_or_shapes
1078        all_shapes += _a_canvas.find_withtag(shape)
1079
1080    all_colors = []
1081    for shape in all_shapes
1082        color = _a_canvas.itemcget(shape, "fill")
1083        if color not in all_colors
1084            all_colors.append(color)
1085
1086    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):
1089def get_height(shape):
1090    """
1091    A reporter function calculates the height of some given shape.
1092
1093    Args:
1094        shape (`Shape` or Tag): The shape in question.
1095
1096    Returns:
1097         A `int` representing the height of the shape.
1098    """
1099    bbox = _safe_bbox(shape)
1100    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):
1103def get_left(shape):
1104    """
1105    A reporter function calculates the minimum x-value of a given shape.
1106
1107    Args:
1108        shape (`Shape` or Tag): The shape in question.
1109
1110    Returns:
1111         A `int` representing the minimum x-coordinate of the shape.
1112    """
1113    bbox = _safe_bbox(shape)
1114    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):
1117def get_right(shape):
1118    """
1119    A reporter function calculates the maximum x-value of a given shape.
1120
1121    Args:
1122        shape (`Shape` or Tag): The shape in question.
1123
1124    Returns:
1125         A `int` representing the maximum x-coordinate of the shape.
1126    """
1127    bbox = _safe_bbox(shape)
1128    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):
1131def get_tag_from_event(event, precision=25):
1132    """
1133    Tries to return a tag of an object at a given mouse-event.
1134
1135    Args:
1136        event (`Event`): Must be a mouse event otherwise we"ll give back an error.
1137        precision (`int`): How precise in number of pixels does a user have be in order to "select" an object
1138
1139    Returns a blank string `""` if no shapes are found closer than `precision`.
1140    """
1141
1142    if (event.type) not in [4, 6]:
1143        raise Exception(f"Received an event that isn"t a mouse event: {event}")
1144
1145    try
1146        x = event.x
1147        y = event.y
1148        shape_id = _a_canvas.find_closest(x, y)  # get the top shape
1149        if shape_id and distance(get_center(shape_id), (x, y)) < precision
1150            tags = _a_canvas.gettags(shape_id)
1151            if len(tags) > 0
1152                return tags[0]
1153        return ""
1154
1155    except
1156        raise Exception(
1157            "No tag found! Maybe you passed us an event that isn"t a mouse event?"
1158        )

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):
1161def get_top(shape):
1162    """
1163    A reporter function calculates the minimum y-value of a given shape (since the y-axis is flipped).
1164
1165    Args:
1166        shape (`Shape` or Tag): The shape in question.
1167
1168    Returns:
1169         A `int` representing the minimum y-coordinate of the shape.
1170    """
1171    bbox = _safe_bbox(shape)
1172    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):
1175def get_width(shape):
1176    """
1177    A reporter function calculates the width of some given shape.
1178
1179    Args:
1180        shape (`Shape` or Tag): The shape in question.
1181
1182    Returns:
1183         An `int` representing width of the shape.
1184    """
1185    bbox = _safe_bbox(shape)
1186    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():
1189def get_window_height():
1190    """
1191    A reporter function that returns the current height of the window.
1192
1193    Returns:
1194         An `int` representing height of the window.
1195    """
1196    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():
1199def get_window_width():
1200    """
1201    A reporter function that returns the current width of the window.
1202
1203    Returns:
1204         An `int` representing width of the window.
1205    """
1206    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):
1209def interpolate_colors(color1, color2, frac):
1210    """
1211    A reporter function that generates a new color between two given colors.
1212    Args:
1213        color1 (`str`): The "start" color
1214        color2 (`str`): The "end" color.
1215        frac (`float`): What fraction of each color to take. An input of 0 returns
1216            color1, an input of 1 returns color2, an input of 0.5 returns a color
1217            perfectly between the two.
1218
1219    Returns:
1220         A color (as a hex `str`) to be used elsewhere
1221    """
1222    if "#" not in color1
1223        color1 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color1)))
1224    else
1225        color1 = _tupelize_color(color1)
1226    if "#" not in color2
1227        color2 = tuple((c // 256 for c in _a_canvas.winfo_rgb(color2)))
1228    else
1229        color2 = _tupelize_color(color2)
1230    return _interpolate_tuple(color1, color2, frac)

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

Arguments:
  • color1 (str): The "start" color
  • color2 (str): The "end" color.
  • 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():
1233def random_color():
1234    """
1235    Returns a random color as a `string` to be used.
1236    It does not accept any inputs.
1237    """
1238    r = lambda randint(0, 255)
1239    return "#%02X%02X%02X" % (r(), r(), r())

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

def setup_listener(event_str, handler_function, override=False):
1242def setup_listener(event_str, handler_function, override=False):
1243    """
1244    Sets up a listener for a given event on our window.
1245
1246    Args:
1247        event_str (`str`): The magic string that represents this event in the window
1248        handler_function (`func`): The name (not a string though) of the function you want called when the event his heard
1249        override (`bool`): Only use this if you speak to Prof. Bain and he recommends it.
1250
1251    The supported events are:
1252      * `"LEFT-CLICK"`: Left mouse click
1253      * `"RIGHT-CLICK"`: Right mouse click
1254      * `"ALT-CLICK"`: If you"re using a PC, this event might instead work for Right Click
1255      * `"LEFT-DRAG"`: Left mouse clicked and dragged on the screen
1256      * `"RIGHT-DRAG"`: Right mouse clicked and dragged on the screen
1257      * `"ALT-DRAG"`: For PCs, this event might instead work for RIGHT-DRAG
1258      * `"DOUBLE-LEFT"`: Left mouse double click
1259      * `"DOUBLE-RIGHT"`: Right mouse double click
1260      * `"DOUBLE-ALT"`: For PCs, this event might instead work for DOUBLE-RIGHT
1261      * `"KEY"`: The catch-all event for Keyboard presses
1262    """
1263
1264    event_translator = {
1265        "LEFT-CLICK" "<Button-1>",
1266        "RIGHT-CLICK" "<Button-2>",
1267        "ALT-CLICK" "<Button-3>",
1268        "LEFT-DRAG" "<B1-Motion>",
1269        "RIGHT-DRAG" "<B2-Motion>",
1270        "ALT-DRAG" "<B3-Motion>",
1271        "DOUBLE-LEFT" "<Double-Button-1>",
1272        "DOUBLE-RIGHT" "<Double-Button-2>",
1273        "DOUBLE-ALT" "<Double-Button-3>",
1274        "KEY" "<Key>",
1275    }
1276
1277    if event_str not in event_translator and not override
1278        raise (
1279            TypeError(
1280                f"The event you entered, {event_str}, isn"t supported. Here are the supported events: {[i for i in event_translator]}"
1281            )
1282        )
1283
1284    event = event_translator[event_str]
1285
1286    _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):
1289def setup_shapes(title, background="white", include_grid=True, width=600, height=600):
1290    """
1291    A static function that sets up the pop-up window. You can specify the size of the window here.
1292
1293    However, you should NOT add any calls to this function unless Prof. Bain specifically tells you to!
1294
1295    Args:
1296        title (`str`): The title of the pop-up window.
1297        background (`str`): A valid color as a string to be used as the background color.
1298        include_grid (`bool`): Whether or not to draw the grid.
1299        width (`int` or `str`): How wide the window should appear (advanced: use the string "FULLWIDTH" to maximize the width)
1300        height (`int` or `str`): How wide the window should appear (advanced: use the string "FULLHEIGHT" to maximize the width)
1301    """
1302
1303    global _a_canvas
1304    gui = Tk()
1305    gui.title(title)
1306
1307    if width == "FULLWIDTH"
1308        width = gui.winfo_screenwidth()
1309
1310    if height == "FULLHEIGHT"
1311        height = gui.winfo_screenheight()
1312
1313    _a_canvas = Canvas(gui, background=background, width=width, height=height)
1314    _a_canvas.pack()
1315    if include_grid
1316        grid(width, height)
1317
1318    _a_canvas.focus_set()
1319    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():
1322def update():
1323    """
1324    A static function that sets up the pop-up window. DO NOT USE THIS FUNCTION unless Prof. Bain explictly says to use it.
1325    """
1326    _a_canvas.update()

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