# graphicsUtils.py # ---------------- # Licensing Information: You are free to use or extend these projects for # educational purposes provided that (1) you do not distribute or publish # solutions, (2) you retain this notice, and (3) you provide clear # attribution to UC Berkeley, including a link to http://ai.berkeley.edu. # # Attribution Information: The Pacman AI projects were developed at UC Berkeley. # The core projects and autograders were primarily created by John DeNero # (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu). # Student side autograding was added by Brad Miller, Nick Hay, and # Pieter Abbeel (pabbeel@cs.berkeley.edu). import sys import math import random import string import time import types import Tkinter _Windows = sys.platform == 'win32' # True if on Win95/98/NT _root_window = None # The root window for graphics output _canvas = None # The canvas which holds graphics _canvas_xs = None # Size of canvas object _canvas_ys = None _canvas_x = None # Current position on canvas _canvas_y = None _canvas_col = None # Current colour (set to black below) _canvas_tsize = 12 _canvas_tserifs = 0 def formatColor(r, g, b): return '#%02x%02x%02x' % (int(r * 255), int(g * 255), int(b * 255)) def colorToVector(color): return map(lambda x: int(x, 16) / 256.0, [color[1:3], color[3:5], color[5:7]]) if _Windows: _canvas_tfonts = ['times new roman', 'lucida console'] else: _canvas_tfonts = ['times', 'lucidasans-24'] pass # XXX need defaults here def sleep(secs): global _root_window if _root_window == None: time.sleep(secs) else: _root_window.update_idletasks() _root_window.after(int(1000 * secs), _root_window.quit) _root_window.mainloop() def begin_graphics(width=640, height=480, color=formatColor(0, 0, 0), title=None): global _root_window, _canvas, _canvas_x, _canvas_y, _canvas_xs, _canvas_ys, _bg_color # Check for duplicate call if _root_window is not None: # Lose the window. _root_window.destroy() # Save the canvas size parameters _canvas_xs, _canvas_ys = width - 1, height - 1 _canvas_x, _canvas_y = 0, _canvas_ys _bg_color = color # Create the root window _root_window = Tkinter.Tk() _root_window.protocol('WM_DELETE_WINDOW', _destroy_window) _root_window.title(title or 'Graphics Window') _root_window.resizable(0, 0) # Create the canvas object try: _canvas = Tkinter.Canvas(_root_window, width=width, height=height) _canvas.pack() draw_background() _canvas.update() except: _root_window = None raise # Bind to key-down and key-up events _root_window.bind( "", _keypress ) _root_window.bind( "", _keyrelease ) _root_window.bind( "", _clear_keys ) _root_window.bind( "", _clear_keys ) _root_window.bind( "", _leftclick ) _root_window.bind( "", _rightclick ) _root_window.bind( "", _rightclick ) _root_window.bind( "", _ctrl_leftclick) _clear_keys() _leftclick_loc = None _rightclick_loc = None _ctrl_leftclick_loc = None def _leftclick(event): global _leftclick_loc _leftclick_loc = (event.x, event.y) def _rightclick(event): global _rightclick_loc _rightclick_loc = (event.x, event.y) def _ctrl_leftclick(event): global _ctrl_leftclick_loc _ctrl_leftclick_loc = (event.x, event.y) def wait_for_click(): while True: global _leftclick_loc global _rightclick_loc global _ctrl_leftclick_loc if _leftclick_loc != None: val = _leftclick_loc _leftclick_loc = None return val, 'left' if _rightclick_loc != None: val = _rightclick_loc _rightclick_loc = None return val, 'right' if _ctrl_leftclick_loc != None: val = _ctrl_leftclick_loc _ctrl_leftclick_loc = None return val, 'ctrl_left' sleep(0.05) def draw_background(): corners = [(0,0), (0, _canvas_ys), (_canvas_xs, _canvas_ys), (_canvas_xs, 0)] polygon(corners, _bg_color, fillColor=_bg_color, filled=True, smoothed=False) def _destroy_window(event=None): sys.exit(0) # global _root_window # _root_window.destroy() # _root_window = None #print "DESTROY" def end_graphics(): global _root_window, _canvas, _mouse_enabled try: try: sleep(1) if _root_window != None: _root_window.destroy() except SystemExit, e: print 'Ending graphics raised an exception:', e finally: _root_window = None _canvas = None _mouse_enabled = 0 _clear_keys() def clear_screen(background=None): global _canvas_x, _canvas_y _canvas.delete('all') draw_background() _canvas_x, _canvas_y = 0, _canvas_ys def polygon(coords, outlineColor, fillColor=None, filled=1, smoothed=1, behind=0, width=1): c = [] for coord in coords: c.append(coord[0]) c.append(coord[1]) if fillColor == None: fillColor = outlineColor if filled == 0: fillColor = "" poly = _canvas.create_polygon(c, outline=outlineColor, fill=fillColor, smooth=smoothed, width=width) if behind > 0: _canvas.tag_lower(poly, behind) # Higher should be more visible return poly def square(pos, r, color, filled=1, behind=0): x, y = pos coords = [(x - r, y - r), (x + r, y - r), (x + r, y + r), (x - r, y + r)] return polygon(coords, color, color, filled, 0, behind=behind) def circle(pos, r, outlineColor, fillColor, endpoints=None, style='pieslice', width=2): x, y = pos x0, x1 = x - r - 1, x + r y0, y1 = y - r - 1, y + r if endpoints == None: e = [0, 359] else: e = list(endpoints) while e[0] > e[1]: e[1] = e[1] + 360 return _canvas.create_arc(x0, y0, x1, y1, outline=outlineColor, fill=fillColor, extent=e[1] - e[0], start=e[0], style=style, width=width) def image(pos, file="../../blueghost.gif"): x, y = pos # img = PhotoImage(file=file) return _canvas.create_image(x, y, image = Tkinter.PhotoImage(file=file), anchor = Tkinter.NW) def refresh(): _canvas.update_idletasks() def moveCircle(id, pos, r, endpoints=None): global _canvas_x, _canvas_y x, y = pos # x0, x1 = x - r, x + r + 1 # y0, y1 = y - r, y + r + 1 x0, x1 = x - r - 1, x + r y0, y1 = y - r - 1, y + r if endpoints == None: e = [0, 359] else: e = list(endpoints) while e[0] > e[1]: e[1] = e[1] + 360 edit(id, ('start', e[0]), ('extent', e[1] - e[0])) move_to(id, x0, y0) def edit(id, *args): _canvas.itemconfigure(id, **dict(args)) def text(pos, color, contents, font='Helvetica', size=12, style='normal', anchor="nw"): global _canvas_x, _canvas_y x, y = pos font = (font, str(size), style) return _canvas.create_text(x, y, fill=color, text=contents, font=font, anchor=anchor) def changeText(id, newText, font=None, size=12, style='normal'): _canvas.itemconfigure(id, text=newText) if font != None: _canvas.itemconfigure(id, font=(font, '-%d' % size, style)) def changeColor(id, newColor): _canvas.itemconfigure(id, fill=newColor) def line(here, there, color=formatColor(0, 0, 0), width=2): x0, y0 = here[0], here[1] x1, y1 = there[0], there[1] return _canvas.create_line(x0, y0, x1, y1, fill=color, width=width) ############################################################################## ### Keypress handling ######################################################## ############################################################################## # We bind to key-down and key-up events. _keysdown = {} _keyswaiting = {} # This holds an unprocessed key release. We delay key releases by up to # one call to keys_pressed() to get round a problem with auto repeat. _got_release = None def _keypress(event): global _got_release #remap_arrows(event) _keysdown[event.keysym] = 1 _keyswaiting[event.keysym] = 1 # print event.char, event.keycode _got_release = None def _keyrelease(event): global _got_release #remap_arrows(event) try: del _keysdown[event.keysym] except: pass _got_release = 1 def remap_arrows(event): # TURN ARROW PRESSES INTO LETTERS (SHOULD BE IN KEYBOARD AGENT) if event.char in ['a', 's', 'd', 'w']: return if event.keycode in [37, 101]: # LEFT ARROW (win / x) event.char = 'a' if event.keycode in [38, 99]: # UP ARROW event.char = 'w' if event.keycode in [39, 102]: # RIGHT ARROW event.char = 'd' if event.keycode in [40, 104]: # DOWN ARROW event.char = 's' def _clear_keys(event=None): global _keysdown, _got_release, _keyswaiting _keysdown = {} _keyswaiting = {} _got_release = None def keys_pressed(d_o_e=Tkinter.tkinter.dooneevent, d_w=Tkinter.tkinter.DONT_WAIT): d_o_e(d_w) if _got_release: d_o_e(d_w) return _keysdown.keys() def keys_waiting(): global _keyswaiting keys = _keyswaiting.keys() _keyswaiting = {} return keys # Block for a list of keys... def wait_for_keys(): keys = [] while keys == []: keys = keys_pressed() sleep(0.05) return keys def remove_from_screen(x, d_o_e=Tkinter.tkinter.dooneevent, d_w=Tkinter.tkinter.DONT_WAIT): _canvas.delete(x) d_o_e(d_w) def _adjust_coords(coord_list, x, y): for i in range(0, len(coord_list), 2): coord_list[i] = coord_list[i] + x coord_list[i + 1] = coord_list[i + 1] + y return coord_list def move_to(object, x, y=None, d_o_e=Tkinter.tkinter.dooneevent, d_w=Tkinter.tkinter.DONT_WAIT): if y is None: try: x, y = x except: raise 'incomprehensible coordinates' horiz = True newCoords = [] current_x, current_y = _canvas.coords(object)[0:2] # first point for coord in _canvas.coords(object): if horiz: inc = x - current_x else: inc = y - current_y horiz = not horiz newCoords.append(coord + inc) _canvas.coords(object, *newCoords) d_o_e(d_w) def move_by(object, x, y=None, d_o_e=Tkinter.tkinter.dooneevent, d_w=Tkinter.tkinter.DONT_WAIT, lift=False): if y is None: try: x, y = x except: raise Exception, 'incomprehensible coordinates' horiz = True newCoords = [] for coord in _canvas.coords(object): if horiz: inc = x else: inc = y horiz = not horiz newCoords.append(coord + inc) _canvas.coords(object, *newCoords) d_o_e(d_w) if lift: _canvas.tag_raise(object) def writePostscript(filename): "Writes the current canvas to a postscript file." psfile = file(filename, 'w') psfile.write(_canvas.postscript(pageanchor='sw', y='0.c', x='0.c')) psfile.close() ghost_shape = [ (0, - 0.5), (0.25, - 0.75), (0.5, - 0.5), (0.75, - 0.75), (0.75, 0.5), (0.5, 0.75), (- 0.5, 0.75), (- 0.75, 0.5), (- 0.75, - 0.75), (- 0.5, - 0.5), (- 0.25, - 0.75) ] if __name__ == '__main__': begin_graphics() clear_screen() ghost_shape = [(x * 10 + 20, y * 10 + 20) for x, y in ghost_shape] g = polygon(ghost_shape, formatColor(1, 1, 1)) move_to(g, (50, 50)) circle((150, 150), 20, formatColor(0.7, 0.3, 0.0), endpoints=[15, - 15]) sleep(2)