karel_asset.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. import operator
  2. import logging
  3. import random
  4. # Logging to console
  5. logger = logging.getLogger(__name__)
  6. logging.basicConfig(level=logging.INFO) # Set loglevel to INFO or higher to prevent console spam.
  7. """
  8. Helper functions
  9. """
  10. # Return some hex colour
  11. """
  12. Waiting for Stanford to fix a bug in the environment
  13. CIP bug: https://codeinplace.stanford.edu/cip6/report?post=ac7c4ffd-1f90-475a-b4ee-2e5b73c5348f
  14. from matplotlib import colors
  15. import decimal
  16. def get_random_colour():
  17. return decimal.Decimal(random.randrange(0,10)/10), decimal.Decimal(random.randrange(0,10)/10), decimal.Decimal(random.randrange(0,10)/10)
  18. colour = colors.rgb2hex((get_random_colour()))
  19. background = colors.rgb2hex((get_random_colour()))
  20. """
  21. def generate_random_colour():
  22. rgb_values = [random.randrange(256), random.randrange(256), random.randrange(256)]
  23. hex_colours = [hex(value)[2:] for value in rgb_values] # Strip the '0x' prefix
  24. for i in range(len(hex_colours)):
  25. if len(str(hex_colours[i])) == 1:
  26. hex_colours[i] = f"0{hex_colours[i]}"
  27. return '#' + ''.join(hex_colours)
  28. """
  29. Karel functions
  30. """
  31. # Erase a passed Karel from the canvas
  32. def erase_asset(asset):
  33. canvas = asset[1][0]
  34. for shape in asset[0].values():
  35. canvas.delete(shape)
  36. logger.debug(f"Erased asset: {asset}")
  37. # Move a passed Karel on the canvas
  38. """
  39. Waiting for Stanford to fix a bug in the environment
  40. CIP bug: https://codeinplace.stanford.edu/cip6/report?post=7043ece9-7653-4e39-8a63-5f4544b1d74b
  41. def move_karel(canvas, karel, x, y):
  42. for shape in karel[0].values():
  43. canvas.move(shape, x, y)
  44. logger.debug(f"Moved: {karel} by {x} horizontally, {y} vertically")
  45. """
  46. # Move a passed Karel relative to previous position
  47. def relative_move_asset(asset, x:int=0, y:int=0):
  48. # Update coordinates in list
  49. asset[1][1] += x
  50. asset[1][2] += y
  51. erase_asset(asset)
  52. 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])
  53. logger.debug(f"Moved: {asset} by {x} horizontally, {y} vertically, to {new_asset}")
  54. return new_asset
  55. # Move a passed Karel in relation to her orientation
  56. def orientation_move_asset(asset, direction, amount):
  57. # Direction translation
  58. if asset[1][4].startswith("east"):
  59. if direction.lower() == "forward" or direction.lower() == "front":
  60. asset[1][1] += amount
  61. if direction.lower() == "left":
  62. asset[1][2] -= amount
  63. if direction.lower() == "right":
  64. asset[1][2] += amount
  65. if direction.lower() == "backward" or direction.lower() == "back":
  66. asset[1][1] -= amount
  67. if asset[1][4].startswith("north"):
  68. if direction.lower() == "forward" or direction.lower() == "front":
  69. asset[1][2] -= amount
  70. if direction.lower() == "left":
  71. asset[1][1] -= amount
  72. if direction.lower() == "right":
  73. asset[1][1] += amount
  74. if direction.lower() == "backward" or direction.lower() == "back":
  75. asset[1][2] += amount
  76. if asset[1][4].startswith("west"):
  77. if direction.lower() == "forward" or direction.lower() == "front":
  78. asset[1][1] -= amount
  79. if direction.lower() == "left":
  80. asset[1][2] += amount
  81. if direction.lower() == "right":
  82. asset[1][2] -= amount
  83. if direction.lower() == "backward" or direction.lower() == "back":
  84. asset[1][1] += amount
  85. if asset[1][4].startswith("south"):
  86. if direction.lower() == "forward" or direction.lower() == "front":
  87. asset[1][2] += amount
  88. if direction.lower() == "left":
  89. asset[1][1] += amount
  90. if direction.lower() == "right":
  91. asset[1][1] -= amount
  92. if direction.lower() == "backward" or direction.lower() == "back":
  93. asset[1][2] -= amount
  94. erase_asset(asset)
  95. 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])
  96. logger.debug(f"Moved: {asset} {direction} by {amount} as {new_karel}")
  97. return new_karel
  98. # Move a passed Karel to new coordinates
  99. def absolute_move_asset(asset, x, y):
  100. # Update coordinates in list
  101. asset[1][1] = x
  102. asset[1][2] = y
  103. erase_asset(asset)
  104. 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])
  105. logger.debug(f"Moved: {asset} by {x} horizontally, {y} vertically, to {new_karel}")
  106. return new_karel
  107. # Change the orientation of a passed Karel
  108. def rotate_asset(asset, direction):
  109. # Relative turn
  110. if direction == "right" or direction == "left":
  111. # East
  112. if asset[1][4] == "east":
  113. if direction == "right":
  114. asset[1][4] = "south"
  115. if direction == "left":
  116. asset[1][4] = "north"
  117. elif asset[1][4] == "east-flipped":
  118. if direction == "right":
  119. asset[1][4] = "south-flipped"
  120. if direction == "left":
  121. asset[1][4] = "north-flipped"
  122. # North
  123. elif asset[1][4] == "north":
  124. if direction == "right":
  125. asset[1][4] = "east"
  126. if direction == "left":
  127. asset[1][4] = "west"
  128. elif asset[1][4] == "north-flipped":
  129. if direction == "right":
  130. asset[1][4] = "east-flipped"
  131. if direction == "left":
  132. asset[1][4] = "west-flipped"
  133. # West
  134. elif asset[1][4] == "west":
  135. if direction == "right":
  136. asset[1][4] = "north"
  137. if direction == "left":
  138. asset[1][4] = "soutch"
  139. elif asset[1][4] == "west-flipped":
  140. if direction == "right":
  141. asset[1][4] = "north-flipped"
  142. if direction == "left":
  143. asset[1][4] = "south-flipped"
  144. # South
  145. elif asset[1][4] == "south":
  146. if direction == "right":
  147. asset[1][4] = "west"
  148. if direction == "left":
  149. asset[1][4] = "east"
  150. elif asset[1][4] == "north-flipped":
  151. if direction == "right":
  152. asset[1][4] = "west-flipped"
  153. if direction == "left":
  154. asset[1][4] = "east-flipped"
  155. # Absolute rotation
  156. 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":
  157. asset[1][4] = direction
  158. # Syntax error
  159. else:
  160. logger.error(f"Invalid rotation direction: {direction}")
  161. erase_asset(asset)
  162. 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])
  163. logger.debug(f"Rotated Karel: {asset} by {direction} as {asset[1][4]} to {new_karel}")
  164. return new_karel
  165. # Recolour a passed Karel on the canvas
  166. """
  167. Waiting for Stanford to fix a bug in the environment
  168. CIP bug: https://codeinplace.stanford.edu/cip6/report?post=c36ed931-3019-4830-8ba6-655c1a513471
  169. def recolour_karel(canvas, karel, colour:str="black", background:str="white"):
  170. for name, shape in karel[0].items(): # Loop over Karel dict
  171. if name.endswith("_fill"): # Background shape
  172. canvas.set_color(shape, background)
  173. canvas.set_outline_color(shape, background)
  174. else: # Foreground shape
  175. if name.endswith("_line") or name.endswith("_corner") or name == "mouth":
  176. canvas.set_color(shape, colour)
  177. elif name == "eye":
  178. #canvas.set_color(shape, "transparent")
  179. canvas.set_outline_color(shape, colour)
  180. else: # Legs and feet
  181. canvas.set_color(shape, colour)
  182. canvas.set_outline_color(shape, colour)
  183. """
  184. def recolour_asset(asset, colour:str="black", background:str="white"):
  185. # Random colours
  186. if colour == "random":
  187. colour = generate_random_colour()
  188. if background == "random":
  189. background = generate_random_colour()
  190. # Update colours in list
  191. asset[1][5] = colour
  192. asset[1][6] = background
  193. erase_asset(asset)
  194. 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])
  195. logger.debug(f"Re-coloured Karel: {asset} with {colour} and {background} to {new_karel}")
  196. return new_karel
  197. # Draw a random Karel on the canvas
  198. def generate_random_karel(canvas):
  199. # Base the size on the shortest pane
  200. if canvas.width < canvas.height:
  201. size = random.randint(1, canvas.width)
  202. else:
  203. size = random.randint(1, canvas.height)
  204. centre_x = random.randint(int(size / 2), int(canvas.width - size / 2))
  205. centre_y = random.randint(int(size / 2), int(canvas.height - size / 2))
  206. orientation = random.choice(["east", "east-flipped", "north", "north-flipped", "west", "west-flipped", "south", "south-flipped"])
  207. transparent = random.choice((True, False))
  208. return draw_karel(canvas, centre_x, centre_y, size, orientation, "random", "random", transparent)
  209. # Draw a Karel
  210. def draw_karel(
  211. canvas,
  212. centre_x:int=25,
  213. centre_y:int=25,
  214. size:int=50,
  215. orientation:str="east",
  216. colour:str="black",
  217. background:str="white",
  218. transparent:bool=False
  219. ):
  220. # Body constants
  221. MARGIN = size / 8
  222. APPENDAGE_MULTIPLIER = MARGIN * 0.6
  223. # Random colours
  224. if colour == "random":
  225. colour = generate_random_colour()
  226. if background == "random":
  227. background = generate_random_colour()
  228. ''' Flipper case
  229. In order to be able to flip Karel, the operands in the forumlas must be able to switch around.
  230. Orientations are in relation to the centre of Karel.
  231. '''
  232. match orientation.lower():
  233. case "east" | "south-flipped":
  234. left_operand = operator.sub # Left / Top
  235. top_operand = operator.sub # Top / Left
  236. right_operand = operator.add # Right / Bottom
  237. bottom_operand = operator.add # Bottom / Right
  238. case "east-flipped" | "south":
  239. left_operand = operator.sub # Left / Top
  240. top_operand = operator.add # Bottom / Right
  241. right_operand = operator.add # Right / Bottom
  242. bottom_operand = operator.sub # Top / Left
  243. case "west" | "north-flipped":
  244. left_operand = operator.add # Right
  245. top_operand = operator.add # Bottom
  246. right_operand = operator.sub # Left
  247. bottom_operand = operator.sub # Top
  248. case "west-flipped" | "north":
  249. left_operand = operator.add # Right / Bottom
  250. top_operand = operator.sub # Top / Left
  251. right_operand = operator.sub # Left / Top
  252. bottom_operand = operator.add # Bottom / Right
  253. # Coords case
  254. if orientation.lower() == "north" or orientation.lower() == "north-flipped" or orientation.lower() == "south" or orientation.lower() == "south-flipped":
  255. temp_x = centre_x
  256. centre_x = centre_y
  257. centre_y = temp_x
  258. #pass
  259. # Borders
  260. left = left_operand(centre_x, size / 2)
  261. top = top_operand(centre_y, size / 2)
  262. right = right_operand(centre_x, size / 2)
  263. bottom = bottom_operand(centre_y, size / 2)
  264. margin = size / 8
  265. appendage_multiplier = margin * 0.6
  266. # Body borders
  267. body_left = left_operand(centre_x, size / 3)
  268. body_top = top
  269. body_right = right_operand(centre_x, size / 3)
  270. body_bottom = bottom_operand(centre_y, size / 2.6)
  271. eye_left = right_operand(body_left, margin)
  272. eye_top = bottom_operand(body_top, margin)
  273. eye_right = left_operand(body_right, margin)
  274. eye_bottom = top_operand(body_bottom, margin * 2)
  275. # Body coordinates
  276. top_left_corner = body_left, body_top
  277. left_diagonal_top = body_left, top_operand(body_bottom, margin)
  278. left_diagonal_bottom = eye_left, body_bottom
  279. right_diagonal_top = eye_right, body_top
  280. right_diagonal_bottom = body_right, bottom_operand(body_top, margin)
  281. bottom_right_corner = body_right, body_bottom
  282. mouth_left_corner = centre_x, bottom_operand(eye_bottom, margin)
  283. mouth_right_corner = eye_right, mouth_left_corner[1]
  284. # Left appendage borders
  285. leftLeg_left = left_operand(body_left, margin)
  286. leftLeg_top = eye_bottom
  287. leftLeg_right = body_left
  288. leftLeg_bottom = bottom_operand(leftLeg_top, appendage_multiplier)
  289. leftFoot_left = leftLeg_left
  290. leftFoot_top = leftLeg_bottom
  291. leftFoot_right = right_operand(leftLeg_left, appendage_multiplier)
  292. leftFoot_bottom = bottom_operand(leftFoot_top, appendage_multiplier)
  293. # Right appendage borders
  294. rightLeg_left = centre_x
  295. rightLeg_top = body_bottom
  296. rightLeg_right = right_operand(rightLeg_left, appendage_multiplier)
  297. rightLeg_bottom = bottom
  298. rightFoot_left = rightLeg_right
  299. rightFoot_top = top_operand(bottom, appendage_multiplier)
  300. rigthFoot_right = right_operand(rightLeg_right, appendage_multiplier)
  301. rightFoot_bottom = bottom
  302. # Draw Karel
  303. match orientation.lower():
  304. case "east" | "east-flipped" | "west" | "west-flipped":
  305. if not transparent:
  306. # Meat
  307. top_fill = canvas.create_rectangle(
  308. top_left_corner[0],
  309. top_left_corner[1],
  310. right_diagonal_top[0],
  311. eye_top,
  312. background,
  313. background
  314. )
  315. top_corner_fill = canvas.create_polygon(
  316. right_diagonal_top[0] , right_diagonal_top[1],
  317. right_diagonal_bottom[0], right_diagonal_bottom[1],
  318. eye_right, eye_top,
  319. color = background,
  320. outline = background
  321. )
  322. left_fill = canvas.create_rectangle(
  323. top_left_corner[0],
  324. eye_top,
  325. eye_left,
  326. left_diagonal_top[1],
  327. background,
  328. background
  329. )
  330. right_fill = canvas.create_rectangle(
  331. eye_right,
  332. eye_top,
  333. right_diagonal_bottom[0],
  334. eye_bottom,
  335. background,
  336. background
  337. )
  338. bottom_fill = canvas.create_rectangle(
  339. eye_left,
  340. eye_bottom,
  341. bottom_right_corner[0],
  342. bottom_right_corner[1],
  343. background,
  344. background
  345. )
  346. bottom_corner_fill = canvas.create_polygon(
  347. left_diagonal_top[0], left_diagonal_top[1],
  348. eye_left, left_diagonal_top[1],
  349. left_diagonal_bottom[0], left_diagonal_bottom[1],
  350. color = background,
  351. outline = background
  352. )
  353. # Outlines
  354. top_line = canvas.create_line(
  355. top_left_corner[0], top_left_corner[1],
  356. right_diagonal_top[0], right_diagonal_top[1],
  357. colour
  358. )
  359. top_corner = canvas.create_line(
  360. right_diagonal_top[0], right_diagonal_top[1],
  361. right_diagonal_bottom[0], right_diagonal_bottom[1],
  362. colour
  363. )
  364. left_line = canvas.create_line(
  365. top_left_corner[0], top_left_corner[1],
  366. left_diagonal_top[0], left_diagonal_top[1],
  367. colour
  368. )
  369. bottom_corner = canvas.create_line(
  370. left_diagonal_top[0], left_diagonal_top[1],
  371. left_diagonal_bottom[0], left_diagonal_bottom[1],
  372. colour
  373. )
  374. bottom_line = canvas.create_line(
  375. left_diagonal_bottom[0], left_diagonal_bottom[1],
  376. bottom_right_corner[0], bottom_right_corner[1],
  377. colour
  378. )
  379. right_line = canvas.create_line(
  380. right_diagonal_bottom[0], right_diagonal_bottom[1],
  381. bottom_right_corner[0], bottom_right_corner[1],
  382. colour
  383. )
  384. left_leg = canvas.create_rectangle(
  385. leftLeg_left,
  386. leftLeg_top,
  387. leftLeg_right,
  388. leftLeg_bottom,
  389. colour,
  390. colour
  391. )
  392. left_foot = canvas.create_rectangle(
  393. leftFoot_left,
  394. leftFoot_top,
  395. leftFoot_right,
  396. leftFoot_bottom,
  397. colour,
  398. colour
  399. )
  400. right_leg = canvas.create_rectangle(
  401. rightLeg_left,
  402. rightLeg_top,
  403. rightLeg_right,
  404. rightLeg_bottom,
  405. colour,
  406. colour
  407. )
  408. right_foot = canvas.create_rectangle(
  409. rightFoot_left,
  410. rightFoot_top,
  411. rigthFoot_right,
  412. rightFoot_bottom,
  413. colour,
  414. colour
  415. )
  416. eye = canvas.create_rectangle(
  417. eye_left,
  418. eye_top,
  419. eye_right,
  420. eye_bottom,
  421. "transparent",
  422. colour,
  423. )
  424. mouth = canvas.create_line(
  425. mouth_left_corner[0], mouth_left_corner[1],
  426. mouth_right_corner[0], mouth_right_corner[1],
  427. colour
  428. )
  429. case "north" | "north-flipped" | "south" | "south-flipped":
  430. if not transparent:
  431. # Meat
  432. top_fill = canvas.create_rectangle(
  433. top_left_corner[1], # Top Y
  434. right_diagonal_top[0], # Right X
  435. eye_top, # Bottom Y
  436. top_left_corner[0], # Left X
  437. background,
  438. background
  439. )
  440. top_corner_fill = canvas.create_polygon(
  441. right_diagonal_top[1] , right_diagonal_top[0],
  442. right_diagonal_bottom[1], right_diagonal_bottom[0],
  443. eye_top, eye_right,
  444. color = background,
  445. outline = background
  446. )
  447. left_fill = canvas.create_rectangle(
  448. eye_top,
  449. eye_left,
  450. left_diagonal_top[1],
  451. top_left_corner[0],
  452. background,
  453. background
  454. )
  455. right_fill = canvas.create_rectangle(
  456. eye_top,
  457. right_diagonal_bottom[0],
  458. eye_bottom,
  459. eye_right,
  460. background,
  461. background
  462. )
  463. bottom_fill = canvas.create_rectangle(
  464. eye_bottom,
  465. bottom_right_corner[0],
  466. bottom_right_corner[1],
  467. eye_left,
  468. background,
  469. background
  470. )
  471. bottom_corner_fill = canvas.create_polygon(
  472. left_diagonal_top[1], left_diagonal_top[0],
  473. left_diagonal_top[1], eye_left,
  474. left_diagonal_bottom[1], left_diagonal_bottom[0],
  475. color = background,
  476. outline = background
  477. )
  478. # Outlines
  479. top_line = canvas.create_line(
  480. top_left_corner[1], top_left_corner[0],
  481. right_diagonal_top[1], right_diagonal_top[0],
  482. colour
  483. )
  484. top_corner = canvas.create_line(
  485. right_diagonal_top[1], right_diagonal_top[0],
  486. right_diagonal_bottom[1], right_diagonal_bottom[0],
  487. colour
  488. )
  489. left_line = canvas.create_line(
  490. top_left_corner[1], top_left_corner[0],
  491. left_diagonal_top[1], left_diagonal_top[0],
  492. colour
  493. )
  494. bottom_corner = canvas.create_line(
  495. left_diagonal_top[1], left_diagonal_top[0],
  496. left_diagonal_bottom[1], left_diagonal_bottom[0],
  497. colour
  498. )
  499. bottom_line = canvas.create_line(
  500. left_diagonal_bottom[1], left_diagonal_bottom[0],
  501. bottom_right_corner[1], bottom_right_corner[0],
  502. colour
  503. )
  504. right_line = canvas.create_line(
  505. right_diagonal_bottom[1], right_diagonal_bottom[0],
  506. bottom_right_corner[1], bottom_right_corner[0],
  507. colour
  508. )
  509. left_leg = canvas.create_rectangle(
  510. leftLeg_top,
  511. leftLeg_right,
  512. leftLeg_bottom,
  513. leftLeg_left,
  514. colour,
  515. colour
  516. )
  517. left_foot = canvas.create_rectangle(
  518. leftFoot_top,
  519. leftFoot_right,
  520. leftFoot_bottom,
  521. leftFoot_left,
  522. colour,
  523. colour
  524. )
  525. right_leg = canvas.create_rectangle(
  526. rightLeg_top,
  527. rightLeg_right,
  528. rightLeg_bottom,
  529. rightLeg_left,
  530. colour,
  531. colour
  532. )
  533. right_foot = canvas.create_rectangle(
  534. rightFoot_top,
  535. rigthFoot_right,
  536. rightFoot_bottom,
  537. rightFoot_left,
  538. colour,
  539. colour
  540. )
  541. eye = canvas.create_rectangle(
  542. eye_top,
  543. eye_right,
  544. eye_bottom,
  545. eye_left,
  546. "transparent",
  547. colour,
  548. )
  549. mouth = canvas.create_line(
  550. mouth_left_corner[1], mouth_left_corner[0],
  551. mouth_right_corner[1], mouth_right_corner[0],
  552. colour
  553. )
  554. # Return each object so it can later be altered/destroyed
  555. if transparent:
  556. shapes = {
  557. "top_line": top_line,
  558. "top_corner": top_corner,
  559. "left_line": left_line,
  560. "bottom_corner": bottom_corner,
  561. "bottom_line": bottom_line,
  562. "right_line": right_line,
  563. "left_leg": left_leg,
  564. "left_foot": left_foot,
  565. "right_foot": right_foot,
  566. "right_leg": right_leg,
  567. "right_foot": right_foot,
  568. "eye": eye,
  569. "mouth": mouth
  570. }
  571. else: # Not transparent
  572. shapes = {
  573. "top_fill": top_fill,
  574. "top_corner_fill": top_corner_fill,
  575. "left_fill": left_fill,
  576. "right_fill": right_fill,
  577. "bottom_fill": bottom_fill,
  578. "bottom_corner_fill": bottom_corner_fill,
  579. "top_line": top_line,
  580. "top_corner": top_corner,
  581. "left_line": left_line,
  582. "bottom_corner": bottom_corner,
  583. "bottom_line": bottom_line,
  584. "right_line": right_line,
  585. "left_leg": left_leg,
  586. "left_foot": left_foot,
  587. "right_foot": right_foot,
  588. "right_leg": right_leg,
  589. "right_foot": right_foot,
  590. "eye": eye,
  591. "mouth": mouth
  592. }
  593. arguments = [canvas, centre_x, centre_y, size, orientation.lower(), colour, background, transparent]
  594. logger.debug(f"Created Karel: {shapes, arguments}")
  595. return [shapes, arguments]