From e5fe256547f7fed0d2825fd68e08bb45e5633774 Mon Sep 17 00:00:00 2001 From: Tom Wang Date: Sun, 3 May 2020 23:34:48 -0700 Subject: [PATCH] Update hanoi_class.py - converting to class for better program flow (no need for global vars, focus changes when button clicks) - WIP version --- hanoi_class.py | 302 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 hanoi_class.py diff --git a/hanoi_class.py b/hanoi_class.py new file mode 100644 index 0000000..bfe4ec9 --- /dev/null +++ b/hanoi_class.py @@ -0,0 +1,302 @@ +# -*- coding: utf-8 -*- +""" +Created on Sat Apr 25 21:18:50 2020 + +@author: cpan +""" + +import tkinter as tk +import time + +class Hanoi: + + def __init__(self, tkroot, num_disks=3, canvas_w=500, canvas_h=400): + self.num_disks = num_disks + self.canvas_w = canvas_w + self.canvas_h = canvas_h + + self._gap = 2 + self._speed = 0.001 # in seconds + self._step = 2 + self._pegs = [] + self._pegstate = [[], [], []] + + self._tkroot = tkroot + self._frame = tk.Frame(self._tkroot) + self._lbl_disks = tk.Label(self._frame, text="No. of Disks: ") + self._ent_disks = tk.Entry(self._frame, width=5) + self._btn_start = tk.Button(self._frame, text="Start", width=6, + command=self._cmd_start) + self._btn_reset = tk.Button(self._frame, text="Reset", width=6, + command=self._cmd_reset) + self._lbl_speed = tk.Label(self._frame, text="Speed: ") + self._var_speed = tk.StringVar(self._tkroot) + self._opt_speed = tk.OptionMenu(self._frame, self._var_speed, + *{'slow', 'normal', 'fastest'}) + self._canvas = tk.Canvas(self._tkroot, width=canvas_w, height=canvas_h) + self._init_tkwindow() + + def _init_tkwindow(self): + self._tkroot.title('Hanoi Tower') + self._lbl_disks.pack(side=tk.LEFT) + self._ent_disks.insert(0, str(self.num_disks)) + self._ent_disks.bind('', self._ent_return) + self._ent_disks.bind('', self._ent_focus) + self._ent_disks.pack(side=tk.LEFT, padx=5) + self._btn_start.pack(side=tk.LEFT, padx=5) + self._btn_reset.pack(side=tk.LEFT, padx=5) + self._lbl_speed.pack(side=tk.LEFT) + self._var_speed.set('normal') + self._opt_speed.config(width=6, takefocus=True) + self._opt_speed.pack(side=tk.LEFT) + self._frame.pack(side=tk.TOP, pady=5) + self._canvas.pack() + self._btn_start.focus_set() + self._var_speed.trace('w', self._var_speed_changed) + self._tkroot.lift() + self._tkroot.focus_force() + + def _var_speed_changed(self, *args): + self._opt_speed.focus_set() + speed_opt = {'slow': 0.001, 'normal': 0.001, 'fastest': 0} + step_opt = {'slow': 1, 'normal': 2, 'fastest': 1} + self._speed = speed_opt.get(self._var_speed.get()) + self._step = step_opt.get(self._var_speed.get()) + print(self._speed) + + def _cmd_start(self): + self._btn_reset.focus_set() + self._btn_start.config(state='disabled') + + def _cmd_reset(self): + self._btn_start.focus_set() + self._btn_start.config(state='normal') + + def _run_hanoi(self): + pass + + def _ent_return(self): + pass + + def _ent_focus(self): + pass + + def _reset_hanoi(self): + pass + + +# gbl_num_disks = 3 +# GAP = 2 +# CANVAS_W = 500 +# CANVAS_H = 400 +# gbl_speed = 0.001 # in seconds +# gbl_step = 2 +# gbl_pegs = [] +# gbl_pegstate = [[], [], []] +# gbl_disks = [] +# gbl_tkroot = tk.Tk() +# gbl_tkroot.title('Hanoi Tower') +# gbl_canvas = None +# gbl_ready = True + + +# def setup_gui(): +# global gbl_canvas + +# def ent_return(event): +# event.widget.tk_focusNext().focus() + +# def get_ent_focus(event): +# global gbl_num_disks + +# try: +# new_num = int(ent_disks.get()) +# gbl_num_disks = new_num +# draw_init_setting() +# except Exception as err: +# ent_disks.delete(0, tk.END) +# ent_disks.insert(0, str(gbl_num_disks)) +# print(repr(err)) +# # print(gbl_num_disks) + +# # options row +# tk_row = tk.Frame(gbl_tkroot) +# tk.Label(tk_row, text="No. of Disks: ").pack(side=tk.LEFT) +# ent_disks = tk.Entry(tk_row, width=5) +# ent_disks.insert(0, str(gbl_num_disks)) +# ent_disks.bind('', ent_return) +# ent_disks.bind('', get_ent_focus) +# ent_disks.pack(side=tk.LEFT, padx=5) +# btn_start = tk.Button(tk_row, text="Start", width=6, command=run_hanoi) +# # btn_start.bind('', run_hanoi) +# btn_start.pack(side=tk.LEFT, padx=5) +# btn_reset = tk.Button(tk_row, text="Reset", width=6, command=reset_hanoi) +# # btn_reset.bind('', reset_hanoi) +# btn_reset.pack(side=tk.LEFT, padx=5) +# tk.Label(tk_row, text="Speed: ").pack(side=tk.LEFT) +# tk_var = tk.StringVar(gbl_tkroot) +# tk_var.set('normal') +# tk_opt_menu = tk.OptionMenu(tk_row, tk_var, +# *{'slow', 'normal', 'fastest'}) +# tk_opt_menu.config(width=6, takefocus=True) +# tk_opt_menu.pack(side=tk.LEFT) +# tk_row.pack(side=tk.TOP, pady=5) + +# # animation canvas +# gbl_canvas = tk.Canvas(gbl_tkroot, width=CANVAS_W, height=CANVAS_H) +# gbl_canvas.pack() +# btn_start.focus_set() + +# def change_speed(*args): +# global gbl_speed, gbl_step +# speed_opt = {'slow': 0.001, 'normal': 0.001, 'fastest': 0} +# step_opt = {'slow': 1, 'normal': 2, 'fastest': 1} +# gbl_speed = speed_opt.get(tk_var.get()) +# gbl_step = step_opt.get(tk_var.get()) +# # print(gbl_speed) + +# tk_var.trace('w', change_speed) + + +# def run_hanoi(): +# global gbl_ready + +# # t0 = time.time() +# if gbl_ready: +# gbl_ready = False +# try: +# hanoi(gbl_num_disks-1, 0, 1, 2) +# except Exception as err: +# print(f'forced reset: {repr(err)}') +# else: +# pass +# # t1 = time.time() +# # print(t1-t0) + + +# def reset_hanoi(): +# draw_init_setting() + + +# def draw_init_setting(): +# global gbl_pegs, gbl_disks, gbl_pegstate, gbl_ready +# gbl_pegs = [] +# gbl_pegstate = [[], [], []] +# gbl_disks = [] + +# gbl_canvas.delete('all') +# # draw the three pegs a, b, c +# peg_w = 10 +# peg_h = CANVAS_H // 2 +# peg_dist = CANVAS_W // 3 +# x1, y1 = (peg_dist - peg_w) // 2, CANVAS_H // 3 +# x2, y2 = x1 + peg_w, y1 + peg_h + +# for i in range(3): +# gbl_pegs.append(gbl_canvas.create_rectangle(x1, y1, x2, y2, fill = 'black')) +# x1 += peg_dist +# x2 += peg_dist +# gbl_tkroot.update_idletasks() +# gbl_tkroot.update() + +# # create disks on the first peg +# disk_h = peg_h // 16 +# disk_maxw = peg_dist * 2 // 3 +# disk_minw = 2 * peg_w +# x1, y1 = (peg_dist - disk_maxw) // 2, y2 - disk_h - GAP +# x2, y2 = x1 + disk_maxw, y1 + disk_h +# dx = (disk_maxw - disk_minw) // (2 * max(1, gbl_num_disks-1)) +# dx = min(dx, 2 * peg_w) + +# for i in range(gbl_num_disks): +# gbl_disks.insert(0, gbl_canvas.create_rectangle(x1, y1, x2, y2, fill = 'red')) +# gbl_pegstate[0].append(gbl_num_disks - i - 1) +# x1 += dx +# x2 -= dx +# y1 -= disk_h + GAP +# y2 -= disk_h + GAP +# gbl_tkroot.update_idletasks() +# gbl_tkroot.update() + +# gbl_ready = True + + +def move_disk(i, a, b): + global gbl_pegstate, gbl_canvas + disk_num = gbl_pegstate[a].pop() + if disk_num != i: + raise RuntimeError(f'Trying to move disk piece #{i} from peg {a}\ + to peg {b} that does not exist.') + # disk = gbl_disks[i] + +# # Lift the disk above peg a +# px1, py1, px2, py2 = gbl_canvas.bbox(gbl_pegs[a]) +# while True: +# x1, y1, x2, y2 = gbl_canvas.bbox(disk) +# if y2 < py1: +# break +# gbl_canvas.move(disk, 0, -gbl_step) +# gbl_tkroot.update_idletasks() +# gbl_tkroot.update() +# time.sleep(gbl_speed) + +# # Move to peg b +# px1, py1, px2, py2 = gbl_canvas.bbox(gbl_pegs[b]) +# new_center = (px1 + px2) // 2 +# x1, y1, x2, y2 = gbl_canvas.bbox(disk) +# center = (x1 + x2) // 2 + +# while center < new_center: +# gbl_canvas.move(disk, gbl_step, 0) +# gbl_tkroot.update_idletasks() +# gbl_tkroot.update() +# time.sleep(0.7*gbl_speed) # faster +# x1, y1, x2, y2 = gbl_canvas.bbox(disk) +# center = (x1 + x2) // 2 + +# while center > new_center: +# gbl_canvas.move(disk, -gbl_step, 0) +# gbl_tkroot.update_idletasks() +# gbl_tkroot.update() +# time.sleep(0.7*gbl_speed) # faster +# x1, y1, x2, y2 = gbl_canvas.bbox(disk) +# center = (x1 + x2) // 2 + +# # Drop down +# disk_h = y2 - y1 +# new_bottom = py2 - disk_h * len(gbl_pegstate[b]) - GAP +# while True: +# x1, y1, x2, y2 = gbl_canvas.bbox(disk) +# if y2 >= new_bottom: +# break +# gbl_canvas.move(disk, 0, gbl_step) +# gbl_tkroot.update_idletasks() +# gbl_tkroot.update() +# time.sleep(gbl_speed) + +# gbl_pegstate[b].append(i) + + +def hanoi(n :int, a :int, b :int, c :int): + ''' + Hanoi algorithm: move n pieces from a to c, using b as buffer. + For each move, call animate() to show the move + ''' + if n < 0: + return + hanoi(n-1, a, c, b) + move_disk(n, a, c) # move nth piece from peg a to peg c + hanoi(n-1, b, a, c) + + +def main(): + + tkroot = tk.Tk() + + hanoi = Hanoi(tkroot) + + tkroot.mainloop() + + +if __name__ == "__main__": + main() \ No newline at end of file