忽略王车易位,国际象棋实现起来还是比较简单的,按照行棋路线不断进行即可,遇到边界或棋子则停,兵,王,马只走一步,兵有方向,如此而已。
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()
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'game\chess\res')
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()
3.下载
来源:oschina
链接:https://my.oschina.net/u/4311839/blog/4286337