class Ventana(): def __init__(self, titulo, alto, ancho): assert isinstance(titulo, str) assert isinstance(alto, int) and alto > 0 assert isinstance(ancho, int) and ancho > 0 ## Crea la ventana y un canvas para dibujar self.root = TK.Tk() self.root.title(titulo) self.canvas = TK.Canvas(self.root, width=ancho, height=alto) self.canvas.pack() ## Crea un TurtleScreen y la tortuga para dibujar self.fondo_ventana = TurtleScreen(self.canvas) self.fondo_ventana.setworldcoordinates(0, alto, ancho, 0) ## Establece el color de fondo self.canvas["bg"] = "blue" self.canvas.pack() ## Crea una tortuga para dibujar self.pencil = RawTurtle(self.fondo_ventana) self.pencil.pencolor("white")
class FractalCanvas(object): def __init__(self, parent, levels): self.levels = levels # Toggles screen update rate self.slow_drawing = False # Draw button button = Button(parent, text='Draw Fractal', command=self._draw_click) button.pack() width, height = (600, 600) self.canvas = Canvas(parent, width=600, height=600) # Constrain resizing to a 1:1 aspect ratio self.canvas.winfo_toplevel().aspect(1, 1, 1, 1) self.canvas.pack(fill=BOTH, expand=YES) # Setup a turtle self.turtleScreen = TurtleScreen(self.canvas) # 5px of padding self.turtleScreen.setworldcoordinates(-5, -height - 5, width + 5, 5) self.turtle = RawTurtle(self.turtleScreen) self.turtleScreen.colormode(255) # Listen to resize events self.canvas.bind('<Configure>', self._resize_and_draw) # Do an initial draw self.slow_drawing = True self._resize_and_draw() self.slow_drawing = False def _draw_click(self): """Handler for button click.""" # Draw the fractal slowly when we press the button, but quickly # if we're drawing for a resize self.slow_drawing = True self._resize_and_draw() self.slow_drawing = False def _resize_and_draw(self, event=None): """Handler for when the canvas resizes (due to a window resize).""" self.draw(self.canvas.winfo_width(), self.canvas.winfo_height()) def draw(self, width, height): """Draws the fractal.""" pass def update_screen(self): """ Conditionally updates the screen. If self.slow_drawing is set, then this method forces image data to be pushed to the screen, otherwise it does nothing. """ if self.slow_drawing: self.turtleScreen.update()
class Ventana(): def __init__(self, titulo, alto, ancho): assert isinstance(titulo, str) assert isinstance(alto, int) and alto > 0 assert isinstance(ancho, int) and ancho > 0 self.root = TK.Tk() self.root.title(titulo) self.canvas = TK.Canvas(self.root, width=ancho, height=alto) self.canvas.pack() self.fondo_ventana = TurtleScreen(self.canvas) self.fondo_ventana.setworldcoordinates(0, alto, ancho, 0) self.canvas["bg"] = "gold" self.canvas.pack() self.pencil = RawTurtle(self.fondo_ventana) self.pencil.pencolor("white")
class Snake(): """ Implementa un Snake que puede moverse en una cuadrícula imaginaria dede m filas por n columnas. Las filas y columnas se numeran a partir de 1. El snake tendrá una largo, que incluye su cabeza. El largo tiene que ser mayor que 1. La cabeza se pinta de un color y los segmentos de su cuerpo en otro. El snake se puede mover en forma horizontal o vertical. Para mover el snake se utilizan las flechas direccionales y la tecla "x" (que también mueve el snake hacia abajo). """ ## Atributos de clase que definen el tamaño por ## defecto de la cuadrícula. FILAS = 40 COLUMNAS = 30 ## Atributos de clase que define el tamaño (en pixeles) ## de cada elemento de la cuadrícula. DIM = 10 ## Atributo de clase que defifne el tamaño por ## defecto del snake. LARGO_SNAKE = 4 ## Atributos de clase que define a partir de que ## coordenadas en el eje horizontal(x) y vertical(y) ## se empieza a dibujar la cuadrícula. DY = 20 DX = 20 @staticmethod def deme_posicion(i,j): """ Retorna la posicion superior izquierda en eje x, eje y de un elemento i,j en la cuadrícula imaginaria. Entradas: i : Fila en la cuadrícula imaginaria. j : Columna en la cuadrícula imaginaria. Salidas: (x,y) : Posición de la esquina superior izquierda en donde se encuentra la entrada (i,j) Supuesto: (i,j) es una posición válida en la cuadrícula imaginaria. """ x = Snake.DX + (j - 1) * (Snake.DIM + 1) y = Snake.DY + (i - 1) * (Snake.DIM + 1) return (x, y) def __init__(self, filas = FILAS, columnas = COLUMNAS, largo = LARGO_SNAKE, cabeza = "blue", cuerpo="red"): """Crea la culebra y su cuadrícula. Entradas: filas : # de filas en la cuadrícula imaginaria. columnas : # de columna en la cuadrícula imaginaria. largo : Tamaño del snake incluyendo la cabeza. Salidas: Snake en una cuadrícula según las dimensiones indicadas. Supuesto: La ventana, según las dimensiones establecidas, cabe en la ventana. El snake cabe en la cuadrícula. """ ## Funciones locales al constructor ## def segmento(color, i, j): """ Dibuja un segmento del snake en posicion i, j con el color indicado. Entradas: color : Color del segmento a dibujar. (i,j) : Ubicación en que se desea dibujar el segmento en la cuadrícula imaginaria. Salidas: Dibujo del segemento con el color indicado en la posición (i,j) de la cuadrícula imaginaria. Supuesto: El color es uno válido en Tkinter. (i,j) es una posición válida en la cuadrícula imaginaria. """ ## Determina la posición en los ejes ## reales de la posición (i,j) de la ## cuadrícula imaginaria. x, y = Snake.deme_posicion(i, j) ## Prepara el lápiz para dibujar ## un rectánculo relleno. self.lapiz.fillcolor(color) self.lapiz.pu() self.lapiz.setpos(x, y) self.lapiz.seth(0) self.lapiz.pd() self.lapiz.begin_fill() ## Dibuja el rectángulo con 4 ## movimientos !!! for i in range(4): self.lapiz.fd(Snake.DIM+1) self.lapiz.left(90) ## Cierra el relleno. self.lapiz.end_fill() def mueva_snake(direccion): """ Mueve el snake en la dirección indicada. Entradas: direccion : Dirección en que se mueve el snake. Salidas: Actualización del snkae en pantalla. Si el snake pega contra un borde o contra ella misma no avanza. Supuesto: dirección es alguno de los valores "Up", "Down", "Left" o "Right". """ ## Obtiene la posición actual de la cabeza del snake. ci, cj = self.snake[-1][0], self.snake[-1][1] ## Calcula la nueva posición de la cabeza según ## la dirección indicada por el usuario. if direccion == "Up": i, j = (ci if ci == 1 else ci - 1, cj) elif direccion == "Down": i, j = (ci if ci == self.filas else ci + 1, cj) elif direccion == "Left": i, j = (ci, cj if cj == 1 else cj - 1) elif direccion == "Right": i, j = (ci, cj if cj == self.columnas else cj + 1) if not((i,j) in self.snake): ## se asegura que el snake ## no choque contra sí mismo !! self.scr.tracer(False) ## Borra la cola. La cola está en la ## posición 0 de la lista self.snake. segmento("white", self.snake[0][0], self.snake[0][1]) del self.snake[0] ## Pinta la antigua cabeza de color azul para que sea ## parte del cuerpo. La cabeza es el último elemento ## de la lista self.snake. segmento(cuerpo, self.snake[-1][0], self.snake[-1][1]) ## Agrega la nueva cabeza. La cabeza nueva cabeza ## se agrega al final de la lista. self.snake.append((i, j)) segmento(cabeza, i, j) self.scr.tracer(True) def dibuja_horizontales(): """ Dibuja las filas+1 lineas horizontales. Entradas: Ninguna. Salidas: Dibujo de las líneas horizontales de la cuadrícula imaginaria en que se moverá el snake. """ dy = Snake.DY ## Posición en eje y de la primera ## línea horizontal. ## Calcula la posición en eje x en que finalizan ## todas la líneas horizontales. posFin_x = Snake.DX + self.columnas * (Snake.DIM + 1) for i in range(self.filas+1): self.lapiz.up() self.lapiz.setpos(Snake.DX, dy) self.lapiz.down() self.lapiz.setpos(posFin_x, dy) dy += Snake.DIM + 1 def dibuja_verticales(): """ Dibuja las columnas+1 lineas verticales Entradas: Ninguna. Salidas: Dibujo de las líneas verticales de la cuadrícula imaginaria en que se moverá el snake. """ dx = Snake.DX ## Posición en eje x de la primera ## línea vertical. ## Calcula la posición en eje y en que finalizan ## todas la líneas verticales. posFin_y = Snake.DY + self.filas * (Snake.DIM + 1) for j in range(self.columnas+1): self.lapiz.up() self.lapiz.setpos(dx,Snake.DY) self.lapiz.down() self.lapiz.setpos(dx, posFin_y) dx += Snake.DIM + 1 def dibuja_escenario(): """ Dibuja la cuadrícula y el snake: el cuerpo en azul y la cabeza en rojo. Entradas: Ninguna. Salidas: Dibujo de la cuadrícula imaginaria en que se moverá el snake. """ self.scr.tracer(False) ## Dibuja la cuadricula dibuja_horizontales() dibuja_verticales() ## Dibuja el cuerpo del snake for x in self.snake[:-1]: segmento(cuerpo,x[0],x[1]) ## Dibuja la cabeza segmento(cabeza, self.snake[-1][0], self.snake[-1][1]) self.scr.tracer(True) ############################################################ ## Inicio de las instrucciones del constructor __init__. ## ############################################################ ## Verifica restricciones, sino se cumplen dispara un ## SnakeError. if not (isinstance(filas,int) and isinstance(columnas,int) and \ isinstance(largo,int)): raise SnakeError("Type Error") else: ## Guarda las dimensiones de la cuadrícula ## imaginaria y del snake en atributos de instancia. self.filas = filas self.columnas = columnas self.largo = largo ## Crea la ventana y estable un título para la misma. self.root = TK.Tk() self.root.title("Snake v1.0 / 2014") ## Obtiene la posición (x,y) en la ventana de la ## última fila y columna de la cuadrícula imaginaria, ## lo anterior con el objetivo de establecer el ## tamaño de la ventana. x, y = Snake.deme_posicion(filas, columnas) ## Calcula el ancho y el alto de la ventana anchoVentana = x + Snake.DX + Snake.DIM + 1 altoVentana = y + Snake.DY + Snake.DIM + 1 ## Crea un área de dibujo (canvas) con un ancho y ## alto que está en función de la cuadrícula ## en que se moverá el snake. self.canvas = TK.Canvas(self.root, width=anchoVentana, height=altoVentana) self.canvas.pack() ## Crea un área de dibujo para tortugas. self.scr = TurtleScreen(self.canvas) ## Establece un sistema de coordenadas en donde ## el punto (0,0) se ubica en la esquina superior ## izquierda. ## El eje x va de 0 a positivos de izquierda a derecha. ## El eje y va de 0 a positivos de arriba hacia abajo. self.scr.setworldcoordinates(0,altoVentana,anchoVentana,0) self.scr.reset() ## Crea la tortuga para dibujar self.lapiz = RawTurtle(self.scr) self.lapiz.ht() ## Crea el snake. ## El snake corresponde a una lista de pares ## ordenados (x, y) en donde cada uno de estos ## elementos corresponde a un segmento del snake. ## La cabeza del snake se ubica en la última ## posición de la lista. ## El snake creado queda en posición horizontal ## y su cabeza mira hacia la derecha. La cola ## se ubica en la posición 1,1. Observe que se ## utilizaron listas por comprensión para ## construir el snake. En este punto el snake ## no es visible. self.snake = [(1,eje_y) for eje_y in range(1, self.largo + 1)] ## Dibuja la cuadrícula y el snake. dibuja_escenario() ## Establece el binding entre las teclas para el movimiento ## del snake y las funciones que atenderán dicho movimiento. ## En todos los casos se utiliza la misma función solo que ## el parámetro con que se invoca es diferente. self.scr.onkeypress(lambda : mueva_snake("Up"), "Up") # Arriba self.scr.onkeypress(lambda : mueva_snake("Right"), "Right") # Derecha self.scr.onkeypress(lambda : mueva_snake("Down"), "Down") # Abajo self.scr.onkeypress(lambda : mueva_snake("Left"), "Left") # Izquierda self.scr.onkeypress(lambda : mueva_snake("Down"), "x") # Otra vez abajo ## Se queda escuchando los eventos. ## El programa termina cuando el usuario cierre la ventana. self.scr.listen()
def loadAndDraw(load, draw, indicatorList, trades): def get_mouse_click_coor(x, y): print(x, y) barNumber = round(x / 10) barNumber = max(1, barNumber) print("Bar Number: ", barNumber, " ", d[startPt + barNumber - 1], " ", o[startPt + barNumber - 1], " ", highestHigh) # tkMessageBox("Information",str(barNumber) # # trtl.write('Vivax Solutions', font=("Arial", 20, "bold")) # chosing the font ## trtl.goto(10,highestHigh-.05*(highestHigh - lowestLow)) ## trtl.pendown() indexVal = startPt + barNumber - 1 outPutStr = str(d[indexVal]) + " " + str(o[indexVal]) + " " + str( h[indexVal]) + " " + str(l[indexVal]) + " " + str( c[indexVal]) # chosing the font root.focus_set() T.focus_set() T.insert(tk.END, outPutStr + "\n") ## trtl.goto(20,highestHigh-60) ## trtl.write(str(o[50-(50-barNumber)]), font=("Arial", 8, "bold")) # chosing the font ## trtl.goto(20,highestHigh-80) ## trtl.write(str(h[50-(50-barNumber)]), font=("Arial", 8, "bold")) # chosing the font ## trtl.goto(20,highestHigh-100) ## trtl.write(str(l[50-(50-barNumber)]), font=("Arial", 8, "bold")) # chosing the font ## trtl.goto(20,highestHigh-120) ## trtl.write(str(c[50-(50-barNumber)]), font=("Arial", 8, "bold")) # chosing the font ## ## #root.withdraw() if load == True: cnt = 0 file = askopenfilename( filetypes=(('CSV files', '*.csv'), ('TXT files', '*.txt'), ('POR files', '*.por')), title='Select Markets or Ports. To Test- CSV format only!') with open(file) as f: f_csv = csv.reader(f) numDecs = 0 for row in f_csv: numCols = len(row) cnt += 1 d.append(int(row[0])) dt.append(datetime.datetime.strptime(row[0], '%Y%m%d')) o.append(float(row[1])) h.append(float(row[2])) l.append(float(row[3])) c.append(float(row[4])) v.append(float(row[5])) oi.append(float(row[6])) oString = str(o[-1]) if '.' in oString: decLoc = oString.index('.') numDecs = max(numDecs, len(oString) - decLoc - 1) xDate = list() yVal = list() zVal = list() w.Button5.configure(state="normal") w.Entry1.insert(0, str(d[-1])) if draw == True: startDrawDateStr = w.Entry1.get() startDrawDate = int(startDrawDateStr) cnt = -1 for x in range(0, len(d)): cnt += 1 if startDrawDate >= d[x]: startPt = x numBarsPlot = 60 if startPt + numBarsPlot > len(d): startPt = len(d) - (numBarsPlot + 1) print(startPt, " ", len(d), " ", numBarsPlot) indicCnt = 0 screen = TurtleScreen(w.Canvas1) trtl = RawTurtle(screen) screen.tracer(False) screen.bgcolor('white') clr = ['red', 'green', 'blue', 'yellow', 'purple'] trtl.pensize(6) trtl.penup() trtl.color("black") highestHigh = 0 lowestLow = 99999999 # scaleMult = 10**numDecs scaleMult = 1 for days in range(startPt, startPt + numBarsPlot): if h[days] * scaleMult > highestHigh: highestHigh = h[days] * scaleMult if l[days] * scaleMult < lowestLow: lowestLow = l[days] * scaleMult hhllDiffScale = (highestHigh - lowestLow) / 1.65 hhllDiff = highestHigh - lowestLow botOfChart = lowestLow screen.setworldcoordinates(-10, highestHigh - hhllDiffScale, 673, highestHigh) print(highestHigh, " ", lowestLow) m = 0 trtl.setheading(0) trtl.penup() for i in range(startPt, startPt + numBarsPlot + 1): m = m + 1 trtl.goto(m * 10, h[i] * scaleMult) trtl.pendown() trtl.goto(m * 10, l[i] * scaleMult) trtl.penup() trtl.goto(m * 10, c[i] * scaleMult) trtl.pendown() trtl.goto(m * 10 + 5, c[i] * scaleMult) trtl.penup() trtl.goto(m * 10, o[i] * scaleMult) trtl.pendown() trtl.goto(m * 10 - 5, o[i] * scaleMult) trtl.penup() trtl.goto(10, highestHigh) print("Indicator List: ", indicatorList) if len(indicatorList) != 0: movAvgParams = list([]) if "movAvg" in indicatorList: movAvgVal = 0 movAvgParamIndexVal = indicatorList.index("movAvg") movAvgParams.append(indicatorList[movAvgParamIndexVal + 1]) movAvgParams.append(indicatorList[movAvgParamIndexVal + 2]) movAvgParams.append(indicatorList[movAvgParamIndexVal + 3]) for j in range(0, 3): n = 0 trtl.penup() if j == 0: trtl.color("red") if j == 1: trtl.color("green") if j == 2: trtl.color("blue") for i in range(startPt, startPt + numBarsPlot): n = n + 1 movAvgVal = 0 for k in range(i - movAvgParams[j], i): movAvgVal = movAvgVal + c[k] * scaleMult if movAvgParams[j] != 0: movAvgVal = movAvgVal / movAvgParams[j] if i == startPt: trtl.goto(n * 10, movAvgVal) trtl.pendown() trtl.goto(n * 10, movAvgVal) trtl.penup() # print("PlotTrades : ",plotTrades) if trades.draw: debugTradeDate = tradeDate[0] debugDate = d[startPt] n = 0 while debugTradeDate <= debugDate: n += 1 debugTradeDate = tradeDate[n] m = 0 for i in range(startPt, startPt + numBarsPlot): m = m + 1 debugDate = d[i] if debugDate == debugTradeDate: trtl.penup() tradeValue = tradePrice[n] if tradeType[n] == "buy": trtl.color("Green") trtl.goto(m * 10 - 5, tradeValue - hhllDiff * .03) trtl.pensize(3) trtl.pendown() trtl.goto(m * 10, tradeValue) trtl.goto(m * 10 + 5, tradeValue - hhllDiff * .03) trtl.penup() if tradeType[n] == "sell": trtl.color("Red") trtl.goto(m * 10 - 5, tradeValue + hhllDiff * .03) trtl.pensize(3) trtl.pendown() trtl.goto(m * 10, tradeValue) trtl.goto(m * 10 + 5, tradeValue + hhllDiff * .03) trtl.penup() if tradeType[n] == "longLiq": trtl.color("Blue") trtl.penup() trtl.goto(m * 10 - 5, tradeValue) trtl.pensize(3) trtl.pendown() trtl.goto(m * 10 + 5, tradeValue) trtl.penup() trtl.pensize(1) print("Found a trade: ", tradeValue, " ", debugTradeDate, " m= ", m, " ", tradeValue - hhllDiff * .05) n += 1 if n < len(tradeDate): debugTradeDate = tradeDate[n] trtl.color("black") trtl.goto(-10, botOfChart) trtl.pendown() trtl.goto(673, botOfChart) trtl.penup() trtl.goto(-10, botOfChart) m = 0 for i in range(startPt, startPt + numBarsPlot): if i % 10 == 0: m = m + 1 trtl.pendown() trtl.write(str(d[i]), font=("Arial", 8, "bold")) # chosing the font trtl.penup() trtl.goto(m * 100, botOfChart) trtl.penup() trtl.goto(628, highestHigh) trtl.pendown() trtl.goto(628, botOfChart) trtl.penup() m = 0 vertIncrement = hhllDiff / 10 for i in range(0, 11): trtl.goto(630, highestHigh - m * vertIncrement) trtl.pendown() trtl.write(str(highestHigh - m * vertIncrement), font=("Arial", 8, "bold")) trtl.penup() m += 1 # turtle.done() screen.onscreenclick(get_mouse_click_coor)
class TurtleGraphics(BasicGUI): """GUI with graphics created using 'turtle'.""" _WORLD_COORDS = (-2, -2, 10, 10) _PEG_OFFSET = (0, 0.4) HADES = (0, 12) best_move = None @classmethod def _add_offset(cls, position): """Adds offset to peg's position coordinates.""" peg_pos = tuple(map(add, position, cls._PEG_OFFSET)) peg_pos = tuple(round(i, 1) for i in peg_pos) return peg_pos @classmethod def _subtract_offset(cls, position): """Subtracts offset from peg's position coordinates.""" peg_pos = tuple(map(sub, position, cls._PEG_OFFSET)) peg_pos = tuple(map(int, peg_pos)) return peg_pos def _draw_board(self): """Draws board.""" tri = ((-1.5, -0.5), (4, 9.5), (9.5, -0.5)) artist = RawPen(self.window) # Draws grooves in wood: artist.pen(pendown=False, pensize=2, speed=0) x1, y1, x2, y2 = __class__._WORLD_COORDS for y in range(y1, y2 + 1, 2): artist.goto(x1, y) artist.pendown() artist.goto(x2, y) artist.penup() # Draws board: artist.pen(pencolor=(34, 16, 0), fillcolor=(51, 25, 0), pensize=6, speed=0) artist.goto(tri[-1]) artist.pendown() artist.begin_fill() for coord in tri: artist.goto(coord) artist.end_fill() # Draws peg holes: artist.pen(pencolor="gray", fillcolor="black", pensize=1) for peg_hole in self.game.board: artist.penup() artist.goto(peg_hole) artist.pendown() artist.begin_fill() artist.circle(0.4) artist.end_fill() artist.penup() artist.goto(__class__.HADES) def _place_pegs(self): """Places pegs.""" for peg_hole in self.game.board: if self.game.board[peg_hole]: start_point = __class__._add_offset(peg_hole) peg = Peg(start_point, self) self.peg_dir.append(peg) def _add_callbacks(self): """Adds callbacks to buttons.""" self.undo_btn["command"] = self.game.undo self.restart_btn["command"] = self.game.restart self.show_moves_btn["command"] = self.show_legal_moves self.best_move_btn["command"] = self.show_best_move def _find_best_move(self): """Finds best move possible for current game.""" if len(self.game.moves) <= 3: with shelve.open("paths") as db: best_paths = db[str(self.game.moves)] best_path = choice(best_paths) else: self.path_finder(self.game) best_path = self.path_finder.best_path best_move = best_path[len(self.game.moves)] best_move = (__class__._add_offset(best_move[0]), best_move[1]) return best_move def _disable_all(self): """Disables all buttons and pegs.""" self.undo_btn["state"] = "disabled" self.restart_btn["state"] = "disabled" self.show_moves_btn["state"] = "disabled" self.best_move_btn["state"] = "disabled" for peg in self.peg_dir: peg.moveable = False def _restore_all(self): """Enables pegs and buttons that would normally be enabled.""" self.update_gui() for peg in self.peg_dir: peg.moveable = True def _delayed_callback(self, arrows): """Banishes arrows and restores GUI.""" for arrow in arrows: arrow.banish() self._restore_all() def construct(self): """Constructs graphics.""" self.window = TurtleScreen(self.canvas) self.window.setworldcoordinates(*__class__._WORLD_COORDS) self.window.bgcolor(102, 51, 0) self.peg_dir = [] self.arrow_dir = [] self.graveyard = [] self.path_finder = PathFinder() self._draw_board() self._place_pegs() self._add_callbacks() def update_(self, peg, move): """Updates the graphics when a move is made.""" midpoint = __class__._add_offset(self.game._midpoint(peg, move)) lower_bound = (midpoint[0], midpoint[1] - 0.01) upper_bound = (midpoint[0], midpoint[1] + 0.01) dead_peg = [ peg for peg in self.peg_dir if peg.pos() > lower_bound and peg.pos() < upper_bound ][0] dead_peg.goto(__class__.HADES) self.peg_dir.remove(dead_peg) self.graveyard.append(dead_peg) def erase(self): """Updates the graphics when a move is undone.""" last_peg_pos = __class__._add_offset( tuple(map(add, *self.game.moves[-1]))) last_peg = [ peg for peg in self.peg_dir if abs(peg.pos() - last_peg_pos) < 0.1 ][0] last_peg.goto(__class__._add_offset(self.game.moves[-1][0])) last_peg.start_point = last_peg.pos() revived_peg = self.graveyard.pop() revived_peg.goto(revived_peg.start_point) self.peg_dir.append(revived_peg) def reset_(self): """Updates the graphics when the game is restarted.""" for obj in [self.window, self.peg_dir, self.arrow_dir, self.graveyard]: del obj self.canvas.destroy() self.canvas = Canvas(self.mainframe, width=500, height=500, relief="sunken", borderwidth=3) self.canvas.grid(row=1, column=1, sticky=(N, S, E, W)) self.construct() def show_legal_moves(self): """Shows the player all legal moves.""" self._disable_all() move_count = 0 legal_moves = self.game.find_legal_moves() for val in legal_moves.values(): for move in val: move_count += 1 arrows_needed = move_count - len(self.arrow_dir) for task in range(arrows_needed): self.arrow_dir.append(Arrow(self)) used_arrows = [] arrow_count = 0 for start_peg in legal_moves: for move in legal_moves[start_peg]: arrow = self.arrow_dir[arrow_count] origin = __class__._add_offset(start_peg) destination = tuple(map(add, origin, move)) arrow.draw(origin, destination) used_arrows.append(arrow) arrow_count += 1 self.root.after(3000, self._delayed_callback, used_arrows) def show_best_move(self): """Shows the player the best move to make next.""" self._disable_all() if not self.arrow_dir: self.arrow_dir.append(Arrow(self)) arrow = self.arrow_dir[0] origin = self.best_move[0] destination = tuple(map(add, origin, self.best_move[1])) arrow.draw(origin, destination) self.root.after(3000, self._delayed_callback, [arrow]) def update_peg_moves(self): """Updates move list for all pegs and updates best move, if required.""" legal_moves = self.game.find_legal_moves() for peg in self.peg_dir: board_pos = __class__._subtract_offset(peg.pos()) peg.possible_moves = legal_moves.get(board_pos, []) if legal_moves and self.game.moves: self.best_move = self._find_best_move() def update_gui(self): """Updates GUI to reflect current game conditions.""" legal_moves = self.game.find_legal_moves() if self.game.moves: self.undo_btn["state"] = "!disabled" self.restart_btn["state"] = "!disabled" self.best_move_btn["state"] = "!disabled" else: self.undo_btn["state"] = "disabled" self.restart_btn["state"] = "disabled" if legal_moves: self.show_moves_btn["state"] = "!disabled" else: self.show_moves_btn["state"] = "disabled" if legal_moves and self.game.moves: self.best_move_btn["state"] = "!disabled" else: self.best_move_btn["state"] = "disabled"
class TurtleWidget(CanvasWidget): def newTKWidget(self, parent, hOptions): return super().newTKWidget(parent, hOptions) def initialize(self, hOptions): self.screen = TurtleScreen(self.tkWidget) self.tkTurtle = RawTurtle(self.screen) self.screen.mode('world') self.tkTurtle.setheading(90) if 'speed' in hOptions: self.curSpeed = int(hOptions['speed']) else: self.curSpeed = 1 self.lSaveStack = [] # stack to save/restore state on def setBounds(self, xmin, ymin, xmax, ymax, padding=15): width = xmax - xmin height = ymax - ymin if (width > height): halfdiff = (width - height) / 2 ymin -= halfdiff ymax += halfdiff else: halfdiff = (height - width) / 2 xmin -= halfdiff xmax += halfdiff self.screen.setworldcoordinates( xmin - padding, ymin - padding, xmax + padding, ymax + padding, ) def reset(self): self.screen.reset() def move(self, n): tkTurtle = self.tkTurtle assert isinstance(tkTurtle, RawTurtle) tkTurtle.speed(self.curSpeed) tkTurtle.forward(n) def turn(self, d): tkTurtle = self.tkTurtle assert isinstance(tkTurtle, RawTurtle) tkTurtle.speed(self.curSpeed) tkTurtle.right(d) # --- Turtle state includes these fields: # xpos, ypos, heading, isvisible, isdown def saveState(self): tkTurtle = self.tkTurtle assert isinstance(tkTurtle, RawTurtle) self.lSaveStack.append([ tkTurtle.xcor(), tkTurtle.ycor(), tkTurtle.heading(), tkTurtle.isvisible(), tkTurtle.isdown(), ]) def restoreState(self): tkTurtle = self.tkTurtle assert isinstance(tkTurtle, RawTurtle) if len(self.lSaveStack) == 0: raise Exception("restoreState(): No saved state to restore") lState = self.lSaveStack.pop() saved_x = lState[0] saved_y = lState[1] cur_x = tkTurtle.xcor() cur_y = tkTurtle.ycor() # --- determine whether we need to hide the turtle if tkTurtle.isvisible(): dist = hypot(saved_x - cur_x, saved_y - cur_y) mustHide = (dist > 1) else: mustHide = False if mustHide: tkTurtle.hideturtle() tkTurtle.penup() tkTurtle.setposition(saved_x, saved_y) tkTurtle.setheading(lState[2]) if lState[3] and mustHide: tkTurtle.showturtle() if lState[4]: tkTurtle.pendown() def moveTo(self, x, y): tkTurtle = self.tkTurtle tkTurtle.penup() tkTurtle.hideturtle() tkTurtle.setposition(x, y) tkTurtle.setheading(90) tkTurtle.pendown() tkTurtle.showturtle() def drawAt(self, x, y, func): # --- Must not draw or show movement tkTurtle = self.tkTurtle self.saveState() self.moveTo(x, y) func(self) self.restoreState()