Selaa lähdekoodia

Add 'karel_asset.py'

Init
tBKwtWS 1 päivä sitten
vanhempi
sitoutus
e8fa491561
1 muutettua tiedostoa jossa 511 lisäystä ja 0 poistoa
  1. 511 0
      karel_asset.py

+ 511 - 0
karel_asset.py

@@ -0,0 +1,511 @@
+import operator
+import logging
+import random
+
+# Logging to console
+logger = logging.getLogger(__name__)
+logging.basicConfig(level=logging.INFO) # Set loglevel to INFO or higher to prevent console spam.
+
+
+"""
+Helper functions
+"""
+# Return some hex colour
+"""
+CIP bug: https://codeinplace.stanford.edu/cip6/report?post=ac7c4ffd-1f90-475a-b4ee-2e5b73c5348f
+from matplotlib import colors
+import decimal
+
+def get_random_colour():
+    return decimal.Decimal(random.randrange(0,10)/10), decimal.Decimal(random.randrange(0,10)/10), decimal.Decimal(random.randrange(0,10)/10)
+
+colour = colors.rgb2hex((get_random_colour()))
+background = colors.rgb2hex((get_random_colour()))
+"""
+def generate_random_colour():
+    rgb_values = [random.randrange(256), random.randrange(256), random.randrange(256)]
+    hex_colours = [hex(value)[2:] for value in rgb_values]  # Strip the '0x' prefix
+    for i in range(len(hex_colours)):
+        if len(str(hex_colours[i])) == 1:
+            hex_colours[i] = f"0{hex_colours[i]}"
+    return '#' + ''.join(hex_colours)
+
+"""
+Karel functions
+"""
+# Erase a passed Karel from the canvas
+def erase_karel(karel):
+    canvas = karel[1][0]
+
+    for shape in karel[0].values():
+        canvas.delete(shape)
+    logger.debug(f"Erased karel: {karel}")
+
+# Move a passed Karel on the canvas
+"""
+Waiting for Stanford to fix a bug in the environment
+CIP bug: https://codeinplace.stanford.edu/cip6/report?post=7043ece9-7653-4e39-8a63-5f4544b1d74b
+
+def move_karel(canvas, karel, dx, dy):
+    for shape in karel[0].values():
+        canvas.move(shape, dx, dy)
+    logger.debug(f"Moved: {karel} by {dx} horizontally, {dy} vertically")
+"""
+def move_karel(karel, dx, dy):
+    canvas = karel[1][0]
+
+    erase_karel(karel)
+
+    # Update coordinates in list
+    karel[1][1] += dx
+    karel[1][2] += dy
+
+    new_karel = draw_karel(karel[1][0], )
+    logger.debug(f"Moved: {karel} by {dx} horizontally, {dy} vertically, to {new_karel}")
+    return new_karel
+
+# Recolour a passed Karel on the canvas
+"""
+Waiting for Stanford to fix a bug in the environment
+CIP bug: https://codeinplace.stanford.edu/cip6/report?post=c36ed931-3019-4830-8ba6-655c1a513471
+
+def recolour_karel(canvas, karel, colour:str="black", background:str="white"):
+    for name, shape in karel[0].items():   # Loop over Karel dict
+        if name.endswith("_fill"): # Background shape
+            canvas.set_color(shape, background)
+            canvas.set_outline_color(shape, background)
+        else:   # Foreground shape
+            if name.endswith("_line") or name.endswith("_corner") or name == "mouth":
+                canvas.set_color(shape, colour)
+            elif name == "eye":
+                #canvas.set_color(shape, "transparent")
+                canvas.set_outline_color(shape, colour)
+            else:   # Legs and feet
+                canvas.set_color(shape, colour)
+                canvas.set_outline_color(shape, colour)
+"""
+def recolour_karel(karel, colour:str="black", background:str="white"):
+    # Random colours
+    if colour == "random":
+        colour = generate_random_colour()
+    if background == "random":
+        background = generate_random_colour()
+
+    # Update colours in list
+    karel[1][5] = colour
+    karel[1][6] = background
+
+    erase_karel(karel)
+    new_karel = draw_karel(karel[1][0], karel[1][1], karel[1][2], karel[1][3], karel[1][4], karel[1][5], karel[1][6], karel[1][7])
+
+    logger.debug(f"Re-coloured Karel: {karel} with {colour} and {background} to {new_karel}")
+    return new_karel
+
+# Draw a Karel
+def draw_karel(
+        canvas,
+        centre_x:int=25,
+        centre_y:int=25,
+        size:int=50,
+        orientation:str="east",
+        colour:str="black",
+        background:str="white",
+        transparent:bool=False
+    ):
+
+    # Random colours
+    if colour == "random":
+        colour = generate_random_colour()
+    if background == "random":
+        background = generate_random_colour()
+    
+    # Body constants
+    MARGIN = size / 8
+    APPENDAGE_MULTIPLIER = MARGIN * 0.6
+
+    ''' Flipper case
+    In order to be able to flip Karel, the operands in the forumlas must be able to switch around.
+    Orientations are in relation to the centre of Karel.
+    '''
+    match orientation.lower():     
+        case "east" | "south-flipped":
+            left_operand = operator.sub     # Left / Top
+            top_operand = operator.sub      # Top / Left
+            right_operand = operator.add    # Right / Bottom
+            bottom_operand = operator.add   # Bottom / Right
+        case "east-flipped" | "south":
+            left_operand = operator.sub     # Left / Top
+            top_operand = operator.add      # Bottom / Right
+            right_operand = operator.add    # Right / Bottom
+            bottom_operand = operator.sub   # Top / Left
+        case "west" | "north-flipped":
+            left_operand = operator.add     # Right 
+            top_operand = operator.add      # Bottom
+            right_operand = operator.sub    # Left
+            bottom_operand = operator.sub   # Top
+        case "west-flipped" | "north":
+            left_operand = operator.add     # Right / Bottom
+            top_operand = operator.sub      # Top / Left
+            right_operand = operator.sub    # Left / Top
+            bottom_operand = operator.add   # Bottom / Right
+    
+    # Coords case
+    if orientation.lower() == "north" or orientation.lower() == "north-flipped" or orientation.lower() == "south" or orientation.lower() == "south-flipped":
+        temp_x = centre_x
+        centre_x = centre_y
+        centre_y = temp_x
+        #pass
+
+
+    # Borders
+    left = left_operand(centre_x, size / 2)
+    top = top_operand(centre_y, size / 2)
+    right = right_operand(centre_x, size / 2)
+    bottom = bottom_operand(centre_y, size / 2)
+    margin = size / 8
+    appendage_multiplier = margin * 0.6
+
+    # Body borders
+    body_left = left_operand(centre_x, size / 3)
+    body_top = top
+    body_right = right_operand(centre_x, size / 3)
+    body_bottom = bottom_operand(centre_y, size / 2.6)
+    eye_left = right_operand(body_left, margin)
+    eye_top = bottom_operand(body_top, margin)
+    eye_right = left_operand(body_right, margin)
+    eye_bottom = top_operand(body_bottom, margin * 2)
+
+    # Body coordinates
+    top_left_corner = body_left, body_top
+    left_diagonal_top = body_left, top_operand(body_bottom, margin)
+    left_diagonal_bottom = eye_left, body_bottom
+    right_diagonal_top = eye_right, body_top
+    right_diagonal_bottom = body_right, bottom_operand(body_top, margin)
+    bottom_right_corner = body_right, body_bottom
+    mouth_left_corner = centre_x, bottom_operand(eye_bottom, margin)
+    mouth_right_corner = eye_right, mouth_left_corner[1]
+
+    # Left appendage borders
+    leftLeg_left = left_operand(body_left, margin)
+    leftLeg_top = eye_bottom
+    leftLeg_right = body_left
+    leftLeg_bottom = bottom_operand(leftLeg_top, appendage_multiplier)
+    leftFoot_left = leftLeg_left
+    leftFoot_top = leftLeg_bottom
+    leftFoot_right = right_operand(leftLeg_left, appendage_multiplier)
+    leftFoot_bottom = bottom_operand(leftFoot_top, appendage_multiplier)
+
+    # Right appendage borders
+    rightLeg_left = centre_x
+    rightLeg_top = body_bottom
+    rightLeg_right = right_operand(rightLeg_left, appendage_multiplier)
+    rightLeg_bottom = bottom
+    rightFoot_left = rightLeg_right
+    rightFoot_top = top_operand(bottom, appendage_multiplier)
+    rigthFoot_right = right_operand(rightLeg_right, appendage_multiplier)
+    rightFoot_bottom = bottom
+
+
+    # Draw Karel
+    match orientation.lower():
+        case "east" | "east-flipped" | "west" | "west-flipped":
+            if not transparent:
+                # Meat
+                top_fill = canvas.create_rectangle(
+                    top_left_corner[0],
+                    top_left_corner[1],
+                    right_diagonal_top[0],
+                    eye_top,
+                    background,
+                    background
+                )
+                top_corner_fill = canvas.create_polygon(
+                    right_diagonal_top[0] , right_diagonal_top[1],
+                    right_diagonal_bottom[0], right_diagonal_bottom[1],
+                    eye_right, eye_top,
+                    color = background,
+                    outline = background
+                )
+                left_fill = canvas.create_rectangle(
+                    top_left_corner[0],
+                    eye_top,
+                    eye_left,
+                    left_diagonal_top[1],
+                    background,
+                    background
+                )
+                right_fill = canvas.create_rectangle(
+                    eye_right,
+                    eye_top,
+                    right_diagonal_bottom[0],
+                    eye_bottom,
+                    background,
+                    background
+                )
+                bottom_fill = canvas.create_rectangle(
+                    eye_left,
+                    eye_bottom,
+                    bottom_right_corner[0],
+                    bottom_right_corner[1],
+                    background,
+                    background
+                )
+                bottom_corner_fill = canvas.create_polygon(
+                    left_diagonal_top[0], left_diagonal_top[1],
+                    eye_left, left_diagonal_top[1],
+                    left_diagonal_bottom[0], left_diagonal_bottom[1],
+                    color = background,
+                    outline = background
+                )
+            
+            # Outlines
+            top_line = canvas.create_line(
+                top_left_corner[0], top_left_corner[1],
+                right_diagonal_top[0], right_diagonal_top[1],
+                colour
+            )
+            top_corner = canvas.create_line(
+                right_diagonal_top[0], right_diagonal_top[1],
+                right_diagonal_bottom[0], right_diagonal_bottom[1],
+                colour
+            )
+            left_line = canvas.create_line(
+                top_left_corner[0], top_left_corner[1],
+                left_diagonal_top[0], left_diagonal_top[1],
+                colour
+            )
+            bottom_corner = canvas.create_line(
+                left_diagonal_top[0], left_diagonal_top[1],
+                left_diagonal_bottom[0], left_diagonal_bottom[1],
+                colour
+            )
+            bottom_line = canvas.create_line(
+                left_diagonal_bottom[0], left_diagonal_bottom[1],
+                bottom_right_corner[0], bottom_right_corner[1],
+                colour
+            )
+            right_line = canvas.create_line(
+                right_diagonal_bottom[0], right_diagonal_bottom[1],
+                bottom_right_corner[0], bottom_right_corner[1],
+                colour
+            )
+            left_leg = canvas.create_rectangle(
+                leftLeg_left,
+                leftLeg_top,
+                leftLeg_right,
+                leftLeg_bottom,
+                colour,
+                colour
+            )
+            left_foot = canvas.create_rectangle(
+                leftFoot_left,
+                leftFoot_top,
+                leftFoot_right,
+                leftFoot_bottom,
+                colour,
+                colour
+            )
+            right_leg = canvas.create_rectangle(
+                rightLeg_left,
+                rightLeg_top,
+                rightLeg_right,
+                rightLeg_bottom,
+                colour,
+                colour
+            )
+            right_foot = canvas.create_rectangle(
+                rightFoot_left,
+                rightFoot_top,
+                rigthFoot_right,
+                rightFoot_bottom,
+                colour,
+                colour
+            )
+            eye = canvas.create_rectangle(
+                eye_left,
+                eye_top,
+                eye_right,
+                eye_bottom,
+                "transparent",
+                colour,
+            )
+            mouth = canvas.create_line(
+                mouth_left_corner[0], mouth_left_corner[1],
+                mouth_right_corner[0], mouth_right_corner[1],
+                colour
+            )
+        
+        case "north" | "north-flipped" | "south" | "south-flipped":
+            if not transparent:
+                # Meat
+                top_fill = canvas.create_rectangle(
+
+                    top_left_corner[1],             # Top Y
+                    right_diagonal_top[0],          # Right X
+                    eye_top,                        # Bottom Y
+                    top_left_corner[0],             # Left X
+                    background,
+                    background
+                )
+                top_corner_fill = canvas.create_polygon(
+                    right_diagonal_top[1] , right_diagonal_top[0],
+                    right_diagonal_bottom[1], right_diagonal_bottom[0],
+                    eye_top, eye_right,
+                    color = background,
+                    outline = background
+                )
+                left_fill = canvas.create_rectangle(
+                    
+                    eye_top,
+                    eye_left,
+                    left_diagonal_top[1],
+                    top_left_corner[0],
+                    background,
+                    background
+                )
+                right_fill = canvas.create_rectangle(
+                    
+                    eye_top,
+                    right_diagonal_bottom[0],
+                    eye_bottom,
+                    eye_right,
+                    background,
+                    background
+                )
+                bottom_fill = canvas.create_rectangle(
+                    
+                    eye_bottom,
+                    bottom_right_corner[0],
+                    bottom_right_corner[1],
+                    eye_left,
+                    background,
+                    background
+                )
+                bottom_corner_fill = canvas.create_polygon(
+                    left_diagonal_top[1], left_diagonal_top[0],
+                    left_diagonal_top[1], eye_left,
+                    left_diagonal_bottom[1], left_diagonal_bottom[0],
+                    color = background,
+                    outline = background
+                )
+            
+            # Outlines
+            top_line = canvas.create_line(
+                top_left_corner[1], top_left_corner[0],
+                right_diagonal_top[1], right_diagonal_top[0],
+                colour
+            )
+            top_corner = canvas.create_line(
+                right_diagonal_top[1], right_diagonal_top[0],
+                right_diagonal_bottom[1], right_diagonal_bottom[0],
+                colour
+            )
+            left_line = canvas.create_line(
+                top_left_corner[1], top_left_corner[0],
+                left_diagonal_top[1], left_diagonal_top[0],
+                colour
+            )
+            bottom_corner = canvas.create_line(
+                left_diagonal_top[1], left_diagonal_top[0],
+                left_diagonal_bottom[1], left_diagonal_bottom[0],
+                colour
+            )
+            bottom_line = canvas.create_line(
+                left_diagonal_bottom[1], left_diagonal_bottom[0],
+                bottom_right_corner[1], bottom_right_corner[0],
+                colour
+            )
+            right_line = canvas.create_line(
+                right_diagonal_bottom[1], right_diagonal_bottom[0],
+                bottom_right_corner[1], bottom_right_corner[0],
+                colour
+            )
+            left_leg = canvas.create_rectangle(
+                leftLeg_top,
+                leftLeg_right,
+                leftLeg_bottom,
+                leftLeg_left,
+                colour,
+                colour
+            )
+            left_foot = canvas.create_rectangle(
+                leftFoot_top,
+                leftFoot_right,
+                leftFoot_bottom,
+                leftFoot_left,
+                colour,
+                colour
+            )
+            right_leg = canvas.create_rectangle(
+                rightLeg_top,
+                rightLeg_right,
+                rightLeg_bottom,
+                rightLeg_left,
+                colour,
+                colour
+            )
+            right_foot = canvas.create_rectangle(
+                rightFoot_top,
+                rigthFoot_right,
+                rightFoot_bottom,
+                rightFoot_left,
+                colour,
+                colour
+            )
+            eye = canvas.create_rectangle(
+                eye_top,
+                eye_right,
+                eye_bottom,
+                eye_left,
+                "transparent",
+                colour,
+            )
+            mouth = canvas.create_line(
+                mouth_left_corner[1], mouth_left_corner[0],
+                mouth_right_corner[1], mouth_right_corner[0],
+                colour
+            )
+
+    # Return each object so it can later be altered/destroyed
+    if transparent:
+        shapes = {
+            "top_line": top_line,
+            "top_corner": top_corner,
+            "left_line": left_line,
+            "bottom_corner": bottom_corner,
+            "bottom_line": bottom_line,
+            "right_line": right_line,
+            "left_leg": left_leg,
+            "left_foot": left_foot,
+            "right_foot": right_foot,
+            "right_leg": right_leg,
+            "right_foot": right_foot,
+            "eye": eye,
+            "mouth": mouth
+        }
+    else:   # Not transparent
+        shapes = {
+            "top_fill": top_fill,
+            "top_corner_fill": top_corner_fill,
+            "left_fill": left_fill,
+            "right_fill": right_fill,
+            "bottom_fill": bottom_fill,
+            "bottom_corner_fill": bottom_corner_fill,
+            "top_line": top_line,
+            "top_corner": top_corner,
+            "left_line": left_line,
+            "bottom_corner": bottom_corner,
+            "bottom_line": bottom_line,
+            "right_line": right_line,
+            "left_leg": left_leg,
+            "left_foot": left_foot,
+            "right_foot": right_foot,
+            "right_leg": right_leg,
+            "right_foot": right_foot,
+            "eye": eye,
+            "mouth": mouth
+        }
+
+    arguments = [canvas, centre_x, centre_y, size, orientation, colour, background, transparent]
+    logger.debug(f"Created Karel: {shapes, arguments}")
+    return [shapes, arguments]