简体   繁体   中英

Bugs drawing with turtle(python) using onkey() and dictionaries

I decided redo this question as per advice I received, This is an assignment question I have been given for 1st year uni, python coding. I have bugs in my code and Can't figure out where to fix them. BUG 1 The turtle starts drawing when program is ran even though pen is up. BUG 2 undefined key such as 's, 7, tab' trigger space_bar function

COLOURING BOOK

In this task you create a children's colouring game in which given pictures can be coloured by tracing around a shape and then filling it. The controls are as follows.

ARROW KEYS - Move the "brush" (turtle cursor) left, right, up or down by a fixed small amount.

'z' - Undo the last step.

'r', 'g', 'b' - Change the brush colour to red, green or blue, respectively. (You can define more colours if you like, but we expect at least these three.)

SPACE BAR - Toggle the painting mode. In "move" mode, which is the initial mode, the "brush" (turtle) moves around the screen without drawing. In "paint" mode the brush leaves a coloured line as it moves. Most importantly, when the mode is changed from "paint" to "move", the area traced out by the brush is filled with colour.

from turtle import *
from functools import partial 
bgpic("Colour_A_Turkey.gif") # change this to change the picture

#control the accuracy/speed of the drawing 
step_size =8
pensize(4)
penup()

# whenever spacebar is pressed the current state  and next state switch values 
current_state = penup
next_state = pendown
def space_bar():
    global current_state, next_state
    next_state()
    current_state, next_state = next_state, current_state
    #if the current stat is penup fill in with current colour
    if current_state == penup:
        end_fill()
    else:
        begin_fill()
onkey(space_bar, " ")

# undo do a mistake function
def mistake():
    undo()
onkey(mistake, "z")

#using partial function to store the following functions
#so they can be called  as arguments from a dictionary
#movement
strait = partial(fd, step_size)
reverse = partial(bk, step_size)
turn_rt = partial(rt, step_size)
turn_lf = partial(lt, step_size)

#colour
brow = partial(color, "brown")
gree = partial(color, "green")
yell = partial(color, "yellow")
oran = partial(color, "orange")
purp = partial(color, "purple")
red = partial(color, "red")
blue = partial(color, "blue")


#create a dictionary to store all the keys and there abilities 
key_action = {"b" : blue, "r" : red, "p" : purp, "o" : oran,\
          "y" : yell, "g" : gree, "w" : brow, "Right" : turn_rt , "Up" : strait,\
          "Down" : reverse, "Left" : turn_lf, "z" : undo()}

#when a key in then above dictionary
#is pressed it's function  is activated
for pressed_key, activated_key in key_action.items():
    onkey(activated_key, pressed_key)  

#make turtle look for key strokes with predefined function
listen()
#finish
done()

Remember, in Python, everything is an object and we really mean that . Functions are objects too. We can store functions in a dictionary, and in fact that's exactly what you seem to want to do here.

turn_lf = lt(step_size )

The key problem here is that you want to store "a function that calls lt with step_size as the argument", but here you have just called lt with step_size as an argument immediately, and stored the return value.

Arguably the simplest way to get what you want is to use functools.partial to "bind" the step_size argument.

from functools import partial
turn_lf = partial(lt, step_size) # `lt` is not called yet.

# Now, later on, we can do
turn_lf() # and it's just as if we did `lt(step_size)`.
# So now we can store `turn_lf` in a dict, look it up and call it later, etc.

# Similarly for all the other functions you want to make.

(Another problem is that you haven't been consistent with this; if you want everything to go in one dict, then you need to indicate the bindings for the color function as well. 'brown' is just a string, after all. Fortunately, this is just as simple as with the other functions: we just make our partial(color, 'brown') .

As for "z" : delete , well - we don't have any arguments to bind to undo . So while we could follow the pattern and write partial(undo) (notice, no more arguments, because we aren't binding anything), it makes much more sense to just write undo directly.

As an aside, we can simplify this:

for key in key_action:
    pressed_key = key
    activated_key = key_action[key]

To this:

for pressed_key, activated_key in key_action.items():

Why define all the functions? We can directly use: Break the dict as :

key_action = {"b" : "blue", "r" : "red", "p" : "purple", "o" : "orange", "y" : "yellow","g" : "green", "w" : "brown","Right" : rt , "Left": lt, "Up" : fd, "Down" : bk,"z" : undo}


no_input = ["z"]

one_input = ["Right", "Left", "Up", "Down"]

for key in key_action:
    activated_key = key_action[key]
    if key in no_input:
       activated_key()
    elif key in one_input():
        activated_key(step_size)
    else:
        onkey(color(activated_key), key)

Your dictionary approach is along the right way of thinking. However, your function will not behave correctly. Using a dictionary is simplier than you think. First of all you have to have separate FUNCTIONS against STRING and handle them correctly. As each of them will behave differently:

# Get rid of the top four lines, they will not work
# All actions mapping
key_action = {"b" : "blue", "r" : "red", "p" : "purple", "o" : "orange",
              "y" : "yellow", "g" : "green", "w" : "brown",
              "Right" : rt , "Left": lt, "Up" : fd, "Down" : bk,
              "z" : undo}
# Note down which are special actions
# Functions with no input
foo = ["z"]
# Function with one input
bar = ["Right", "Left", "Up", "Down"]

# Assuming the input key is get here, I don't use turtle don't know how
# the input is read
key = listen()  # PSEUDOCODE!

# Handle the input
if key in foo:
     foo[key]() # Execute no input function
elif key in bar:
     foo[key](step_size)
else:
     onkey(key_action[key], key)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM