• x01.chess: 国际象棋


    忽略王车易位,国际象棋实现起来还是比较简单的,按照行棋路线不断进行即可,遇到边界或棋子则停,兵,王,马只走一步,兵有方向,如此而已。

    1.效果图 

                                       

    2.代码

    import sys, copy, os, configparser
    import tkinter as tk 
    from tkinter import messagebox
    
    import utils 
    from game.chess.core import Board, R 
    
    sys.path.append(utils.R.CurrentDir)
    
    class MainWindow(tk.Tk):
        def __init__(self):
            super().__init__()
            self.title("x01.chess")
            size = (R.CellNumber+0.5)*R.CellSize
            utils.R.win_center(self, w=size, h=size)
    
            self.background = 'lightgrey'
            self.foreground = 'black'
            self.menu = tk.Menu(self, bg=self.background, fg=self.foreground)
            utils.R.generate_menus(self, ['file', 'help'])
            self.configure(menu=self.menu)
    
            self.board = Board(self)
            self.board.pack(pady=R.CellSize/4)
    
        def file_start_game(self):
            self.board.pack_forget()
            self.board = Board(self)
            self.board.pack(pady=R.CellSize/4)
    
        def help_about(self):
            messagebox.showinfo('x01.chess', '国际象棋程序,版权属于x01(黄雄)所有。')
    
    if __name__ == "__main__":
        w = MainWindow()
        w.mainloop()
    main.py
    import tkinter as tk 
    import utils
    import os
    from itertools import count 
    from tkinter import messagebox
    
    class R:
        ImgDir = os.path.join(utils.R.CurrentDir, r'gamechess
    es')
        CellNumber = 8
        CellSize = 64
        Color1 = '#e6a803'
        Color2 = '#8b8350'
        Highlight = '#2ef70d'
    
        OrthogalPoses = ((-1, 0), (0, 1), (1, 0), (0, -1))
        DiagonalPoses = ((-1, -1), (-1, 1), (1, -1), (1, 1))
        KnightPoses = ((-2, -1), (-2, 1), (-1, -2), (-1, 2),
                        (1, -2), (1, 2), (2, -1), (2, 1))
    
        Directions = {
            'p': ((1,0), (2,0), (1,1), (1,-1)),
            'n': KnightPoses,
            'b': DiagonalPoses,
            'r': OrthogalPoses,
            'q': DiagonalPoses + OrthogalPoses,
            'k': DiagonalPoses + OrthogalPoses,
    
            'P': ((-1,0), (-2,0), (-1,1), (-1,-1)),
            'N': KnightPoses,
            'B': DiagonalPoses,
            'R': OrthogalPoses,
            'Q': DiagonalPoses + OrthogalPoses,
            'K': DiagonalPoses + OrthogalPoses
        }
    
    class Board(tk.Frame):
        def __init__(self, master=None):
            super().__init__(master)
            self.master = master 
            self.cell_size = R.CellSize 
            self.offset = R.CellSize // 2
            self.cell_number = R.CellNumber
            self.color1 = R.Color1 
            self.color2 = R.Color2 
            self.highlight = R.Highlight
    
            self.canvas = tk.Canvas(self, bg="#999" , width=R.CellNumber*R.CellSize, height=R.CellNumber*R.CellSize)
            self.canvas.pack()
    
            self.piece_images = {
                'r': tk.PhotoImage(file=os.path.join(R.ImgDir, 'rook_white.png')),
                'n': tk.PhotoImage(file=os.path.join(R.ImgDir, 'knight_white.png')),
                'b': tk.PhotoImage(file=os.path.join(R.ImgDir, 'bishop_white.png')),
                'q': tk.PhotoImage(file=os.path.join(R.ImgDir, 'queen_white.png')),
                'k': tk.PhotoImage(file=os.path.join(R.ImgDir, 'king_white.png')),
                'p': tk.PhotoImage(file=os.path.join(R.ImgDir, 'pawn_white.png')),
    
                'R': tk.PhotoImage(file=os.path.join(R.ImgDir, 'rook_black.png')),
                'N': tk.PhotoImage(file=os.path.join(R.ImgDir, 'knight_black.png')),
                'B': tk.PhotoImage(file=os.path.join(R.ImgDir, 'bishop_black.png')),
                'Q': tk.PhotoImage(file=os.path.join(R.ImgDir, 'queen_black.png')),
                'K': tk.PhotoImage(file=os.path.join(R.ImgDir, 'king_black.png')),
                'P': tk.PhotoImage(file=os.path.join(R.ImgDir, 'pawn_black.png')),
            }
            self.pieces = []
            self.init_pieces()
    
            self.current_move = (None, None)
            self.chess_core = ChessCore(self.pieces)
            self.is_black = True 
    
            self.draw_cells()
            self.draw_pieces()
            self.bind_events()
    
        def init_pieces(self):
            names = 'rnbqkbnrppppppppPPPPPPPPRNBQKBNR'
            for row in range(8):
                for col in range(8):
                    if row == 0 or row==1:
                        self.pieces.append(Piece(row,col,names[row*8+col]))
                    elif row == 6 or row==7:
                        self.pieces.append(Piece(row,col,names[(row-4)*8+col]))
                    else:
                        self.pieces.append(Piece(row,col,'.'))
    
        def draw_pieces(self):
            self.canvas.delete('pieces')
            for p in self.pieces:
                if p.name == '.': continue
                self.canvas.create_image(p.col*R.CellSize+self.offset, 
                    p.row*R.CellSize+self.offset, image=self.piece_images[p.name], tags=('pieces'), anchor='c')
    
        def bind_events(self):
            self.canvas.bind('<Button-1>', self.click)
    
        def click(self, e=None):
            dead = self.check_dead()
            if dead[0]: 
                messagebox.showinfo('x01.chess', 'black king is dead!')
                return
            if dead[1]:
                messagebox.showinfo('x01.chess', 'white king is dead!')
                return
    
            self.canvas.delete("highlights")
            r,c = e.y // self.cell_size,  e.x // self.cell_size
            piece = self.chess_core.get_piece((r,c))
            moves = self.chess_core.get_moves(self.is_black)
            highlight_moves = [p[1] for p in moves if piece == p[0]]
            for h in highlight_moves:
                self.draw_highlight(h)
                self.draw_pieces()
    
            if self.current_move[0]  and self.current_move[1] is None:
                self.current_move = (self.current_move[0], piece)
                if self.current_move[0] and self.current_move[1]:
                    moves = self.chess_core.get_moves(self.is_black)
                    can_moves = [p[1] for p in moves if self.current_move[0] == p[0]]
                    if self.current_move[1] in can_moves:
                        if self.move():
                            self.current_move = (None, None)
                            self.is_black = not self.is_black
                            self.p2q()
                            self.draw_pieces()
            self.current_move = (piece, None)
    
        def check_dead(self):
            blackdead, whitedead = True, True
            for p in self.pieces:
                if 'k' == p.name: whitedead = False
                if 'K' == p.name: blackdead = False
            return (blackdead, whitedead)
    
        def p2q(self):
            pieces = self.pieces[:]
            for i, p in enumerate(pieces):
                if p.name == 'p' and p.row == 7:
                    self.pieces[i].name = 'q'
                elif p.name == 'P' and p.row == 0:
                    self.pieces[i].name = 'Q'
    
        def move(self):
            org, dest = self.current_move
            org_index = self.get_index(org)
            dest_index = self.get_index(dest)
            if org_index is None or dest_index is None: 
                return  False
            self.pieces[dest_index].name = org.name 
            self.pieces[org_index].name = '.'
            self.draw_pieces()
            return True 
    
        def get_index(self, piece):
            for i, p in enumerate(self.pieces):
                if p == piece: return i 
            return None 
            
        def draw_cells(self):
            color = self.color2 
            for row in range(self.cell_number):
                color = self.alternate_color(color)
                for col in range(self.cell_number):
                    x1,y1 = self.get_xy(row,col) 
                    x2,y2 = x1+self.cell_size, y1+self.cell_size
                    self.canvas.create_rectangle(x1,y1,x2,y2,fill=color)
                    color = self.alternate_color(color)
    
        def get_xy(self, row, col):
            x = self.cell_size * col 
            y = self.cell_size * row 
            return (x,y)
    
        def alternate_color(self, color):
            if color == self.color1:
                return self.color2 
            return self.color1 
    
        def test(self):
            moves = self.chess_core.get_moves(isblack=False)
            for org,dest in moves:
                print(org, dest)
    
        def draw_highlight(self, piece):
            # self.canvas.delete('highlights')
            x1,y1 = self.get_xy(piece.row, piece.col)
            x2,y2 = x1+self.cell_size, y1+self.cell_size
            self.canvas.create_rectangle(x1,y1,x2,y2,fill=R.Highlight, tags='highlights')
    
    class Piece:
        def __init__(self, row, col, name):
            self.row = row 
            self.col = col 
            self.name = name
    
        def __str__(self):
            return '(row={},col={},name={})'.format(self.row, self.col, self.name)
    
        def __eq__(self, other):
            return self.row == other.row and self.col == other.col
    
    class ChessCore:
        def __init__(self, pieces):
            self.pieces = pieces[:]
            self.rotates = []
    
        def get_piece(self, pos):
            for p in self.pieces:
                if pos == (p.row, p.col):
                    return p
            return None 
        
        def get_moves(self, isblack=True):
            # 忽略王车易位
            for p in self.pieces:
                if isblack:
                    if p.name.islower() or p.name == '.': continue
                    for d in R.Directions[p.name]:
                        for i in range(1,8):
                            pos = (p.row + d[0]*i, p.col + d[1]*i)
                            dest = self.get_piece(pos)
                            if not self.valid_pos(pos) or dest.name.isupper():  break
                            if p.name == 'P' and d in ((-1,0), (-2,0)) and dest.name != '.': break
                            if p.name == 'P' and d == (-2,0) and (p.row != 6 or self.get_piece((p.row-1,p.col)).name != '.'): break
                            if p.name == 'P' and d in ((-1,1), (-1,-1)) and dest.name == '.': break 
                            yield (p, dest)
                            if p.name in 'PNK' or dest.name.islower(): break 
                else:
                    if p.name.isupper() or p.name == '.': continue
                    for d in R.Directions[p.name]:
                        for i in range(1,9): 
                            pos = (p.row + d[0]*i, p.col + d[1]*i)
                            dest = self.get_piece(pos)
                            if not self.valid_pos(pos) or dest.name.islower():  break
                            if p.name == 'p' and d in ((1,0), (2,0)) and dest.name != '.': break
                            if p.name == 'p' and d == (2,0) and (p.row != 1 or self.get_piece((p.row+1,p.col)).name != '.'): break
                            if p.name == 'p' and d in ((1,1), (1,-1)) and dest.name == '.': break 
                            yield (p, dest)
                            if p.name in 'pnk' or dest.name.islower(): break 
    
    
        def valid_pos(self, pos):
            if 0 <= pos[0] <= 7 and 0 <= pos[1] <= 7: return True
            return False 
    
    
    if __name__ == "__main__":
        b = Board()
        b.test()
    core.py

    3.下载

    x01.lab/py/game/chess

  • 相关阅读:
    java I/O框架 (三)基本流
    java I/O框架 (二)文件操作(File)
    java I/O框架 (一)总览
    8.内部类
    7.权限
    6.继承
    5.代码块
    4.面向对象
    3控制语句
    PHP ksort() 函数
  • 原文地址:https://www.cnblogs.com/china_x01/p/12924022.html
Copyright © 2020-2023  润新知