Today: advanced double-while parsing, flex-arrow drawing example
We've done them like this:
at end v----v xx @word xx
'@'is kind of a crutch here. More realistic would be that we just find the word itself, floating among other chars.
I will work this one in lecture with the double-while technique. Then we'll have you try to solve a similar one. (HW5)
find_alpha(s): We'll say a word is made of 1 or more alphabetic chars. Find and return the first word in s, or
None if there is none. So
'%%%abc xx' returns
'abc'. Use two while loops.
1. Skip over the
'%' to find the
2. Then find the end of the series of alpha
start- will point to first alpha char
start = 0
'%'.. when should it advance?
start < len(s)guard as usual
# Advance start to first alpha start = 0 while start < len(s) and not s[start].isalpha(): start += 1
end- points to first non-alpha char after start
end = start + 1
startis first char
endis 1 past last char
Q: Suppose there is no alpha. What will
start be after loop 1? What is the if-check for that case?
Reminder: here is the loop-1 code:
while start < len(s) and not s[start].isalpha(): start += 1
Sketch out what start does for the no-alpha case:
if start == len(s): return None
def find_alpha(s): # Advance start to first alpha start = 0 while start < len(s) and not s[start].isalpha(): start += 1 # There was no word if start == len(s): return None # Advance end past alpha chars end = start + 1 while end < len(s) and s[end].isalpha(): end += 1 return s[start:end]
Here is a very similar problem on the experimental server. See if you can write the code for it. You can peek at the lecture example above if you need to.
find_num(s): We'll say that a number is a series of one or more digit chars. Find and return the substring of the first num in s, or
None if there is none.
Aside: link to CC licensed music cc mixter. We're looking for ideas for some CC licensed music for coding in lecture to keep me and Juliette from blabbing away, cause neither of us can stand the awkward silence! Something mellow with no vocals.
def find_num(s): # Advance start to first digit start = 0 while start < len(s) and not s[start].isdigit(): start += 1 # There was no num if start == len(s): return None # Advance end past digits end = start + 1 while end < len(s) and s[end].isdigit(): end += 1 return s[start:end]
Download the flex-arrow.zip to work this fun little drawing example.
x = 0 y = 0 width = 200 x2 = x + width # this is fine canvas.draw_line(x, y, x2, y) # this is fine too # draw a line 2/3 as long # note that x3 is not an int x3 = x + width * 0.66 canvas.draw_line(x, y, x3, y)
Ultimately we want to produce this output:
The "flex" parameter is 0..1.0: the fraction of the arrow's length used for the arrow heads. The arms of the arrow will go at a 45-degree angle away from the horizontal.
Specify flex on the command line so you can see how it works. Close the window to exit the program. You can also specify larger canvas sizes.
$ python3 flex-arrow.py -arrows 0.25 $ python3 flex-arrow.py -arrows 0.15 $ python3 flex-arrow.py -arrows 0.1 1200 600
Look at the draw_arrow() function. It is given x,y of the left endpoint of the arrow and the horizontal length of the arrow in pixels. The "flex" number is between 0 .. 1.0, giving the head_len - the horizontal extent of the arrow head - called "h" in the diagram. Main() calls draw_arrow() twice, drawing two arrows in the window.
The code here draws the left arrow head.
def draw_arrow(canvas, x, y, length, flex): """ Draw a horizontal line with arrow heads at both ends. It's left endpoint at x,y, extending for length pixels. "flex" is 0.0 .. 1.0, the fraction of length that the arrow heads should extend horizontally. """ # Compute where the line ends, draw it x_right = x + length - 1 canvas.draw_line(x, y, x_right, y) # Draw 2 arrowhead lines, up and down from left endpoint head_len = flex * length canvas.draw_line(x, y, x + head_len, y - head_len) # up canvas.draw_line(x, y, x + head_len, y + head_len) # down # Draw 2 arrowhead lines from the right endpoint # your code here pass
Look at the diagram below. Add the code to draw the head on the right endpoint of the arrow. The
head_len variable "h" in the drawing. This is a solid, CS106A applied-math exercise.
# Draw 2 arrowhead lines from the right endpoint # your code here pass canvas.draw_line(x_right, y, x_right - head_len, y - head_len) # up canvas.draw_line(x_right, y, x_right - head_len, y + head_len) # down
Now we're going to show you something a little beyond the regular CS106A level, and it's a teeny bit mind warping.
Run the code with -trick like this, see what you get.
$ python3 flex-arrow.py -trick 0.1 1200 600
Note: one more thing today