|
|
@@ -1,634 +1,248 @@
|
|
|
-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
|
|
|
+from karel.stanfordkarel import *
|
|
|
"""
|
|
|
-# Return some hex colour
|
|
|
-"""
|
|
|
-Waiting for Stanford to fix a bug in the environment
|
|
|
-CIP bug: https://codeinplace.stanford.edu/cip6/report?post=ac7c4ffd-1f90-475a-b4ee-2e5b73c5348f
|
|
|
+Inspired by John Conways "Game of Life" and "Biogenesis" by Joan Queralt Molina.
|
|
|
|
|
|
-from matplotlib import colors
|
|
|
-import decimal
|
|
|
+The three phases of life start with Karel seeding a few fountains of youth, represented by beepers on black patches of "land".
|
|
|
|
|
|
-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)
|
|
|
+Than the circle of life commences, with Karel being the fickle hand of god that moves randomly over the board,
|
|
|
+at certain times deciding to bless or smite the life she passes.
|
|
|
+Being blessed means growth and changing colour, while smiting leads to permanent death or being composted.
|
|
|
+After several steps of growth it is possible for life to reproduce, and spread to other patches of land;
|
|
|
+possible in the process overwhelming neighboring life.
|
|
|
|
|
|
-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)
|
|
|
+After an ungodly amount of divine acts, in the final ascension phase, the fountains are collected by their creatress Karel;
|
|
|
+leaving only the result of the onslaught of the competition that is life.
|
|
|
|
|
|
+TIP: Run at top speed to spare your own life from wasting away...
|
|
|
"""
|
|
|
-Karel functions
|
|
|
-"""
|
|
|
-# Erase a passed Karel from the canvas
|
|
|
-def erase_asset(asset):
|
|
|
- canvas = asset[1][0]
|
|
|
|
|
|
- for shape in asset[0].values():
|
|
|
- canvas.delete(shape)
|
|
|
- logger.debug(f"Erased asset: {asset}")
|
|
|
-
|
|
|
-# 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, x, y):
|
|
|
- for shape in karel[0].values():
|
|
|
- canvas.move(shape, x, y)
|
|
|
- logger.debug(f"Moved: {karel} by {x} horizontally, {y} vertically")
|
|
|
-"""
|
|
|
-# Move a passed Karel relative to previous position
|
|
|
-def relative_move_asset(asset, x:int=0, y:int=0):
|
|
|
- # Update coordinates in list
|
|
|
- asset[1][1] += x
|
|
|
- asset[1][2] += y
|
|
|
-
|
|
|
- erase_asset(asset)
|
|
|
- new_asset = draw_karel(asset[1][0], asset[1][1], asset[1][2], asset[1][3], asset[1][4], asset[1][5], asset[1][6], asset[1][7])
|
|
|
-
|
|
|
- logger.debug(f"Moved: {asset} by {x} horizontally, {y} vertically, to {new_asset}")
|
|
|
- return new_asset
|
|
|
-
|
|
|
-# Move a passed Karel in relation to her orientation
|
|
|
-def orientation_move_asset(asset, direction, amount):
|
|
|
- # Direction translation
|
|
|
- if asset[1][4].startswith("east"):
|
|
|
- if direction.lower() == "forward" or direction.lower() == "front":
|
|
|
- asset[1][1] += amount
|
|
|
- if direction.lower() == "left":
|
|
|
- asset[1][2] -= amount
|
|
|
- if direction.lower() == "right":
|
|
|
- asset[1][2] += amount
|
|
|
- if direction.lower() == "backward" or direction.lower() == "back":
|
|
|
- asset[1][1] -= amount
|
|
|
- if asset[1][4].startswith("north"):
|
|
|
- if direction.lower() == "forward" or direction.lower() == "front":
|
|
|
- asset[1][2] -= amount
|
|
|
- if direction.lower() == "left":
|
|
|
- asset[1][1] -= amount
|
|
|
- if direction.lower() == "right":
|
|
|
- asset[1][1] += amount
|
|
|
- if direction.lower() == "backward" or direction.lower() == "back":
|
|
|
- asset[1][2] += amount
|
|
|
- if asset[1][4].startswith("west"):
|
|
|
- if direction.lower() == "forward" or direction.lower() == "front":
|
|
|
- asset[1][1] -= amount
|
|
|
- if direction.lower() == "left":
|
|
|
- asset[1][2] += amount
|
|
|
- if direction.lower() == "right":
|
|
|
- asset[1][2] -= amount
|
|
|
- if direction.lower() == "backward" or direction.lower() == "back":
|
|
|
- asset[1][1] += amount
|
|
|
- if asset[1][4].startswith("south"):
|
|
|
- if direction.lower() == "forward" or direction.lower() == "front":
|
|
|
- asset[1][2] += amount
|
|
|
- if direction.lower() == "left":
|
|
|
- asset[1][1] += amount
|
|
|
- if direction.lower() == "right":
|
|
|
- asset[1][1] -= amount
|
|
|
- if direction.lower() == "backward" or direction.lower() == "back":
|
|
|
- asset[1][2] -= amount
|
|
|
-
|
|
|
- erase_asset(asset)
|
|
|
- new_karel = draw_karel(asset[1][0], asset[1][1], asset[1][2], asset[1][3], asset[1][4], asset[1][5], asset[1][6], asset[1][7])
|
|
|
-
|
|
|
- logger.debug(f"Moved: {asset} {direction} by {amount} as {new_karel}")
|
|
|
- return new_karel
|
|
|
-
|
|
|
-# Move a passed Karel to new coordinates
|
|
|
-def absolute_move_karel(asset, x:int=0, y:int=0):
|
|
|
- # Update coordinates in list
|
|
|
- asset[1][1] = x
|
|
|
- asset[1][2] = y
|
|
|
-
|
|
|
- erase_asset(asset)
|
|
|
- new_karel = draw_karel(asset[1][0], asset[1][1], asset[1][2], asset[1][3], asset[1][4], asset[1][5], asset[1][6], asset[1][7])
|
|
|
-
|
|
|
- logger.debug(f"Moved: {asset} by {x} horizontally, {y} vertically, to {new_karel}")
|
|
|
- return new_karel
|
|
|
-
|
|
|
-# Change the orientation of a passed Karel
|
|
|
-def rotate_karel(asset, direction):
|
|
|
- # Relative turn
|
|
|
- if direction == "right" or direction == "left":
|
|
|
- # East
|
|
|
- if asset[1][4] == "east":
|
|
|
- if direction == "right":
|
|
|
- asset[1][4] = "south"
|
|
|
- if direction == "left":
|
|
|
- asset[1][4] = "north"
|
|
|
- elif asset[1][4] == "east-flipped":
|
|
|
- if direction == "right":
|
|
|
- asset[1][4] = "south-flipped"
|
|
|
- if direction == "left":
|
|
|
- asset[1][4] = "north-flipped"
|
|
|
-
|
|
|
- # North
|
|
|
- elif asset[1][4] == "north":
|
|
|
- if direction == "right":
|
|
|
- asset[1][4] = "east"
|
|
|
- if direction == "left":
|
|
|
- asset[1][4] = "west"
|
|
|
- elif asset[1][4] == "north-flipped":
|
|
|
- if direction == "right":
|
|
|
- asset[1][4] = "east-flipped"
|
|
|
- if direction == "left":
|
|
|
- asset[1][4] = "west-flipped"
|
|
|
-
|
|
|
- # West
|
|
|
- elif asset[1][4] == "west":
|
|
|
- if direction == "right":
|
|
|
- asset[1][4] = "north"
|
|
|
- if direction == "left":
|
|
|
- asset[1][4] = "soutch"
|
|
|
- elif asset[1][4] == "west-flipped":
|
|
|
- if direction == "right":
|
|
|
- asset[1][4] = "north-flipped"
|
|
|
- if direction == "left":
|
|
|
- asset[1][4] = "south-flipped"
|
|
|
-
|
|
|
- # South
|
|
|
- elif asset[1][4] == "south":
|
|
|
- if direction == "right":
|
|
|
- asset[1][4] = "west"
|
|
|
- if direction == "left":
|
|
|
- asset[1][4] = "east"
|
|
|
- elif asset[1][4] == "north-flipped":
|
|
|
- if direction == "right":
|
|
|
- asset[1][4] = "west-flipped"
|
|
|
- if direction == "left":
|
|
|
- asset[1][4] = "east-flipped"
|
|
|
-
|
|
|
- # Absolute rotation
|
|
|
- elif direction == "east" or direction == "east-flipped" or direction == "north" or direction == "north-flipped" or direction == "west" or direction == "west-flipped" or direction == "south" or direction == "south-flipped":
|
|
|
- asset[1][4] = direction
|
|
|
+## Helper functions:
|
|
|
+# Turn left trice:
|
|
|
+def turn_right():
|
|
|
+ for i in range(3):
|
|
|
+ turn_left()
|
|
|
+
|
|
|
+# Keep moving while not blocked:
|
|
|
+def move_till_end():
|
|
|
+ while front_is_clear():
|
|
|
+ move()
|
|
|
+
|
|
|
+# 20% chance to move:
|
|
|
+def perhaps_move():
|
|
|
+ if random(0.2):
|
|
|
+ move()
|
|
|
+
|
|
|
+def pick_if_present():
|
|
|
+ if beepers_present():
|
|
|
+ pick_beeper()
|
|
|
+
|
|
|
+# Move to next row:
|
|
|
+def next_row():
|
|
|
+ # Turn west:
|
|
|
+ if facing_east():
|
|
|
+ turn_left()
|
|
|
+ if front_is_clear():
|
|
|
+ move()
|
|
|
+ turn_left()
|
|
|
+
|
|
|
+ # Turn east
|
|
|
+ else: # Facing west
|
|
|
+ turn_right()
|
|
|
+ if front_is_clear():
|
|
|
+ move()
|
|
|
+ turn_right()
|
|
|
+
|
|
|
+def wall_check():
|
|
|
+ if front_is_blocked(): # End of row
|
|
|
+ next_row()
|
|
|
+
|
|
|
+# Move to southeast corner:
|
|
|
+def genesis_position():
|
|
|
+ # Move south:
|
|
|
+ while not_facing_south():
|
|
|
+ turn_left()
|
|
|
+ move_till_end()
|
|
|
+
|
|
|
+ # Move west:
|
|
|
+ while not_facing_west():
|
|
|
+ turn_left()
|
|
|
+ move_till_end()
|
|
|
+
|
|
|
+ # Turn:
|
|
|
+ while not_facing_east():
|
|
|
+ turn_left()
|
|
|
+
|
|
|
+# Do not face walls, and sometimes change direction:
|
|
|
+def orient():
|
|
|
+
|
|
|
+ # Perhaps turn
|
|
|
+ if random(0.1): # 10% chance to turn
|
|
|
+ if random(0.5): # 50% chance to go right or left
|
|
|
+ turn_left()
|
|
|
+ else:
|
|
|
+ turn_right()
|
|
|
|
|
|
- # Syntax error
|
|
|
- else:
|
|
|
- logger.error(f"Invalid rotation direction: {direction}")
|
|
|
+ # Make sure not to face an obstruction
|
|
|
+ while front_is_blocked():
|
|
|
+ turn_left()
|
|
|
|
|
|
- erase_asset(asset)
|
|
|
- new_karel = draw_karel(asset[1][0], asset[1][1], asset[1][2], asset[1][3], asset[1][4], asset[1][5], asset[1][6], asset[1][7])
|
|
|
|
|
|
- logger.debug(f"Rotated Karel: {asset} by {direction} as {asset[1][4]} to {new_karel}")
|
|
|
- return new_karel
|
|
|
+## Main functions:
|
|
|
+# According to biologists, the sole goal of life.
|
|
|
+def reproduce():
|
|
|
+ move()
|
|
|
+ if no_beepers_present(): # Unseeded tile
|
|
|
|
|
|
-# 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_asset(asset, 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
|
|
|
- asset[1][5] = colour
|
|
|
- asset[1][6] = background
|
|
|
-
|
|
|
- erase_asset(asset)
|
|
|
- new_karel = draw_karel(asset[1][0], asset[1][1], asset[1][2], asset[1][3], asset[1][4], asset[1][5], asset[1][6], asset[1][7])
|
|
|
-
|
|
|
- logger.debug(f"Re-coloured Karel: {asset} 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
|
|
|
- ):
|
|
|
+ # Seed life
|
|
|
+ paint_corner("black")
|
|
|
+ put_beeper()
|
|
|
|
|
|
- # Body constants
|
|
|
- MARGIN = size / 8
|
|
|
- APPENDAGE_MULTIPLIER = MARGIN * 0.6
|
|
|
+ else: # Seeded tile
|
|
|
+ if random(0.5): # 50% chance
|
|
|
+ paint_corner("orange") # Accelerate life or overtake another life.
|
|
|
+ else: # Remainder 50% chance
|
|
|
+ die() # Compete, cancelling each other out.
|
|
|
|
|
|
- # Random colours
|
|
|
- if colour == "random":
|
|
|
- colour = generate_random_colour()
|
|
|
- if background == "random":
|
|
|
- background = generate_random_colour()
|
|
|
-
|
|
|
- ''' 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
|
|
|
+ # Never leave Karel facign a wall:
|
|
|
+ orient()
|
|
|
+
|
|
|
+def die():
|
|
|
+ # Permanent death:
|
|
|
+ if random(0.2): # 20% chance
|
|
|
+ paint_corner("white")
|
|
|
+ pick_beeper()
|
|
|
|
|
|
- # 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
|
|
|
- )
|
|
|
+ # Seed for rebirth | Composting:
|
|
|
+ else: # Remainder 80% chance
|
|
|
+ paint_corner("black")
|
|
|
+
|
|
|
+# Grow, die or reproduce:
|
|
|
+def paint_life():
|
|
|
+ # In reverse order, since "elif" is not available.
|
|
|
+ #if corner_color_is("pink"): # End condition, but "quit()" is not available
|
|
|
+ # quit()
|
|
|
+
|
|
|
+ if corner_color_is("cyan"):
|
|
|
+ if random(0.8): # 80% chance
|
|
|
+ paint_corner("pink") # Evolve
|
|
|
|
|
|
- # 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
|
|
|
- )
|
|
|
+ # Reproduce quadrice:
|
|
|
+ for i in range(4):
|
|
|
+ reproduce()
|
|
|
|
|
|
- # 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.lower(), colour, background, transparent]
|
|
|
- logger.debug(f"Created Karel: {shapes, arguments}")
|
|
|
- return [shapes, arguments]
|
|
|
+ else: # Remainder 20% chance
|
|
|
+ if random(0.2): # 20% chance of death, else stagnation.
|
|
|
+ die() # Death
|
|
|
+ if corner_color_is("green"):
|
|
|
+ if random(0.8): # 80% chance
|
|
|
+ paint_corner("cyan") # Evolve
|
|
|
+
|
|
|
+ # Reproduce thrice:
|
|
|
+ for i in range(3):
|
|
|
+ reproduce()
|
|
|
+
|
|
|
+ else: # Remainder 20% chance
|
|
|
+ if random(0.2): # 20% chance of death, else stagnation.
|
|
|
+ die() # Death
|
|
|
+ if corner_color_is("blue"):
|
|
|
+ if random(0.8): # 80% chance
|
|
|
+ paint_corner("green") # Evolve
|
|
|
+
|
|
|
+ # Reproduce twice:
|
|
|
+ for i in range(2):
|
|
|
+ reproduce()
|
|
|
+
|
|
|
+ else: # Remainder 20% chance
|
|
|
+ if random(0.2): # 20% chance of death, else stagnation.
|
|
|
+ die() # Death
|
|
|
+ if corner_color_is("olive"):
|
|
|
+ if random(0.6): # 60% chance
|
|
|
+ paint_corner("blue") # Evolve
|
|
|
+ reproduce()
|
|
|
+ else: # Remainder 40% chance
|
|
|
+ if random(0.2): # 20% chance of death, else stagnation.
|
|
|
+ die() # Death
|
|
|
+ if corner_color_is("orange"):
|
|
|
+ if random(0.5): # 50% chance
|
|
|
+ paint_corner("olive") # Evolve
|
|
|
+ else: # Remainder 50% chance
|
|
|
+ if random(0.2): # 20% chance of death, else stagnation.
|
|
|
+ die() # Death
|
|
|
+ if corner_color_is("red"): # Adolescence
|
|
|
+ if random(0.4): # 40% chance
|
|
|
+ paint_corner("orange") # Evolve
|
|
|
+ else: # Remainder 60% chance
|
|
|
+ if random(0.2): # 20% chance of death, else stagnation.
|
|
|
+ die() # Death
|
|
|
+ if corner_color_is("purple"): # Early stage
|
|
|
+ if random(0.3): # 30% chance
|
|
|
+ paint_corner("red") # Evolve
|
|
|
+ else: # Remainder 70% chance
|
|
|
+ if random(0.2): # 20% chance of death, else stagnation.
|
|
|
+ die() # Death
|
|
|
+ if corner_color_is("brown"): # Infancy
|
|
|
+ if random(0.2): # 20% chance
|
|
|
+ paint_corner("purple") # Evolve
|
|
|
+ else: # Remainder 80% chance
|
|
|
+ if random(0.2): # 20% chance of death, else stagnation.
|
|
|
+ die() # Death
|
|
|
+ if corner_color_is("gray"): # Prenatal
|
|
|
+ if random(0.1): # 10% chance
|
|
|
+ paint_corner("brown") # Evolve
|
|
|
+ else: # Remainder 90% chance
|
|
|
+ if random(0.2): # 20% chance of death, else stagnation.
|
|
|
+ die() # Death
|
|
|
+ if corner_color_is("black"): # Field is seeded
|
|
|
+ paint_corner("gray") # Sprout life
|
|
|
+
|
|
|
+# Prepare the world with habitable patches.
|
|
|
+def seed():
|
|
|
+ genesis_position()
|
|
|
+
|
|
|
+ while front_is_clear():
|
|
|
+
|
|
|
+ # Perhaps seed a fountain of life
|
|
|
+ if random(0.3): # 30% chance
|
|
|
+ paint_corner("black")
|
|
|
+ put_beeper()
|
|
|
+
|
|
|
+ move()
|
|
|
+ wall_check()
|
|
|
+
|
|
|
+ # Face away from the wall
|
|
|
+ orient()
|
|
|
+
|
|
|
+# The circle of life
|
|
|
+def life_loop():
|
|
|
+ for i in range(9999): # Incubation period
|
|
|
+
|
|
|
+ # Path of god, played by karel:
|
|
|
+ for step in range(9): # Travel period
|
|
|
+ perhaps_move()
|
|
|
+ orient()
|
|
|
+ paint_life()
|
|
|
+
|
|
|
+# End the game neatly:
|
|
|
+def ascension():
|
|
|
+ genesis_position()
|
|
|
+
|
|
|
+ # Remove seeds
|
|
|
+ while front_is_clear():
|
|
|
+ pick_if_present()
|
|
|
+ move()
|
|
|
+ pick_if_present()
|
|
|
+ wall_check()
|
|
|
+
|
|
|
+ genesis_position()
|
|
|
+
|
|
|
+
|
|
|
+ # The three phases of life:
|
|
|
+def main():
|
|
|
+ seed()
|
|
|
+ life_loop()
|
|
|
+ ascension() # The script should not run forever, making some unintended biblical implications...
|
|
|
+
|
|
|
+
|
|
|
+# don't change this code
|
|
|
+if __name__ == '__main__':
|
|
|
+ main()
|