大多数时间,都在使用 deepin 系统,原来的 WPF 实现似乎越来越遥远了。这几天在家学习了一下 tkinter,顺便予以重写。
内在逻辑是一样的,就不重复,但具体实现层面,如图像不能改变大小等不一而足。由于 AI 出现,再去探讨怎么落子已变得毫无意义,所以只实现了最基本的吃子,打劫,倒扑,悔棋功能。
main.py 代码如下:
import os, sys, enum import tkinter as tk from core import Board CurrDir = os.path.dirname(__file__) sys.path.append(CurrDir) class App(tk.Tk): def __init__(self): super().__init__() board = Board(self) board.pack() self.geometry('{}x{}+300+50'.format(board.w,board.h)) if __name__ == "__main__": App().mainloop()
core.py 代码如下:
import os import tkinter as tk import tkinter.ttk as ttk CurrDir = os.path.dirname(__file__) class Board(tk.Frame): def __init__(self, master): super().__init__(master) self.w = self.h = R.StoneSize * R.CellNumber+10 self.offset = R.StoneSize/2+5 self.canvas = tk.Canvas(self, bg='#ec5',width=self.w,height=self.h) self.canvas.bind(R.ButtonLeft, self.next_one) self.canvas.bind(R.ButtonRight, self.back_one) self.canvas.pack() self.draw_lines() self.draw_stars() self.black_stone = tk.PhotoImage(file=os.path.join(CurrDir,'res/black-{}.png'.format(R.StoneSize))) self.white_stone = tk.PhotoImage(file=os.path.join(CurrDir,'res/white-{}.png'.format(R.StoneSize))) self.isBlack = True self.poses = [] self.stepCount = 0 self.wqcore = WqCore() self.once = Record() # 打劫 self.deads = [] # 悔棋 def draw_lines(self): for i in range(R.CellNumber): self.canvas.create_line(self.offset,i*R.StoneSize + self.offset,self.w-self.offset,i*R.StoneSize+self.offset) self.canvas.create_line(i*R.StoneSize+self.offset,self.offset,i*R.StoneSize+self.offset,self.h-self.offset) def draw_stars(self): stars = [(3,3), (3,9), (3,15),(9,3,),(9,9),(9,15),(15,3),(15,9),(15,15)] r = 3 for i in range(R.StarNumber): x,y = self.offset + stars[i][0]*R.StoneSize,self.offset + stars[i][1]*R.StoneSize self.canvas.create_oval(x-r, y-r, x+r, y+r, fill="black") def next_one(self, e): x,y = e.x//R.StoneSize, e.y // R.StoneSize color = 1 if self.isBlack else -1 self.draw_stone((x,y), color) self.kill() def draw_stone(self, pos, color): if color==0: return record = self.wqcore.GetRecord(pos) if record == None or record.color != 0: return x,y = pos self.stepCount += 1 self.poses.append(pos) self.wqcore.Steps.append(Record(row=y,col=x,count=self.stepCount, color=color)) self.wqcore.UpdateRecords() stone = self.black_stone if color == 1 else self.white_stone self.canvas.create_image(self.offset + x*R.StoneSize, self.offset + y*R.StoneSize, image=stone) self.isBlack = not self.isBlack def kill(self): deads = self.wqcore.KillOther() steps = self.wqcore.Steps[:] if deads != None: if len(deads) == 1: col,row = deads[0] if self.once.count == self.stepCount - 1 and (col,row) in self.wqcore.LinkPoses((self.once.col,self.once.row)): self.back_one(None) return self.once = Record(row, col, self.stepCount,0) for d in deads: r = self.wqcore.GetRecord(d) r = Record(r.row,r.col,r.count, -self.wqcore.Current().color) self.deads.append(r) self.delete_stone(d) for i,s in enumerate(steps): if (s.col,s.row) == d: self.wqcore.Steps[i].color = 0 else: deads = self.wqcore.KillSelf() if deads != None: for d in deads: r = self.wqcore.GetRecord(d) r = Record(r.row,r.col,r.count,self.wqcore.Current().color) self.deads.append(r) self.delete_stone(d) for i,s in enumerate(steps): if (s.col,s.row) == d: self.wqcore.Steps[i].color = 0 self.wqcore.DeadPoses.clear() self.wqcore.UpdateRecords() def back_one(self, e): if len(self.poses) == 0: return pos = self.poses.pop() self.delete_stone(pos) self.show_deads() p = self.wqcore.Steps.pop() for i, r in enumerate(self.wqcore.Records[:]): if (p.col, p.row) == (r.col,r.row): self.wqcore.Records[i].count = -1 self.wqcore.Records[i].color = 0 self.isBlack = not self.isBlack self.stepCount -= 1 def get_deads(self): self.wqcore.GetDeadBlocks(self.deads) result = [r for r in self.deads if (r.col,r.row) in self.wqcore.DeadPoses] self.wqcore.DeadPoses.clear() for r in result[:]: self.deads.remove(r) return result def show_deads(self): deads = self.get_deads() if deads == None: return for d in deads: for i, s in enumerate(self.wqcore.Steps[:]): if s.count == d.count: self.wqcore.Steps[i].color = d.color stone = self.black_stone if d.color == 1 else self.white_stone self.canvas.create_image(self.offset + d.col*R.StoneSize, self.offset + d.row*R.StoneSize, image=stone) self.wqcore.DeadPoses.clear() self.wqcore.UpdateRecords() def delete_stone(self, pos): r = self.wqcore.GetRecord(pos) if r == None or r.color == 0: return col,row = pos x,y = self.offset + col*R.StoneSize, self.offset + row*R.StoneSize stone = self.canvas.find_closest(x,y) if stone: self.canvas.delete(stone) class WqCore: def __init__(self): self.Steps = [] # 棋步 self.Records = [Record(r,c) for r in range(0,19) for c in range(0,19)] # 棋谱 self.DeadPoses = [] def UpdateRecords(self): records = self.Records[:] for i,r in enumerate(records): for s in self.Steps: if (s.col,s.row) == (r.col,r.row): self.Records[i] = s def Current(self): if len(self.Steps) == 0: return None else: return self.Steps[-1] def KillOther(self): c = self.Current() if c == None: return None poses = self.LinkPoses((c.col,c.row)) records = [r for r in self.Records if (r.col,r.row) in poses and r.color != c.color and r.color != 0] result = [] for temp in records: self.DeadPoses.clear() deads = self.GetDeadPoses((temp.col, temp.row)) if deads != None: [result.append(d) for d in deads] return None if len(result) == 0 else result[:] def KillSelf(self): c = self.Current() if c == None: return None poses = self.LinkPoses((c.col,c.row)) records = [r for r in self.Records if (r.col,r.row) in poses and r.color == c.color and r.color != 0] for temp in records: self.DeadPoses.clear() deads = self.GetDeadPoses((temp.col, temp.row)) if deads != None: return deads return None def GetRecord(self, pos): for r in self.Records: if (r.col, r.row) == pos: return r return None def GetDeadPoses(self, pos): record = self.GetRecord(pos) self.DeadPoses.append(pos) poses = set(self.LinkPoses(pos)).difference(set(self.DeadPoses)) records = [r for r in self.Records if (r.col,r.row) in poses] result = [] for t in records: if t.color == 0: self.DeadPoses.clear() return None elif t.color == record.color: deads = self.GetDeadPoses((t.col,t.row)) if deads != None: continue else: return None return self.DeadPoses def GetDeadBlocks(self, deads): self.DeadPoses.clear() curr = self.Current() col,row,color = curr.col, curr.row,curr.color poses = self.LinkPoses((col,row)) for pos in poses: for d in deads: if (d.col,d.row) == pos and d.color == -color: self.GetDeadBlock(d,deads) def GetDeadBlock(self, record, deads): col,row,color = record.col,record.row,record.color self.DeadPoses.append((col,row)) links = set(self.LinkPoses((col,row))).difference(set(self.DeadPoses)) poses = [(r.col,r.row) for r in deads if (r.col,r.row) in links and r.color == color] for x,y in poses: r = self.GetRecord((x,y)) r.color = color self.GetDeadBlock(r, deads) def IsValid(self, pos): x,y = pos if 0 <= x < 19 and 0 <= y < 19: return True else: return False def LinkPoses(self, pos): poses = [] x,y = pos for i in range(-1,2): for j in range(-1,2): if i==j or i==-j: continue if self.IsValid(pos): poses.append((x+j,y+i)) poses.append(pos) return poses def RoundPoses(self, pos): poses = [] x,y = pos for i in range(-1,2): for j in range(-1,2): if self.IsValid(pos): poses.append((x+j,y+i)) return poses class Record: def __init__(self, row=-1,col=-1,count=-1,color=0): self.row = row self.col = col self.count = count self.color = color # black:1,white:-1,empty=0 def __str__(self): return '(row:{},col:{},count:{},color:{})'.format(self.row,self.col,self.count,self.color) class R: # stone and board StoneSize = 32 CellNumber = 19 StarNumber = 9 # bind event names ButtonLeft = '<Button-1>' ButtonRight = '<Button-3>' if __name__ == "__main__": c = WqCore()
代码在 x01.lab/py/game/weiqi 下,链接:https://gitee.com/chinax01/x01.lab
来源:https://www.cnblogs.com/china_x01/p/12456382.html