"""Wrapper functions for Tcl/Tk.
Tkinter provides classes which allow the display, positioning and
control of widgets. Toplevel widgets are Tk and Toplevel. Other
widgets are Frame, Label, Entry, Text, Canvas, Button, Radiobutton,
Checkbutton, Scale, Listbox, Scrollbar, OptionMenu, Spinbox
LabelFrame and PanedWindow.
Properties of the widgets are specified with keyword arguments.
Keyword arguments have the same name as the corresponding resource
under Tk.
Widgets are positioned with one of the geometry managers Place, Pack
or Grid. These managers can be called with methods place, pack, grid
available in every Widget.
Actions are bound to events by resources (e.g. keyword argument
command) or with the method bind.
Example (Hello, World):
import tkinter
from tkinter.constants import *
tk = tkinter.Tk()
frame = tkinter.Frame(tk, relief=RIDGE, borderwidth=2)
frame.pack(fill=BOTH,expand=1)
label = tkinter.Label(frame, text="Hello, World")
label.pack(fill=X, expand=1)
button = tkinter.Button(frame,text="Exit",command=tk.destroy)
button.pack(side=BOTTOM)
tk.mainloop()
"""
import enum
import sys
import types
import _tkinter # If this fails your Python may not be configured for Tk
TclError = _tkinter.TclError
from tkinter.constants import *
import re
wantobjects = 1
TkVersion = float(_tkinter.TK_VERSION)
TclVersion = float(_tkinter.TCL_VERSION)
READABLE = _tkinter.READABLE
WRITABLE = _tkinter.WRITABLE
EXCEPTION = _tkinter.EXCEPTION
_magic_re = re.compile(r'([\\{}])')
_space_re = re.compile(r'([\s])', re.ASCII)
def _join(value):
"""Internal function."""
return ' '.join(map(_stringify, value))
def _stringify(value):
"""Internal function."""
if isinstance(value, (list, tuple)):
if len(value) == 1:
value = _stringify(value[0])
if _magic_re.search(value):
value = '{%s}' % value
else:
value = '{%s}' % _join(value)
else:
value = str(value)
if not value:
value = '{}'
elif _magic_re.search(value):
# add '\' before special characters and spaces
value = _magic_re.sub(r'\\\1', value)
value = value.replace('\n', r'\n')
value = _space_re.sub(r'\\\1', value)
if value[0] == '"':
value = '\\' + value
elif value[0] == '"' or _space_re.search(value):
value = '{%s}' % value
return value
def _flatten(seq):
"""Internal function."""
res = ()
for item in seq:
if isinstance(item, (tuple, list)):
res = res + _flatten(item)
elif item is not None:
res = res + (item,)
return res
try: _flatten = _tkinter._flatten
except AttributeError: pass
def _cnfmerge(cnfs):
"""Internal function."""
if isinstance(cnfs, dict):
return cnfs
elif isinstance(cnfs, (type(None), str)):
return cnfs
else:
cnf = {}
for c in _flatten(cnfs):
try:
cnf.update(c)
except (AttributeError, TypeError) as msg:
print("_cnfmerge: fallback due to:", msg)
for k, v in c.items():
cnf[k] = v
return cnf
try: _cnfmerge = _tkinter._cnfmerge
except AttributeError: pass
def _splitdict(tk, v, cut_minus=True, conv=None):
"""Return a properly formatted dict built from Tcl list pairs.
If cut_minus is True, the supposed '-' prefix will be removed from
keys. If conv is specified, it is used to convert values.
Tcl list is expected to contain an even number of elements.
"""
t = tk.splitlist(v)
if len(t) % 2:
raise RuntimeError('Tcl list representing a dict is expected '
'to contain an even number of elements')
it = iter(t)
dict = {}
for key, value in zip(it, it):
key = str(key)
if cut_minus and key[0] == '-':
key = key[1:]
if conv:
value = conv(value)
dict[key] = value
return dict
class EventType(str, enum.Enum):
KeyPress = '2'
Key = KeyPress
KeyRelease = '3'
ButtonPress = '4'
Button = ButtonPress
ButtonRelease = '5'
Motion = '6'
Enter = '7'
Leave = '8'
FocusIn = '9'
FocusOut = '10'
Keymap = '11' # undocumented
Expose = '12'
GraphicsExpose = '13' # undocumented
NoExpose = '14' # undocumented
Visibility = '15'
Create = '16'
Destroy = '17'
Unmap = '18'
Map = '19'
MapRequest = '20'
Reparent = '21'
Configure = '22'
ConfigureRequest = '23'
Gravity = '24'
ResizeRequest = '25'
Circulate = '26'
CirculateRequest = '27'
Property = '28'
SelectionClear = '29' # undocumented
SelectionRequest = '30' # undocumented
Selection = '31' # undocumented
Colormap = '32'
ClientMessage = '33' # undocumented
Mapping = '34' # undocumented
VirtualEvent = '35' # undocumented
Activate = '36'
Deactivate = '37'
MouseWheel = '38'
__str__ = str.__str__
class Event:
"""Container for the properties of an event.
Instances of this type are generated if one of the following events occurs:
KeyPress, KeyRelease - for keyboard events
ButtonPress, ButtonRelease, Motion, Enter, Leave, MouseWheel - for mouse events
Visibility, Unmap, Map, Expose, FocusIn, FocusOut, Circulate,
Colormap, Gravity, Reparent, Property, Destroy, Activate,
Deactivate - for window events.
If a callback function for one of these events is registered
using bind, bind_all, bind_class, or tag_bind, the callback is
called with an Event as first argument. It will have the
following attributes (in braces are the event types for which
the attribute is valid):
serial - serial number of event
num - mouse button pressed (ButtonPress, ButtonRelease)
focus - whether the window has the focus (Enter, Leave)
height - height of the exposed window (Configure, Expose)
width - width of the exposed window (Configure, Expose)
keycode - keycode of the pressed key (KeyPress, KeyRelease)
state - state of the event as a number (ButtonPress, ButtonRelease,
Enter, KeyPress, KeyRelease,
Leave, Motion)
state - state as a string (Visibility)
time - when the event occurred
x - x-position of the mouse
y - y-position of the mouse
x_root - x-position of the mouse on the screen
(ButtonPress, ButtonRelease, KeyPress, KeyRelease, Motion)
y_root - y-position of the mouse on the screen
(ButtonPress, ButtonRelease, KeyPress, KeyRelease, Motion)
char - pressed character (KeyPress, KeyRelease)
send_event - see X/Windows documentation
keysym - keysym of the event as a string (KeyPress, KeyRelease)
keysym_num - keysym of the event as a number (KeyPress, KeyRelease)
type - type of the event as a number
widget - widget in which the event occurred
delta - delta of wheel movement (MouseWheel)
"""
def __repr__(self):
attrs = {k: v for k, v in self.__dict__.items() if v != '??'}
if not self.char:
del attrs['char']
elif self.char != '??':
attrs['char'] = repr(self.char)
if not getattr(self, 'send_event', True):
del attrs['send_event']
if self.state == 0:
del attrs['state']
elif isinstance(self.state, int):
state = self.state
mods = ('Shift', 'Lock', 'Control',
'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5',
'Button1', 'Button2', 'Button3', 'Button4', 'Button5')
s = []
for i, n in enumerate(mods):
if state & (1 << i):
s.append(n)
state = state & ~((1<< len(mods)) - 1)
if state or not s:
s.append(hex(state))
attrs['state'] = '|'.join(s)
if self.delta == 0:
del attrs['delta']
# widget usually is known
# serial and time are not very interesting
# keysym_num duplicates keysym
# x_root and y_root mostly duplicate x and y
keys = ('send_event',
'state', 'keysym', 'keycode', 'char',
'num', 'delta', 'focus',
'x', 'y', 'width', 'height')
return '<%s event%s>' % (
getattr(self.type, 'name', self.type),
''.join(' %s=%s' % (k, attrs[k]) for k in keys if k in attrs)
)
_support_default_root = True
_default_root = None
def NoDefaultRoot():
"""Inhibit setting of default root window.
Call this function to inhibit that the first instance of
Tk is used for windows without an explicit parent window.
"""
global _support_default_root, _default_root
_support_default_root = False
# Delete, so any use of _default_root will immediately raise an exception.
# Rebind before deletion, so repeated calls will not fail.
_default_root = None
del _default_root
def _get_default_root(what=None):
if not _support_default_root:
raise RuntimeError("No master specified and tkinter is "
"configured to not support default root")
if _default_root is None:
if what:
raise RuntimeError(f"Too early to {what}: no default root window")
root = Tk()
assert _default_root is root
return _default_root
def _get_temp_root():
global _support_default_root
if not _support_default_root:
raise RuntimeError("No master specified and tkinter is "
"configured to not support default root")
root = _default_root
if root is None:
assert _support_default_root
_support_default_root = False
root = Tk()
_support_default_root = True
assert _default_root is None
root.withdraw()
root._temporary = True
return root
def _destroy_temp_root(master):
if getattr(master, '_temporary', False):
try:
master.destroy()
except TclError:
pass
def _tkerror(err):
"""Internal function."""
pass
def _exit(code=0):
"""Internal function. Calling it will raise the exception SystemExit."""
try:
code = int(code)
except ValueError:
pass
raise SystemExit(code)
_varnum = 0
class Variable:
"""Class to define value holders for e.g. buttons.
Subclasses StringVar, IntVar, DoubleVar, BooleanVar are specializations
that constrain the type of the value returned from get()."""
_default = ""
_tk = None
_tclCommands = None
def __init__(self, master=None, value=None, name=None):
"""Construct a variable
MASTER can be given as master widget.
VALUE is an optional value (defaults to "")
NAME is an optional Tcl name (defaults to PY_VARnum).
If NAME matches an existing variable and VALUE is omitted
then the existing value is retained.
"""
# check for type of NAME parameter to override weird error message
# raised from Modules/_tkinter.c:SetVar like:
# TypeError: setvar() takes exactly 3 arguments (2 given)
if name is not None and not isinstance(name, str):
raise TypeError("name must be a string")
global _varnum
if master is None:
master = _get_default_root('create variable')
self._root = master._root()
self._tk = master.tk
if name:
self._name = name
else:
self._name = 'PY_VAR' + repr(_varnum)
_varnum += 1
if value is not None:
self.initialize(value)
elif not self._tk.getboolean(self._tk.call("info", "exists", self._name)):
self.initialize(self._default)
def __del__(self):
"""Unset the variable in Tcl."""
if self._tk is None:
return
if self._tk.getboolean(self._tk.call("info", "exists", self._name)):
self._tk.globalunsetvar(self._name)
if self._tclCommands is not None:
for name in self._tclCommands:
#print '- Tkinter: deleted command', name
self._tk.deletecommand(name)
self._tclCommands = None
def __str__(self):
"""Return the name of the variable in Tcl."""
return self._name
def set(self, value):
"""Set the variable to VALUE."""
return self._tk.globalsetvar(self._name, value)
initialize = set
def get(self):
"""Return value of variable."""
return self._tk.globalgetvar(self._name)
def _register(self, callback):
f = CallWrapper(callback, None, self._root).__call__
cbname = repr(id(f))
try:
callback = callback.__func__
except AttributeError:
pass
try:
cbname = cbname + callback.__name__
except AttributeError:
pass
self._tk.createcommand(cbname, f)
if self._tclCommands is None:
self._tclCommands = []
self._tclCommands.append(cbname)
return cbname
def trace_add(self, mode, callback):
"""Define a trace callback for the variable.
Mode is one of "read", "write", "unset", or a list or tuple of
such strings.
Callback must be a function which is called when the variable is
read, written or unset.
Return the name of the callback.
"""
cbname = self._register(callback)
self._tk.call('trace', 'add', 'variable',
self._name, mode, (cbname,))
return cbname
def trace_remove(self, mode, cbname):
"""Delete the trace callback for a variable.
Mode is one of "read", "write", "unset" or a list or tuple of
such strings. Must be same as were specified in trace_add().
cbname is the name of the callback returned from trace_add().
"""
self._tk.call('trace', 'remove', 'variable',
self._name, mode, cbname)
for m, ca in self.trace_info():
if self._tk.splitlist(ca)[0] == cbname:
break
else:
self._tk.deletecommand(cbname)
try:
self._tclCommands.remove(cbname)
except ValueError:
pass
def trace_info(self):
"""Return all trace callback information."""
splitlist = self._tk.splitlist
return [(splitlist(k), v) for k, v in map(splitlist,
splitlist(self._tk.call('trace', 'info', 'variable', self._name)))]
def trace_variable(self, mode, callback):
"""Define a trace callback for the variable.
MODE is one of "r", "w", "u" for read, write, undefine.
CALLBACK must be a function which is called when
the variable is read, written or undefined.
Return the name of the callback.
This deprecated method wraps a deprecated Tcl method that will
likely be removed in the future. Use trace_add() instead.
"""
# TODO: Add deprecation warning
cbname = self._register(callback)
self._tk.call("trace", "variable", self._name, mode, cbname)
return cbname
trace = trace_variable
def trace_vdelete(self, mode, cbname):
"""Delete the trace callback for a variable.
MODE is one of "r", "w", "u" for read, write, undefine.
CBNAME is the name of the callback returned from trace_variable or trace.
This deprecated method wraps a deprecated Tcl method that will
likely be removed in the future. Use trace_remove() instead.
"""
# TODO: Add deprecation warning
self._tk.call("trace", "vdelete", self._name, mode, cbname)
cbname = self._tk.splitlist(cbname)[0]
for m, ca in self.trace_info():
if self._tk.splitlist(ca)[0] == cbname:
break
else:
self._tk.deletecommand(cbname)
try:
self._tclCommands.remove(cbname)
except ValueError:
pass
def trace_vinfo(self):
"""Return all trace callback information.
This deprecated method wraps a deprecated Tcl method that will
likely be removed in the future. Use trace_info() instead.
"""
# TODO: Add deprecation warning
return [self._tk.splitlist(x) for x in self._tk.splitlist(
self._tk.call("trace", "vinfo", self._name))]
def __eq__(self, other):
if not isinstance(other, Variable):
return NotImplemented
return (self._name == other._name
and self.__class__.__name__ == other.__class__.__name__
and self._tk == other._tk)
因为代码太长了,所以我就列举一部分内容。
大家是不是都有一个问题:为什么包里面都只有函数和类呢?
我们来看一看我们在用这个包的时候用的语句:
from tkinter import *
# ttk覆盖tkinter部分对象,ttk对tkinter进行了优化
from tkinter.ttk import *
# 深拷贝时需要用到copy模块
import copy
import tkinter.messagebox
# 围棋应用对象定义
class Application(Tk):
# 初始化棋盘,默认九路棋盘
def __init__(self,my_mode_num=9):
Tk.__init__(self)
# 模式,九路棋:9,十三路棋:13,十九路棋:19
self.mode_num=my_mode_num
# 窗口尺寸设置,默认:1.8
self.size=1.8
# 棋盘每格的边长
self.dd=360*self.size/(self.mode_num-1)
# 相对九路棋盘的矫正比例
self.p=1 if self.mode_num==9 else (2/3 if self.mode_num==13 else 4/9)
# 定义棋盘阵列,超过边界:-1,无子:0,黑棋:1,白棋:2
self.positions=[[0 for i in range(self.mode_num+2)] for i in range(self.mode_num+2)]
# 初始化棋盘,所有超过边界的值置-1
for m in range(self.mode_num+2):
for n in range(self.mode_num+2):
if (m*n==0 or m==self.mode_num+1 or n==self.mode_num+1):
self.positions[m][n]=-1
# 拷贝三份棋盘“快照”,悔棋和判断“打劫”时需要作参考
self.last_3_positions=copy.deepcopy(self.positions)
self.last_2_positions=copy.deepcopy(self.positions)
self.last_1_positions=copy.deepcopy(self.positions)
# 记录鼠标经过的地方,用于显示shadow时
self.cross_last=None
# 当前轮到的玩家,黑:0,白:1,执黑先行
self.present=0
# 初始停止运行,点击“开始游戏”运行游戏
self.stop=True
# 悔棋次数,次数大于0才可悔棋,初始置0(初始不能悔棋),悔棋后置0,下棋或弃手时恢复为1,以禁止连续悔棋
self.regretchance=0
# 图片资源,存放在当前目录下的/Pictures/中
self.photoW=PhotoImage(file = "./Pictures/W.png")
self.photoB=PhotoImage(file = "./Pictures/B.png")
self.photoBD=PhotoImage(file = "./Pictures/"+"BD"+"-"+str(self.mode_num)+".png")
self.photoWD=PhotoImage(file = "./Pictures/"+"WD"+"-"+str(self.mode_num)+".png")
self.photoBU=PhotoImage(file = "./Pictures/"+"BU"+"-"+str(self.mode_num)+".png")
self.photoWU=PhotoImage(file = "./Pictures/"+"WU"+"-"+str(self.mode_num)+".png")
# 用于黑白棋子图片切换的列表
self.photoWBU_list=[self.photoBU,self.photoWU]
self.photoWBD_list=[self.photoBD,self.photoWD]
# 窗口大小
self.geometry(str(int(600*self.size))+'x'+str(int(400*self.size)))
# 画布控件,作为容器
self.canvas_bottom=Canvas(self,bg='#369',bd=0,width=600*self.size,height=400*self.size)
self.canvas_bottom.place(x=0,y=0)
# 几个功能按钮
self.startButton=Button(self,text='开始游戏',command=self.start)
self.startButton.place(x=480*self.size,y=200*self.size)
self.passmeButton=Button(self,text='弃一手',command=self.passme)
self.passmeButton.place(x=480*self.size,y=225*self.size)
self.regretButton=Button(self,text='悔棋',command=self.regret)
self.regretButton.place(x=480*self.size,y=250*self.size)
# 初始悔棋按钮禁用
self.regretButton['state']=DISABLED
self.replayButton=Button(self,text='重新开始',command=self.reload)
self.replayButton.place(x=480*self.size,y=275*self.size)
self.newGameButton1=Button(self,text=('十三' if self.mode_num==9 else '九')+'路棋',command=self.newGame1)
self.newGameButton1.place(x=480*self.size,y=300*self.size)
self.newGameButton2=Button(self,text=('十三' if self.mode_num==19 else '十九')+'路棋',command=self.newGame2)
self.newGameButton2.place(x=480*self.size,y=325*self.size)
self.quitButton=Button(self,text='退出游戏',command=self.quit)
self.quitButton.place(x=480*self.size,y=350*self.size)
# 画棋盘,填充颜色
self.canvas_bottom.create_rectangle(0*self.size,0*self.size,400*self.size,400*self.size,fill='#c51')
# 刻画棋盘线及九个点
# 先画外框粗线
self.canvas_bottom.create_rectangle(20*self.size,20*self.size,380*self.size,380*self.size,width=3)
# 棋盘上的九个定位点,以中点为模型,移动位置,以作出其余八个点
for m in [-1,0,1]:
for n in [-1,0,1]:
self.oringinal=self.canvas_bottom.create_oval(200*self.size-self.size*2,200*self.size-self.size*2,
200*self.size+self.size*2,200*self.size+self.size*2,fill='#000')
self.canvas_bottom.move(self.oringinal,m*self.dd*(2 if self.mode_num==9 else (3 if self.mode_num==13 else 6)),
n*self.dd*(2 if self.mode_num==9 else (3 if self.mode_num==13 else 6)))
# 画中间的线条
for i in range(1,self.mode_num-1):
self.canvas_bottom.create_line(20*self.size,20*self.size+i*self.dd,380*self.size,20*self.size+i*self.dd,width=2)
self.canvas_bottom.create_line(20*self.size+i*self.dd,20*self.size,20*self.size+i*self.dd,380*self.size,width=2)
# 放置右侧初始图片
self.pW=self.canvas_bottom.create_image(500*self.size+11, 65*self.size,image=self.photoW)
self.pB=self.canvas_bottom.create_image(500*self.size-11, 65*self.size,image=self.photoB)
# 每张图片都添加image标签,方便reload函数删除图片
self.canvas_bottom.addtag_withtag('image',self.pW)
self.canvas_bottom.addtag_withtag('image',self.pB)
# 鼠标移动时,调用shadow函数,显示随鼠标移动的棋子
self.canvas_bottom.bind('<Motion>',self.shadow)
# 鼠标左键单击时,调用getdown函数,放下棋子
self.canvas_bottom.bind('<Button-1>',self.getDown)
# 设置退出快捷键<Ctrl>+<D>,快速退出游戏
self.bind('<Control-KeyPress-d>',self.keyboardQuit)
# 开始游戏函数,点击“开始游戏”时调用
def start(self):
# 删除右侧太极图
self.canvas_bottom.delete(self.pW)
self.canvas_bottom.delete(self.pB)
# 利用右侧图案提示开始时谁先落子
if self.present==0:
self.create_pB()
self.del_pW()
else:
self.create_pW()
self.del_pB()
# 开始标志,解除stop
self.stop=None
# 放弃一手函数,跳过落子环节
def passme(self):
# 悔棋恢复
if not self.regretchance==1:
self.regretchance+=1
else:
self.regretButton['state']=NORMAL
# 拷贝棋盘状态,记录前三次棋局
self.last_3_positions=copy.deepcopy(self.last_2_positions)
self.last_2_positions=copy.deepcopy(self.last_1_positions)
self.last_1_positions=copy.deepcopy(self.positions)
self.canvas_bottom.delete('image_added_sign')
# 轮到下一玩家
if self.present==0:
self.create_pW()
self.del_pB()
self.present=1
else:
self.create_pB()
self.del_pW()
self.present=0
# 悔棋函数,可悔棋一回合,下两回合不可悔棋
def regret(self):
# 判定是否可以悔棋,以前第三盘棋局复原棋盘
if self.regretchance==1:
self.regretchance=0
self.regretButton['state']=DISABLED
list_of_b=[]
list_of_w=[]
self.canvas_bottom.delete('image')
if self.present==0:
self.create_pB()
else:
self.create_pW()
for m in range(1,self.mode_num+1):
for n in range(1,self.mode_num+1):
self.positions[m][n]=0
for m in range(len(self.last_3_positions)):
for n in range(len(self.last_3_positions[m])):
if self.last_3_positions[m][n]==1:
list_of_b+=[[n,m]]
elif self.last_3_positions[m][n]==2:
list_of_w+=[[n,m]]
self.recover(list_of_b,0)
self.recover(list_of_w,1)
self.last_1_positions=copy.deepcopy(self.last_3_positions)
for m in range(1,self.mode_num+1):
for n in range(1,self.mode_num+1):
self.last_2_positions[m][n]=0
self.last_3_positions[m][n]=0
# 重新加载函数,删除图片,序列归零,设置一些初始参数,点击“重新开始”时调用
def reload(self):
if self.stop==1:
self.stop=0
self.canvas_bottom.delete('image')
self.regretchance=0
self.present=0
self.create_pB()
for m in range(1,self.mode_num+1):
for n in range(1,self.mode_num+1):
self.positions[m][n]=0
self.last_3_positions[m][n]=0
self.last_2_positions[m][n]=0
self.last_1_positions[m][n]=0
# 以下四个函数实现了右侧太极图的动态创建与删除
def create_pW(self):
self.pW=self.canvas_bottom.create_image(500*self.size+11, 65*self.size,image=self.photoW)
self.canvas_bottom.addtag_withtag('image',self.pW)
def create_pB(self):
self.pB=self.canvas_bottom.create_image(500*self.size-11, 65*self.size,image=self.photoB)
self.canvas_bottom.addtag_withtag('image',self.pB)
def del_pW(self):
self.canvas_bottom.delete(self.pW)
def del_pB(self):
self.canvas_bottom.delete(self.pB)
# 显示鼠标移动下棋子的移动
def shadow(self,event):
if not self.stop:
# 找到最近格点,在当前位置靠近的格点出显示棋子图片,并删除上一位置的棋子图片
if (20*self.size<event.x<380*self.size) and (20*self.size<event.y<380*self.size):
dx=(event.x-20*self.size)%self.dd
dy=(event.y-20*self.size)%self.dd
self.cross=self.canvas_bottom.create_image(event.x-dx+round(dx/self.dd)*self.dd+22*self.p, event.y-dy+round(dy/self.dd)*self.dd-27*self.p,image=self.photoWBU_list[self.present])
self.canvas_bottom.addtag_withtag('image',self.cross)
if self.cross_last!=None:
self.canvas_bottom.delete(self.cross_last)
self.cross_last=self.cross
# 落子,并驱动玩家的轮流下棋行为
def getDown(self,event):
if not self.stop:
# 先找到最近格点
if (20*self.size-self.dd*0.4<event.x<self.dd*0.4+380*self.size) and (20*self.size-self.dd*0.4<event.y<self.dd*0.4+380*self.size):
dx=(event.x-20*self.size)%self.dd
dy=(event.y-20*self.size)%self.dd
x=int((event.x-20*self.size-dx)/self.dd+round(dx/self.dd)+1)
y=int((event.y-20*self.size-dy)/self.dd+round(dy/self.dd)+1)
# 判断位置是否已经被占据
if self.positions[y][x]==0:
# 未被占据,则尝试占据,获得占据后能杀死的棋子列表
self.positions[y][x]=self.present+1
self.image_added=self.canvas_bottom.create_image(event.x-dx+round(dx/self.dd)*self.dd+4*self.p, event.y-dy+round(dy/self.dd)*self.dd-5*self.p,image=self.photoWBD_list[self.present])
self.canvas_bottom.addtag_withtag('image',self.image_added)
# 棋子与位置标签绑定,方便“杀死”
self.canvas_bottom.addtag_withtag('position'+str(x)+str(y),self.image_added)
deadlist=self.get_deadlist(x,y)
self.kill(deadlist)
# 判断是否重复棋局
if not self.last_2_positions==self.positions:
# 判断是否属于有气和杀死对方其中之一
if len(deadlist)>0 or self.if_dead([[x,y]],self.present+1,[x,y])==False:
# 当不重复棋局,且属于有气和杀死对方其中之一时,落下棋子有效
if not self.regretchance==1:
self.regretchance+=1
else:
self.regretButton['state']=NORMAL
self.last_3_positions=copy.deepcopy(self.last_2_positions)
self.last_2_positions=copy.deepcopy(self.last_1_positions)
self.last_1_positions=copy.deepcopy(self.positions)
# 删除上次的标记,重新创建标记
self.canvas_bottom.delete('image_added_sign')
self.image_added_sign=self.canvas_bottom.create_oval(event.x-dx+round(dx/self.dd)*self.dd+0.5*self.dd, event.y-dy+round(dy/self.dd)*self.dd+0.5*self.dd,event.x-dx+round(dx/self.dd)*self.dd-0.5*self.dd, event.y-dy+round(dy/self.dd)*self.dd-0.5*self.dd,width=3,outline='#3ae')
self.canvas_bottom.addtag_withtag('image',self.image_added_sign)
self.canvas_bottom.addtag_withtag('image_added_sign',self.image_added_sign)
if self.present==0:
self.create_pW()
self.del_pB()
self.present=1
else:
self.create_pB()
self.del_pW()
self.present=0
else:
# 不属于杀死对方或有气,则判断为无气,警告并弹出警告框
self.positions[y][x]=0
self.canvas_bottom.delete('position'+str(x)+str(y))
self.bell()
self.showwarningbox('无气',"你被包围了!")
else:
# 重复棋局,警告打劫
self.positions[y][x]=0
self.canvas_bottom.delete('position'+str(x)+str(y))
self.recover(deadlist,(1 if self.present==0 else 0))
self.bell()
self.showwarningbox("打劫","此路不通!")
else:
# 覆盖,声音警告
self.bell()
else:
# 超出边界,声音警告
self.bell()
# 判断棋子(种类为yourChessman,位置为yourPosition)是否无气(死亡),有气则返回False,无气则返回无气棋子的列表
# 本函数是游戏规则的关键,初始deadlist只包含了自己的位置,每次执行时,函数尝试寻找yourPosition周围有没有空的位置,有则结束,返回False代表有气;
# 若找不到,则找自己四周的同类(不在deadlist中的)是否有气,即调用本函数,无气,则把该同类加入到deadlist,然后找下一个邻居,只要有一个有气,返回False代表有气;
# 若四周没有一个有气的同类,返回deadlist,至此结束递归
# def if_dead(self,deadlist,yourChessman,yourPosition):
def if_dead(self,deadList,yourChessman,yourPosition):
for i in [-1,1]:
if [yourPosition[0]+i,yourPosition[1]] not in deadList:
if self.positions[yourPosition[1]][yourPosition[0]+i]==0:
return False
if [yourPosition[0],yourPosition[1]+i] not in deadList:
if self.positions[yourPosition[1]+i][yourPosition[0]]==0:
return False
if ([yourPosition[0]+1,yourPosition[1]] not in deadList) and (self.positions[yourPosition[1]][yourPosition[0]+1]==yourChessman):
midvar=self.if_dead(deadList+[[yourPosition[0]+1,yourPosition[1]]],yourChessman,[yourPosition[0]+1,yourPosition[1]])
if not midvar:
return False
else:
deadList+=copy.deepcopy(midvar)
if ([yourPosition[0]-1,yourPosition[1]] not in deadList) and (self.positions[yourPosition[1]][yourPosition[0]-1]==yourChessman):
midvar=self.if_dead(deadList+[[yourPosition[0]-1,yourPosition[1]]],yourChessman,[yourPosition[0]-1,yourPosition[1]])
if not midvar:
return False
else:
deadList+=copy.deepcopy(midvar)
if ([yourPosition[0],yourPosition[1]+1] not in deadList) and (self.positions[yourPosition[1]+1][yourPosition[0]]==yourChessman):
midvar=self.if_dead(deadList+[[yourPosition[0],yourPosition[1]+1]],yourChessman,[yourPosition[0],yourPosition[1]+1])
if not midvar:
return False
else:
deadList+=copy.deepcopy(midvar)
if ([yourPosition[0],yourPosition[1]-1] not in deadList) and (self.positions[yourPosition[1]-1][yourPosition[0]]==yourChessman):
midvar=self.if_dead(deadList+[[yourPosition[0],yourPosition[1]-1]],yourChessman,[yourPosition[0],yourPosition[1]-1])
if not midvar:
return False
else:
deadList+=copy.deepcopy(midvar)
return deadList
# 警告消息框,接受标题和警告信息
def showwarningbox(self,title,message):
self.canvas_bottom.delete(self.cross)
tkinter.messagebox.showwarning(title,message)
# 落子后,依次判断四周是否有棋子被杀死,并返回死棋位置列表
def get_deadlist(self,x,y):
deadlist=[]
for i in [-1,1]:
if self.positions[y][x+i]==(2 if self.present==0 else 1) and ([x+i,y] not in deadlist):
killList=self.if_dead([[x+i,y]],(2 if self.present==0 else 1),[x+i,y])
if not killList==False:
deadlist+=copy.deepcopy(killList)
if self.positions[y+i][x]==(2 if self.present==0 else 1) and ([x,y+i] not in deadlist):
killList=self.if_dead([[x,y+i]],(2 if self.present==0 else 1),[x,y+i])
if not killList==False:
deadlist+=copy.deepcopy(killList)
return deadlist
# 恢复位置列表list_to_recover为b_or_w指定的棋子
def recover(self,list_to_recover,b_or_w):
if len(list_to_recover)>0:
for i in range(len(list_to_recover)):
self.positions[list_to_recover[i][1]][list_to_recover[i][0]]=b_or_w+1
self.image_added=self.canvas_bottom.create_image(20*self.size+(list_to_recover[i][0]-1)*self.dd+4*self.p, 20*self.size+(list_to_recover[i][1]-1)*self.dd-5*self.p,image=self.photoWBD_list[b_or_w])
self.canvas_bottom.addtag_withtag('image',self.image_added)
self.canvas_bottom.addtag_withtag('position'+str(list_to_recover[i][0])+str(list_to_recover[i][1]),self.image_added)
# 杀死位置列表killList中的棋子,即删除图片,位置值置0
def kill(self,killList):
if len(killList)>0:
for i in range(len(killList)):
self.positions[killList[i][1]][killList[i][0]]=0
self.canvas_bottom.delete('position'+str(killList[i][0])+str(killList[i][1]))
# 键盘快捷键退出游戏
def keyboardQuit(self,event):
self.quit()
# 以下两个函数修改全局变量值,newApp使主函数循环,以建立不同参数的对象
def newGame1(self):
global mode_num,newApp
mode_num=(13 if self.mode_num==9 else 9)
newApp=True
self.quit()
def newGame2(self):
global mode_num,newApp
mode_num=(13 if self.mode_num==19 else 19)
newApp=True
self.quit()
# 声明全局变量,用于新建Application对象时切换成不同模式的游戏
global mode_num,newApp
mode_num=9
newApp=False
if __name__=='__main__':
# 循环,直到不切换游戏模式
while True:
newApp=False
app=Application(mode_num)
app.title('围棋')
app.mainloop()
if newApp:
app.destroy()
else:
break
上面的都是围棋程序。
我们基本都是用包名.函数或者函数
我来举个例子:
import mod
from mod import *
from mod.system import *
from mod.system import Print