cs110_ex5

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

A reporter function that draws a rectangle.

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

Shape: The rectangle that was created.

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

A reporter function that draws a square.

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

Shape: The square that was created.

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

A reporter function that draws an oval.

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

Shape: The oval that was created.

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

Reporter function that draws a cloud to the screen.

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

Shape: The cloud that was created.

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

A reporter function that draws a circle.

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

Shape: The circle that was created.

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

A reporter function that draws a circle.

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

Shape: The wedge that was created.

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

A reporter function that draws a triangle.

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

Shape: The triangle that was created.

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

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

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

Shape: The line that was created.

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

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

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

Shape: The arc that was created.

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

A reporter function that draws a rectangle.

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

Shape: The shape that was created.

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

A reporter function that draws a star.

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

Shape: The star that was created.

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

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

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

Shape: The polygon that was created.

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

A reporter function that draws a spiral.

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

Shape: The spiral that was created.

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

Draws a pixel art design!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Shape: The modified shape1.

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

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

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

Shape: The modified shape1.

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

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

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

Shape: The modified shape1.

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

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

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

Shape: The modified shape1.

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

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

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

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

Shape: The modified shape1.

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

A function that deletes a shape from our screen.

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

A function that deletes everything from the window.

Arguments:
  • keep_grid (bool): Whether or not to keep the grid.
def duplicate(shape, color=None):
724def duplicate(shape, color=None):
725    """
726    A reporter function that perfectly copies a shape and returns that copy.
727
728    Args:
729        shape (`Shape` or Tag): The shape to duplicate.
730        color (`str`): A new color to use with the duplicated shape.
731
732    Returns:
733        `Shape`: The new duplicated shape.
734    """
735    shape_type = _a_canvas.type(shape)
736    shape_config = _a_canvas.itemconfig(shape)
737    shape_coords = _a_canvas.coords(shape)
738    the_copy = None
739    if shape_type == "polygon"
740        new_config = {key shape_config[key][-1] for key in shape_config.keys()}
741        if color != None
742            new_config["fill"] = color
743        the_copy = _a_canvas.create_polygon(shape_coords, new_config)
744        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):
747def mirror(shape):
748    """
749    A function that takes a shape and flips it across its vertical
750    axis, returning the modified shape.
751
752    Args:
753        shape (`Shape` or Tag): The shape in question.
754
755    """
756    center = get_center(shape)[0]
757    shape_ids = _a_canvas.find_withtag(shape)
758    for shape_id in shape_ids
759        flipped_coordinates = []
760        shape_coords = _a_canvas.coords(shape_id)
761        counter = 0
762        for num in shape_coords
763            if counter % 2 == 0
764                if num < center
765                    flipped_coordinates.append(num + 2 * (center - num))
766                elif num > center
767                    flipped_coordinates.append(num - 2 * (num - center))
768                else
769                    flipped_coordinates.append(num)
770            else
771                flipped_coordinates.append(num)
772            counter += 1
773        _a_canvas.coords(shape_id, flipped_coordinates)

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

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

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

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

Shape: The modified shape.

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

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

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

A float representing the distance between the two points.

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

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

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

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

Change the fill color of a tagged object.

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

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

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

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

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

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

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

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

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

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

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

A tuple representing center of the given shape.

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

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

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

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

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

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

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

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

def get_left(shape):
958def get_left(shape):
959    """
960    A reporter function calculates the minimum x-value of a given shape.
961
962    Args:
963        shape (`Shape` or Tag): The shape in question.
964
965    Returns:
966         A `int` representing the minimum x-coordinate of the shape.
967    """
968    bbox = _safe_bbox(shape)
969    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):
972def get_right(shape):
973    """
974    A reporter function calculates the maximum x-value of a given shape.
975
976    Args:
977        shape (`Shape` or Tag): The shape in question.
978
979    Returns:
980         A `int` representing the maximum x-coordinate of the shape.
981    """
982    bbox = _safe_bbox(shape)
983    return bbox[2]

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

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

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

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

A reporter function calculates the height of some given shape.

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

A int representing the height of the shape.

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

A reporter function calculates the width of some given shape.

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

An int representing width of the shape.

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

Draws a grid on a screen with intervals of 100.

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

Returns True if a given tag exists otherwise returns False.

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

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

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

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