一.題目簡介
本課程設計主要是使用Swing這個Java自帶的圖形開發工具實作中國象棋棋子及棋盤的繪制,并根據相應的象棋規則,可以設計棋譜,完成棋譜的儲存和對已儲存的棋譜的示範,友善現在愛棋人士對殘局的收藏于研究,而且達到了進一步鞏固課堂上所學到的知識,深刻把握Java語言的重要概念及其面向對象的特性,熟練的應用面向對象的思想和設計方法解決實際問題的能力的目的。
1.當兩方有一方将(帥)被吃掉後,程式不能自動結束或提示遊戲結束,但想到該程式并不是要進行兩方對弈,而是要設計棋譜是以在能力實作範圍内可以允許該事件發生;
2.使用者不能自動的将棋子删除,使得在擺棋譜過程中增加了工作量,必須從一開始進行,記錄每一個棋子的行走過程,因為該程式給使用者提供按照一定的思路設計防止其他非專業使用者亂走和亂擺。
二.結對分工及過程
姓 名 | 學号 | 承 擔 的 任 務 |
李增佐 | 201303014031 | 棋盤界面設計,對弈規則的實作,設計棋譜 |
紀欣 | 201303014016 | 儲存下棋的步驟進而實作悔棋的實作,完成儲存棋譜 |
1.棋子的設計;
(1)聲明一個ChessPiece類,完成各個棋子的外觀設計;
public class ChessPiece extends JLabel
{String name;
Color backColor=null,foreColor;
String 顔色類别=null;
ChessBoard board=null;
int width,height;
public ChessPiece(String name,Color fc,Color bc,int width,int height,ChessBoard board){
this.name=name;
this.board=board;
this.width=width;
this.height=height;
foreColor=fc;
backColor=bc;
setSize(width,height);
setBackground(bc);
addMouseMotionListener(board);
addMouseListener(board);}
public void paint(Graphics g){
g.setColor(foreColor);
g.fillOval(2,2,width-2,height-2);
g.setColor(Color.white);
g.setFont(new Font("隸書",Font.BOLD,28));
g.drawString(name,7,height-8);
g.setColor(Color.yellow);
g.drawOval(2,2,width-2,height-2);}
public int getWidth(){return width;}
public int getHeight(){return height;}
public String getName(){return name;}
public Color 擷取棋子顔色(){ return foreColor;}
public void set棋子類别(String 類别){顔色類别=類别;}
public String 棋子類别(){return 顔色類别;}}
(2)實作各個棋子外觀;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ChessBoard extends JPanel implements MouseListener,MouseMotionListener{
public ChessPoint point[][];
public int unitWidth,unitHeight;
int x軸長,y軸長;
int x,y;
boolean move=false;
public String 紅方顔色="紅色",黑方顔色="黑色";
ChessPiece 紅車1,紅車2,紅馬1,紅馬2,紅相1,紅相2,紅帥,紅士1,紅士
2,紅兵1,紅兵2,紅兵3,紅兵4,紅兵5,紅炮1,紅炮2;
ChessPiece 黑車1,黑車2,黑馬1,黑馬2,黑将,黑士1,黑士2,黑卒1,黑卒2,黑卒3,黑卒4,黑卒5,黑象1,黑象2,黑炮1,黑炮2;
int startX,startY;
int startI,startJ;
public boolean 紅方走棋=true,黑方走棋=false;
Rule rule=null;
public MakeChessManual record=null;
public ChessBoard(int w,int h,int r,int c){
setLayout(null);
addMouseListener(this);
addMouseMotionListener(this);
Color bc=getBackground();
unitWidth=w;
unitHeight=h;
x軸長=r;
y軸長=c;
point=new ChessPoint[r+1][c+1];
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
point[i][j]=new ChessPoint(i*unitWidth,j*unitHeight,false); }}
rule=new Rule(this,point);
record=new MakeChessManual(this,point) ;
紅車1=new ChessPiece("車",Color.red,bc,w-4,h-4,this);
紅車1.set棋子類别(紅方顔色);
……//分别是紅方各個棋子的設計
紅兵5=new ChessPiece("兵",Color.red,bc,w-4,h-4,this);
紅兵5.set棋子類别(紅方顔色);
黑将=new ChessPiece("将",Color.blue,bc,w-4,h-4,this);
黑将.set棋子類别(黑方顔色);
……//分别是黑方各個棋子的設計
黑卒5=new ChessPiece("卒",Color.blue,bc,w-4,h-4,this);
黑卒5.set棋子類别(黑方顔色);
point[1][10].setPiece(紅車1,this);
……//紅方的每個棋子放到與生活中棋盤位置一樣
point[9][7].setPiece(紅兵5,this);
point[1][1].setPiece(黑車1,this);
……//黑方的每個棋子放到與生活中棋盤位置一樣
point[9][4].setPiece(黑卒5,this); }
(3)棋盤的設計:
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int j=1;j<=y軸長;j++) {
g.drawLine(point[1][j].x,point[1][j].y,point[x軸長][j].x,point[x軸長][j].y); }
for(int i=1;i<=x軸長;i++) {
if(i!=1&&i!=x軸長){
g.drawLine(point[i][1].x,point[i][1].y,point[i][y軸長-5].x,point[i][y軸長-5].y);
g.drawLine(point[i][y軸長-4].x,point[i][y軸長-4].y,point[i][y軸長].x,point[i][y軸長].y); }
else{
g.drawLine(point[i][1].x,point[i][1].y,point[i][y軸長].x,point[i][y軸長].y);}} g.drawLine(point[4][1].x,point[4][1].y,point[6][3].x,point[6][3].y);
g.drawLine(point[6][1].x,point[6][1].y,point[4][3].x,point[4][3].y);
g.drawLine(point[4][8].x,point[4][8].y,point[6][y軸長].x,point[6][y軸長].y);
g.drawLine(point[4][y軸長].x,point[4][y軸長].y,point[6][8].x,point[6][8].y);
for(int i=1;i<=x軸長;i++){
g.drawString(""+i,i*unitWidth,unitHeight/2);}int j=1;
for(char c='A';c<='J';c++){
g.drawString(""+c,unitWidth/4,j*unitHeight);j++;}}
(4)實作棋子按照生活中的對弈規則走棋的程式如下:
public boolean movePieceRule(ChessPiece piece,int startI,int startJ,int endI,int endJ){
this.piece=piece;this.startI=startI;this.startJ=startJ;
this.endI=endI;
this.endJ=endJ;
int minI=Math.min(startI,endI);
int maxI=Math.max(startI,endI);
int minJ=Math.min(startJ,endJ);
int maxJ=Math.max(startJ,endJ);
boolean 可否走棋=false;
if(piece.getName().equals("車")){if(startI==endI)
{int j=0;for(j=minJ+1;j<=maxJ-1;j++){
if(point[startI][j].isPiece()){可否走棋=false;break;} }
if(j==maxJ){可否走棋=true;}}
else if(startJ==endJ) { int i=0;for(i=minI+1;i<=maxI-1;i++)
{ if(point[i][startJ].isPiece()){可否走棋=false;
break;} }
if(i==maxI){可否走棋=true;}}
else{可否走棋=false;}}
else if(piece.getName().equals("馬"))
…..//以及各個棋子規則的設計
實作棋子按對弈規則的移動并記錄棋子移動的位置;
public void mousePressed(MouseEvent e){
ChessPiece piece=null;Rectangle rect=null;
if(e.getSource()==this)move=false;
if(move==false)
if(e.getSource() instanceof ChessPiece){
piece=(ChessPiece)e.getSource();
startX=piece.getBounds().x;
startY=piece.getBounds().y;
rect=piece.getBounds();
for(int i=1;i<=x軸長;i++){
for(int j=1;j<=y軸長;j++){
int x=point[i][j].getX();
int y=point[i][j].getY();
if(rect.contains(x,y))
{startI=i;startJ=j;break;} }}}}
public void mouseMoved(MouseEvent e){ }
public void mouseDragged(MouseEvent e){
ChessPiece piece=null;
if(e.getSource() instanceof ChessPiece){
piece=(ChessPiece)e.getSource(); move=true;
e=SwingUtilities.convertMouseEvent(piece,e,this); }
if(e.getSource()==this){if(move&&piece!=null)
{x=e.getX(); y=e.getY();
if(紅方走棋&&((piece.棋子類别()).equals(紅方顔色))){
piece.setLocation(x-piece.getWidth()/2,y-piece.getHeight()/2);}
if(黑方走棋&&(piece.棋子類别().equals(黑方顔色))){
piece.setLocation(x-piece.getWidth()/2,y-piece.getHeight()/2);}}}}
public void mouseReleased(MouseEvent e){ …}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseClicked(MouseEvent e){ }
}
圖中中國象棋是個菜單包括制作棋譜、儲存棋譜、示範棋譜三個菜單項
設計actionPerformed事件的代碼為:
public void actionPerformed(ActionEvent e){
if(e.getSource()==制作棋譜) {con.removeAll();
儲存棋譜.setEnabled(true);
this.setTitle(制作棋譜.getText());
board=new ChessBoard(45,45,9,10);
record=board.record;
JSplitPane split=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,true,board,record);
split.setDividerSize(5);
split.setDividerLocation(460);
con.add(split,BorderLayout.CENTER);
validate();}
if(e.getSource()==儲存棋譜) {
int state=fileChooser.showSaveDialog(null);
File saveFile =fileChooser.getSelectedFile();
if(saveFile!=null&&state==JFileChooser.APPROVE_OPTION)
{try{
FileOutputStream outOne=newFileOutputStream(saveFile);
ObjectOutputStream outTwo=new ObjectOutputStream(outOne);
outTwo.writeObject(record.擷取棋譜()) ;
outOne.close();
outTwo.close();}
catch(IOException event){} }}
if(e.getSource()==示範棋譜) {
con.removeAll();con.repaint();con.validate(); validate();
儲存棋譜.setEnabled(false);
int state=fileChooser.showOpenDialog(null);
File openFile =fileChooser.getSelectedFile();
if(openFile!=null&&state==JFileChooser.APPROVE_OPTION)
{try{FileInputStream inOne=new FileInputStream(openFile);
ObjectInputStream inTwo=new ObjectInputStream(inOne);
棋譜=(LinkedList)inTwo.readObject() ;
inOne.close();inTwo.close();ChessBoard board=new ChessBoard(45,45,9,10);demon=new Demon(board);
demon.set棋譜(棋譜);con.add(demon,BorderLayout.CENTER);
con.validate(); validate();
this.setTitle(示範棋譜.getText()+":"+openFile); }
catch(Exception event)
{JLabel label=new JLabel("不是棋譜檔案");
label.setFont(new Font("隸書",Font.BOLD,60));
label.setForeground(Color.red);
label.setHorizontalAlignment(SwingConstants.CENTER);
con.add(label,BorderLayout.CENTER);
con.validate(); this.setTitle("沒有打開棋譜"); validate();} }}else
{JLabel label=new JLabel("沒有打開棋譜檔案呢");
label.setFont(new Font("隸書",Font.BOLD,50));
label.setForeground(Color.pink);
label.setHorizontalAlignment(SwingConstants.CENTER);
con.add(label,BorderLayout.CENTER);
con.validate();
this.setTitle("沒有打開棋譜檔案呢"); validate(); }}}
三.代碼位址
https://github.com/lizengzuo/two/tree/master
https://github.com/jixin1995/xiangqi/tree/master
四.測試情況
菜單中儲存棋譜:打開儲存檔案
(1) 打開棋譜
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL1cTO4cDM4gDMyQTMyEjMvwVNwUTMwIzLcZjN2kDN38CX1EDMyc2bsJ2Lc12bj5ycn9Gbi52YuAzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
(2) 如果沒有選擇棋譜檔案則會有如下:
(3) 打開棋譜檔案後:
五.問題及心得
采用程式設計棋子與棋盤,使得棋子更加可觀,棋子和生活中真實存在的棋子相仿,使得使用者使用軟體布置棋譜更加習慣,且有悔棋功能友善了使用者使用在界面上有使用者設計棋譜的步驟使得棋譜從一開始狀态到現在狀态的過程,滿足使用者的需要。
增加打開棋譜檔案功能,增加設計棋譜的作用,增加設計過的棋譜的可讀性,也可以修改已存的棋譜檔案。
具有示範功能,示範棋局的形成,可以手動一步一步的觀察現有棋局的形成,也可以讓軟體自動形成,還可以設定電腦自動形成的時間間隔,增加與使用者之間的互動性,使得軟體更加人性化。