Skip to content

Instantly share code, notes, and snippets.

@andy23512
Created August 2, 2020 17:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andy23512/b79377cd53d0d95ff8308aa2e16a0d50 to your computer and use it in GitHub Desktop.
Save andy23512/b79377cd53d0d95ff8308aa2e16a0d50 to your computer and use it in GitHub Desktop.
#### imports
from tkinter import *
import pandas as pd
#### global constants
CAN_MOVE = '#99CC00'
MOVE_NOMOVE = '#00FF00'
ROTATE = '#FFFF00'
ROTATE_NOMOVE = '#0000FF'
MOVE2_CANMOVE = '#660000'
HAVE_ROAD = 'red'
START_COLOR = 'blue'
END_COLOR = 'green'
MAXSTEPS = 1
ROW = 3
COL = 3
FRAME_BGCOLOR_CHANGE_MAP = { # A mapping table to determine next state (FSM concept)
CAN_MOVE: MOVE_NOMOVE,
MOVE_NOMOVE: ROTATE,
ROTATE: ROTATE_NOMOVE,
ROTATE_NOMOVE: MOVE2_CANMOVE,
MOVE2_CANMOVE: 'SystemButtonFace',
}
#### functions
# bg_equals, get_bg, set_bg, init_2d_data are frequently used pieces of code, so extract them into functions to reduce code
# More advanced way is to define methods under custom widget classes (inherit from Button and LabelFrame)
def bg_equals(widget, bg):
return get_bg(widget) == bg
def get_bg(widget):
return widget.config('bg')[-1]
def set_bg(widget, bg):
widget.config(bg=bg)
# utility function to initialize 2d data with a value function as parameter
def init_2d_data(value_func):
return [[value_func() for x in range(ROW)] for y in range(COL)]
def toggle_have_road(widget):
set_bg(widget, 'SystemButtonFace' if bg_equals(widget, HAVE_ROAD) else HAVE_ROAD)
def up_color_change(x, y):
toggle_have_road(btnUp[x][y])
def bg_center_color_change(p):
# Generally the code will be more clear if you split the logic of input, process and output.
# Part 1: input: get required things for process
widget = p.widget
bg = get_bg(widget)
# Part 2: do process: determine next bg
if bg == START_COLOR:
next_bg = END_COLOR
elif bg == END_COLOR:
next_bg = 'SystemButtonFace'
else:
next_bg = START_COLOR
# Part 3: output: set next bg
set_bg(widget, next_bg)
def bg_color_change(p):
toggle_have_road(p.widget)
def frame_bgColor_change(p):
widget = p.widget
bg = get_bg(widget)
# use the mapping table can reduce lots of if-else logic, but make sure to handle the condition when key is not in dict
next_bg = FRAME_BGCOLOR_CHANGE_MAP[bg] if bg in FRAME_BGCOLOR_CHANGE_MAP else CAN_MOVE
set_bg(widget, next_bg)
def solve():
for j in range(ROW):
for i in range(COL):
thisCells = [
bg_equals(btnUp[i][j], HAVE_ROAD), # == operator would return boolean. You can directly use it as a value
bg_equals(btnRight[i][j], HAVE_ROAD),
bg_equals(btnDown[i][j], HAVE_ROAD),
bg_equals(btnLeft[i][j], HAVE_ROAD),
]
#
centerBg = get_bg(btnCenter[i][j])
thisCells.extend([ #! You can use extend to append multiple items at once
centerBg == START_COLOR,
centerBg == END_COLOR,
])
#
frmBg = get_bg(frmCell[i][j])
#! This part can be refined with the above-mentioned mapping table. You can try it by yourself.
if frmBg == CAN_MOVE:
thisCells.extend([
True, # initially movable
False,
False,
False
])
elif frmBg == MOVE_NOMOVE:
thisCells.extend([
True, # initially movable
True, # cannot move after move
False,
False
])
elif frmBg == ROTATE:
thisCells.extend([
True, # initially movable
False,
True, # will rotate when each move
False
])
elif frmBg == MOVE2_CANMOVE:
thisCells.extend([
False,
False,
False,
True # initially cannot move until totally 2 steps of move
])
else:
thisCells.extend([False, False, False, False])
#
cells[i][j] = thisCells
df = pd.DataFrame(cells)
#df.columns = [['up', 'right', 'down', 'left', 'start', 'end', 'canMove', 'move_noMove', 'rotate', 'move2_canMove']]
# 以上為遊戲題目出題之視覺界面設定完成, 轉化出之df為出題結果之三維陣列
# 接下去才開始進入解題, 解題程式尚未寫作
getMovableGroup()
move(0, cells)
def getMovableGroup():
return
def move(steps, cells):
if steps == MAXSTEPS:
print(cells)
return
thisMove()
check()
steps += 1
# print(df)
move(steps, cells)
def thisMove():
return
def check():
return
#### main code
root = Tk()
root.title("test")
pw = PanedWindow(orient=VERTICAL)
cells = init_2d_data(lambda: [])
frmCell = init_2d_data(lambda: 0)
btnUp = init_2d_data(lambda: 0)
btnLeft = init_2d_data(lambda: 0)
btnRight = init_2d_data(lambda: 0)
btnDown = init_2d_data(lambda: 0)
btnCenter = init_2d_data(lambda: 0)
for i in range(ROW):
pwInner = PanedWindow(orient=HORIZONTAL)
for j in range(COL):
frmCell[j][i] = LabelFrame(pwInner, text=str(i) + "," + str(j), width=80, height=40)
frmCell[j][i].bind('<Button-1>', frame_bgColor_change)
pwInner.add(frmCell[j][i])
# The code below are really similar to each other, you can try to think how to use function, loop or class to refine them
btnUp[j][i] = Button(frmCell[j][i], text="", width=3, height=2) # , command= lambda x1=j, y1=i: up_color_change(x1,y1))
btnUp[j][i].grid(row=0, column=1)
btnUp[j][i].bind('<Button-1>', bg_color_change)
btnLeft[j][i] = Button(frmCell[j][i], text="", width=5, height=1)
btnLeft[j][i].grid(row=1, column=0)
btnLeft[j][i].bind('<Button-1>', bg_color_change)
btnCenter[j][i] = Button(frmCell[j][i], text="", width=5, height=2)
btnCenter[j][i].grid(row=1, column=1)
btnCenter[j][i].bind('<Button-1>', bg_center_color_change)
btnRight[j][i] = Button(frmCell[j][i], text="", width=5, height=1)
btnRight[j][i].grid(row=1, column=2)
btnRight[j][i].bind('<Button-1>', bg_color_change)
btnDown[j][i] = Button(frmCell[j][i], text="", width=3, height=2)
btnDown[j][i].grid(row=2, column=1)
btnDown[j][i].bind('<Button-1>', bg_color_change)
pw.add(pwInner)
btnSolve = Button(pw, text='Solve', bg='yellow', command=solve)
pw.add(btnSolve)
pw.pack(fill=BOTH, expand=True, padx=10, pady=10)
root.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment