A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://inventwithpython.com/bigbookpython/project23.html below:

Etching Drawer

#23
Etching Drawer

When you move a pen point around the screen with the WASD keys, the etching drawer forms a picture by tracing a continuous line, like the Etch A Sketch toy. Let your artistic side break out and see what images you can create! This program also lets you save your drawings to a text file so you can print them out later. Plus, you can copy and paste the WASD movements of other drawings into this program, like the WASD commands for the Hilbert Curve fractal presented on lines 6 to 14 of the source code.

The Program in Action

When you run etchingdrawer.py, the output will look like Figure 23-1.

Figure 23-1: A drawing made in the etching drawer program

How It Works

Like Project 17, “Dice Math,” this program uses a dictionary stored in a variable named canvas to record the lines of the drawing. The keys are (x, y) tuples and the values are strings representing the line shape to draw at those x, y coordinates on the screen. A full list of Unicode characters you can use in your Python programs is given in Appendix B.

Line 126 has a function call to open() that passes an encoding='utf-8' argument. The reasons are beyond the scope of this book, but this is necessary for Windows to write the line characters to a text file.

  1. """Etching Drawer, by Al Sweigart [email protected]
  2. An art program that draws a continuous line around the screen using the
  3. WASD keys. Inspired by Etch A Sketch toys.
  4.
  5. For example, you can draw Hilbert Curve fractal with:
  6. SDWDDSASDSAAWASSDSASSDWDSDWWAWDDDSASSDWDSDWWAWDWWASAAWDWAWDDSDW
  7.
  8. Or an even larger Hilbert Curve fractal with:
  9. DDSAASSDDWDDSDDWWAAWDDDDSDDWDDDDSAASDDSAAAAWAASSSDDWDDDDSAASDDSAAAAWA
 10. ASAAAAWDDWWAASAAWAASSDDSAASSDDWDDDDSAASDDSAAAAWAASSDDSAASSDDWDDSDDWWA
 11. AWDDDDDDSAASSDDWDDSDDWWAAWDDWWAASAAAAWDDWAAWDDDDSDDWDDSDDWDDDDSAASDDS
 12. AAAAWAASSDDSAASSDDWDDSDDWWAAWDDDDDDSAASSDDWDDSDDWWAAWDDWWAASAAAAWDDWA
 13. AWDDDDSDDWWAAWDDWWAASAAWAASSDDSAAAAWAASAAAAWDDWAAWDDDDSDDWWWAASAAAAWD
 14. DWAAWDDDDSDDWDDDDSAASSDDWDDSDDWWAAWDD
 15.
 16. View this code at https://nostarch.com/big-book-small-python-projects
 17. Tags: large, artistic"""
 18.
 19. import shutil, sys
 20.
 21. # Set up the constants for line characters:
 22. UP_DOWN_CHAR         = chr(9474)  # Character 9474 is '│'
 23. LEFT_RIGHT_CHAR      = chr(9472)  # Character 9472 is '─'
 24. DOWN_RIGHT_CHAR      = chr(9484)  # Character 9484 is '┌'
 25. DOWN_LEFT_CHAR       = chr(9488)  # Character 9488 is '┐'
 26. UP_RIGHT_CHAR        = chr(9492)  # Character 9492 is '└'
 27. UP_LEFT_CHAR         = chr(9496)  # Character 9496 is '┘'
 28. UP_DOWN_RIGHT_CHAR   = chr(9500)  # Character 9500 is '├'
 29. UP_DOWN_LEFT_CHAR    = chr(9508)  # Character 9508 is '┤'
 30. DOWN_LEFT_RIGHT_CHAR = chr(9516)  # Character 9516 is '┬'
 31. UP_LEFT_RIGHT_CHAR   = chr(9524)  # Character 9524 is '┴'
 32. CROSS_CHAR           = chr(9532)  # Character 9532 is '┼'
 33. # A list of chr() codes is at https://inventwithpython.com/chr
 34.
 35. # Get the size of the terminal window:
 36. CANVAS_WIDTH, CANVAS_HEIGHT = shutil.get_terminal_size()
 37. # We can't print to the last column on Windows without it adding a
 38. # newline automatically, so reduce the width by one:
 39. CANVAS_WIDTH -= 1
 40. # Leave room at the bottom few rows for the command info lines.
 41. CANVAS_HEIGHT -= 5
 42.
 43. """The keys for canvas will be (x, y) integer tuples for the coordinate,
 44. and the value is a set of letters W, A, S, D that tell what kind of line
 45. should be drawn."""
 46. canvas = {}
 47. cursorX = 0
 48. cursorY = 0
 49.
 50.
 51. def getCanvasString(canvasData, cx, cy):
 52.     """Returns a multiline string of the line drawn in canvasData."""
 53.     canvasStr = ''
 54.
 55.     """canvasData is a dictionary with (x, y) tuple keys and values that
 56.     are sets of 'W', 'A', 'S', and/or 'D' strings to show which
 57.     directions the lines are drawn at each xy point."""
 58.     for rowNum in range(CANVAS_HEIGHT):
 59.         for columnNum in range(CANVAS_WIDTH):
 60.             if columnNum == cx and rowNum == cy:
 61.                 canvasStr += '#'
 62.                 continue
 63.
 64.             # Add the line character for this point to canvasStr.
 65.             cell = canvasData.get((columnNum, rowNum))
 66.             if cell in (set(['W', 'S']), set(['W']), set(['S'])):
 67.                 canvasStr += UP_DOWN_CHAR
 68.             elif cell in (set(['A', 'D']), set(['A']), set(['D'])):
 69.                 canvasStr += LEFT_RIGHT_CHAR
 70.             elif cell == set(['S', 'D']):
 71.                 canvasStr += DOWN_RIGHT_CHAR
 72.             elif cell == set(['A', 'S']):
 73.                 canvasStr += DOWN_LEFT_CHAR
 74.             elif cell == set(['W', 'D']):
 75.                 canvasStr += UP_RIGHT_CHAR
 76.             elif cell == set(['W', 'A']):
 77.                 canvasStr += UP_LEFT_CHAR
 78.             elif cell == set(['W', 'S', 'D']):
 79.                 canvasStr += UP_DOWN_RIGHT_CHAR
 80.             elif cell == set(['W', 'S', 'A']):
 81.                 canvasStr += UP_DOWN_LEFT_CHAR
 82.             elif cell == set(['A', 'S', 'D']):
 83.                 canvasStr += DOWN_LEFT_RIGHT_CHAR
 84.             elif cell == set(['W', 'A', 'D']):
 85.                 canvasStr += UP_LEFT_RIGHT_CHAR
 86.             elif cell == set(['W', 'A', 'S', 'D']):
 87.                 canvasStr += CROSS_CHAR
 88.             elif cell == None:
 89.                 canvasStr += ' '
 90.         canvasStr += '\n'  # Add a newline at the end of each row.
 91.     return canvasStr
 92.
 93.
 94. moves = []
 95. while True:  # Main program loop.
 96.     # Draw the lines based on the data in canvas:
 97.     print(getCanvasString(canvas, cursorX, cursorY))
 98.
 99.     print('WASD keys to move, H for help, C to clear, '
100.         + 'F to save, or QUIT.')
101.     response = input('> ').upper()
102.
103.     if response == 'QUIT':
104.         print('Thanks for playing!')
105.         sys.exit()  # Quit the program.
106.     elif response == 'H':
107.         print('Enter W, A, S, and D characters to move the cursor and')
108.         print('draw a line behind it as it moves. For example, ddd')
109.         print('draws a line going right and sssdddwwwaaa draws a box.')
110.         print()
111.         print('You can save your drawing to a text file by entering F.')
112.         input('Press Enter to return to the program...')
113.         continue
114.     elif response == 'C':
115.         canvas = {}  # Erase the canvas data.
116.         moves.append('C')  # Record this move.
117.     elif response == 'F':
118.         # Save the canvas string to a text file:
119.         try:
120.             print('Enter filename to save to:')
121.             filename = input('> ')
122.
123.             # Make sure the filename ends with .txt:
124.             if not filename.endswith('.txt'):
125.                 filename += '.txt'
126.             with open(filename, 'w', encoding='utf-8') as file:
127.                 file.write(''.join(moves) + '\n')
128.                 file.write(getCanvasString(canvas, None, None))
129.         except:
130.             print('ERROR: Could not save file.')
131.
132.     for command in response:
133.         if command not in ('W', 'A', 'S', 'D'):
134.             continue  # Ignore this letter and continue to the next one.
135.         moves.append(command)  # Record this move.
136.
137.         # The first line we add needs to form a full line:
138.         if canvas == {}:
139.             if command in ('W', 'S'):
140.                 # Make the first line a horizontal one:
141.                 canvas[(cursorX, cursorY)] = set(['W', 'S'])
142.             elif command in ('A', 'D'):
143.                 # Make the first line a vertical one:
144.                 canvas[(cursorX, cursorY)] = set(['A', 'D'])
145.
146.         # Update x and y:
147.         if command == 'W' and cursorY > 0:
148.             canvas[(cursorX, cursorY)].add(command)
149.             cursorY = cursorY - 1
150.         elif command == 'S' and cursorY < CANVAS_HEIGHT - 1:
151.             canvas[(cursorX, cursorY)].add(command)
152.             cursorY = cursorY + 1
153.         elif command == 'A' and cursorX > 0:
154.             canvas[(cursorX, cursorY)].add(command)
155.             cursorX = cursorX - 1
156.         elif command == 'D' and cursorX < CANVAS_WIDTH - 1:
157.             canvas[(cursorX, cursorY)].add(command)
158.             cursorX = cursorX + 1
159.         else:
160.             # If the cursor doesn't move because it would have moved off
161.             # the edge of the canvas, then don't change the set at
162.             # canvas[(cursorX, cursorY)].
163.             continue
164.
165.         # If there's no set for (cursorX, cursorY), add an empty set:
166.         if (cursorX, cursorY) not in canvas:
167.             canvas[(cursorX, cursorY)] = set()
168.
169.         # Add the direction string to this xy point's set:
170.         if command == 'W':
171.             canvas[(cursorX, cursorY)].add('S')
172.         elif command == 'S':
173.             canvas[(cursorX, cursorY)].add('W')
174.         elif command == 'A':
175.             canvas[(cursorX, cursorY)].add('D')
176.         elif command == 'D':
177.             canvas[(cursorX, cursorY)].add('A')
Exploring the Program

Try to find the answers to the following questions. Experiment with some modifications to the code and rerun the program to see what effect the changes have.

  1. What happens if you change response = input('> ').upper() on line 101 to response = input('> ')?
  2. What happens if you change canvasStr += '#' on line 61 to canvasStr += '@'?
  3. What happens if you change canvasStr += ' ' on line 89 to canvasStr += '.'?
  4. What happens if you change moves = [] on line 94 to moves = list('SDWDDSASDSAAWASSDSAS')?

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4