天天看點

用python實作圍棋

今天給大家帶來一期圍棋的​​源碼​​分享。下面我們先看看效果。遊戲進去預設為九路玩法,當然也可以選擇十三路或是十九路玩法。

用python實作圍棋

目錄-文末領取所有檔案

  • ​​1.導入子產品​​
  • ​​2.初始化棋盤​​
  • ​​3. 開始遊戲​​
  • ​​4.放棄目前回合落子​​
  • ​​5.悔棋判斷​​
  • ​​6.重新開始​​
  • ​​7.右側太極圖的設定​​
  • ​​8.落子設定​​
  • ​​9.吃子規則判定設定​​
  • ​​10.其他​​
  • ​​11.程式入口​​
  • ​​檔案自取​​

1.導入子產品

tkinter:ttk覆寫tkinter部分對象,ttk對tkinter進行了優化

copy:深拷貝時需要用到copy子產品

tkinter.messagebox:圍棋應用對象定義

如沒有以上子產品,在pycharm終端輸入以下指令:

pip install 相應子產品 -i https://pypi.douban.com/simple
from tkinter import *from tkinter.ttk import *import copyimport tkinter.messagebox      

2.初始化棋盤

對棋盤進行初始化和棋盤右側的按鈕設定,以及對棋子的控制。

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.positinotallow=[[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_positinotallow=copy.deepcopy(self.positions)        self.last_2_positinotallow=copy.deepcopy(self.positions)        self.last_1_positinotallow=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.startButtnotallow=Button(self,text='開始遊戲',command=self.start)      self.startButton.place(x=480*self.size,y=200*self.size)     self.passmeButtnotallow=Button(self,text='棄一手',command=self.passme)     self.passmeButton.place(x=480*self.size,y=225*self.size)            self.regretButtnotallow=Button(self,text='悔棋',command=self.regret)      self.regretButton.place(x=480*self.size,y=250*self.size)        # 初始悔棋按鈕禁用      self.regretButton['state']=DISABLED     self.replayButtnotallow=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.quitButtnotallow=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)      

3. 開始遊戲

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      

4.放棄目前回合落子

點選棄一手,可跳過目前回合落子。

def passme(self):        # 悔棋恢複      if not self.regretchance==1:            self.regretchance+=1        else:           self.regretButton['state']=NORMAL       # 拷貝棋盤狀态,記錄前三次棋局        self.last_3_positinotallow=copy.deepcopy(self.last_2_positions)     self.last_2_positinotallow=copy.deepcopy(self.last_1_positions)     self.last_1_positinotallow=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      

5.悔棋判斷

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_positinotallow=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      

6.重新開始

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      

7.右側太極圖的設定

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)      

8.落子設定

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_positinotallow==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_positinotallow=copy.deepcopy(self.last_2_positions)                         self.last_2_positinotallow=copy.deepcopy(self.last_1_positions)                         self.last_1_positinotallow=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()      

9.吃子規則判定設定

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]))      

10.其他

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,newAppmode_num=9newApp=False      

11.程式入口

if __name__=='__main__':    # 循環,直到不切換遊戲模式  while True:     newApp=False        app=Application(mode_num)       app.title('圍棋')     app.mainloop()      if newApp:          app.destroy()       else:           break      

檔案自取