チェスをプレイするためのチェス盤を最初に準備する必要があります。これは適切なサイズ、比率、位置を持つインターフェイスであり、それをフォーム (はい、drawLine) n 直線上に描画します。とスラッシュの場合、特定の値はインターフェイスのサイズに応じて設定されます。このようにして描かれたインターフェイスはすっきりしていて美しいです~
public void paint(Graphics g){ super.paint(g);//重写画图函数 Font f=new Font("微软雅黑",Font.BOLD,30); g.setFont(f); g.drawRect(60, 50, 500, 560);//外圈 g.drawRect(70, 60, 480, 540);//内圈 //横线部分 int length=60; for(int i=0;i<9;i++){ g.drawLine(70, length, 550, length); length+=60; } //中间汉字 g.drawString("楚河", 160, 340); g.drawString("汉界", 400, 340); //竖线部分 length=130; for(int i=0;i<7;i++){ //上半部分竖线 g.drawLine( length,60, length,300); //下半部分竖线 g.drawLine( length,360, length,600); length+=60; } //上半部分九宫格斜线 g.drawLine(250, 60, 370, 180); g.drawLine(370, 60, 250, 180); //下半部分九宫格斜线 g.drawLine(250, 480, 370, 600); g.drawLine(250, 600, 370, 480); }
チェス盤を描いた後、機能ボタンを追加します。この時点での機能は現時点では実装されていないと考えられます。好みに応じて自由に追加できます。ここでは、タイムリーな追加と削除を容易にするために、ボタンのタイプを配列に設定することをお勧めします。
//添加到面板上 String[] type = {"开始游戏","重新开始","认 输","悔 棋"}; for(int i=0;i<type.length;i++){ Button btn = new Button(type[i]); btn.setPreferredSize(new Dimension(150,50)); anniu.add(btn); }
現時点では、ボタンが非常にコンパクトであることがわかります。解決策は、このパネルに別のパネルを追加し、それを白に設定することです。上記のボタンは、パネルの流動的なレイアウトに従って下に移動します。ブランク パネルの幅を調整すると、ボタンの位置が変更されることがあります。
見つけたチェスの駒の絵をチェス盤の交点位置に追加して、チェス盤に魂を注入します。他のコンピュータでも実行できます (ここでは png 形式をお勧めします。jpg 形式には正方形の境界線が表示されます)。
次のステップは 3 つのステップです
1. 10 行 9 列の整数配列を作成して、各位置にデータを保存します;
2. 長さの Image 配列を作成します14、チェスの駒のタイプに対応するために使用されます;
3. 整数配列をトラバースして、対応するチェスの駒を描画します;
これは、チェス盤の直感的な図であり、整数の初期値です。配列:
画像をチェスの駒の絵に対応させる:
//初始化给每个chess定义 for(int k=0; k<14; k++){ chess[k] = new ImageIcon(this.getClass().getResource((k+1)+".png")).getImage(); }
図面を横切る:
//根据棋盘布局 for(int i=0;i<place.length;i++){ for(int j=0;j<place[0].length;j++){ if(place[i][j] >0){ bg.drawImage(chess[place[i][j]-1], chessX+60*j, chessY+60*i, 50, 50, null); } } }
関数を通じてマウスドラッグを取得前後の2点で表されるチェス盤上の位置を移動し、この2つの位置の2次元配列の値を交換し、次に、チェスの駒の動きを認識するために再描画します。
int x1, y1, x2, y2; public void mousePressed(MouseEvent e) { x1 = e.getX(); y1 = e.getY(); x1 = getj(x1); y1 = geti(y1); } public void mouseReleased(MouseEvent e) { x2 = e.getX(); y2 = e.getY(); x2 = getj(x2); y2 = geti(y2); } //根据点的坐标得到其代表的位置,具体参数可以微调,我的格子是60x60大小 public int getj(int x){ return (x-50)/60; } public int geti(int y){ return (y-40)/60; }
現時点で遭遇する状況は、移動するたびにインターフェイス全体を再描画する必要があり、画像はフォーム上に直接描画され、データはコンピューター ハードウェアに直接送信されます。このように、描画速度が遅いため、一歩踏み出すたびにインターフェースがちらつきますが、この場合、画像をキャッシュに保存してから、ハードウェアを介さずに直接描画できるため、効率が高くなります。大幅に改善されました。
BufferedImage buffer = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics bg = buffer.getGraphics(); //这个中间写的是你画界面的方法,也就是上面提到的paint方法内部 //...... //绘制缓存到窗体上 g.drawImage(buffer, 0, 0, null);
先手を取って相手の大将または大将を倒したチームが勝ちとなります。勝利を表示するために、誰が勝ったのか、誰が負けたのかを決定する関数を記述してください。同時に、データを 0 に初期化し、次のラウンドの準備をします。 ゲーム:
(showMessageDialog メソッドはボックスから直接ジャンプできます)
//判断游戏结束并显示胜局 public void isWine() { System.out.println(place[y1][x1]+" "+place[y2][x2]); if (place[y2][x2]==7&&place[y1][x1]!=0) { place[y2][x2] = place[y1][x1]; place[y1][x1] = 0; UI.repaint(); JOptionPane.showMessageDialog(null, "黑方 胜利!"); again(); } else if(place[y2][x2]==14&&place[y1][x1]!=0) { place[y2][x2] = place[y1][x1]; place[y1][x1] = 0; UI.repaint(); JOptionPane.showMessageDialog(null, "红方 胜利!"); again(); } } //游戏结束时要重绘 public void again(){ for(int i=0; i<place.length; i++){ for(int j=0; j<place[0].length; j++){ place[i][j] = 0; } } }
アクション リスナーの追加
public void actionPerformed(ActionEvent e) { type = e.getActionCommand(); if("开始游戏".equals(type)||"重新开始".equals(type)){ x=0; count = 1;//这里要把每次的走棋方刷新,认输时也需要刷新 init(); UI.repaint(); } } //初始化place坐标 public void init(){ /*红兵 1.png *红炮 2.png *红車 3.png *红马 4.png *红相 5.png *红仕 6.png *红帥 7.png *黑卒 8.png *黑炮 9.png *黑車 10.png *黑马 11.png *黑象 12.png *黑士 13.png *黑将 14.png */ for(int i=0;i<place.length;i++){ for(int j=0;j<place[0].length;j++){ place[i][j] = 0; } } place[0][0] = 10; place[9][0] = 3; place[0][1] = 11; place[9][1] = 4; place[0][2] = 12; place[9][2] = 5; place[0][3] = 13; place[9][3] = 6; place[0][4] = 14; place[9][4] = 7; place[0][5] = 13; place[9][5] = 6; place[0][6] = 12; place[9][6] = 5; place[0][7] = 11; place[9][7] = 4; place[0][8] = 10; place[9][8] = 3; place[2][1] = 9; place[7][1] = 2; place[2][7] = 9; place[7][7] = 2; place[3][0] = 8; place[6][0] = 1; place[3][2] = 8; place[6][2] = 1; place[3][4] = 8; place[6][4] = 1; place[3][6] = 8; place[6][6] = 1; place[3][8] = 8; place[6][8] = 1; }
ここでの init 関数は、整数の 2 次元配列を、トラバーサルの開始後にチェスの駒を追加できる状態に初期化することです。
//规定各个棋子的移动规则 public boolean rule(int gi, int gj,int si, int sj){ int x = place[gi][gj]; int y = place[si][sj]; int start, end; //判断为何种棋子 //車:只能走直线 if(x == 3||x == 10){ if(gi != si&&gj != sj) return false; else if(gi == si){ start = Math.min(gj, sj); end = Math.max(gj, sj); for(int m = 1; m < end - start; m++){ if(place[gi][start+m] != 0) return false; } return true; } else if(gj == sj){ start = Math.min(gi, si); end = Math.max(gi, si); for(int m = 1; m < end - start; m++){ if(place[start+m][gj] != 0) return false; } return true; } else return true; } //马:走日,且某个位置不可以有棋子 else if(x == 4||x == 11){ //下 if(si - gi == 2&&Math.abs(gj-sj) == 1&&place[gi+1][gj] == 0) return true; //上 else if(gi - si == 2&&Math.abs(gj-sj) == 1&&place[gi-1][gj] == 0) return true; //右 else if(sj - gj == 2&&Math.abs(gi-si) == 1&&place[gi][gj+1] == 0) return true; //左 else if(gj - sj == 2&&Math.abs(gi-si) == 1&&place[gi][gj-1] == 0) return true; //否则不可以走 else return false; } //相:走田,且不能过河 else if(x == 5||x == 12){ //左上 if(gi - si == 2&&gj - sj == 2&&place[gi-1][gj-1] == 0){ if((x == 5&&si >= 5)||(x == 12&&si < 5)) return true; else return false; } //右上 else if(gi - si == 2&&sj - gj == 2&&place[gi-1][gj+1] == 0){ if((x == 5&&si >= 5)||(x == 12&&si < 5)) return true; else return false; } //左下 else if(si - gi == 2&&gj - sj == 2&&place[gi+1][gj-1] == 0){ if((x == 5&&si >= 5)||(x == 12&&si < 5)) return true; else return false; } //右下 else if(si - gi == 2&&sj - gj == 2&&place[gi+1][gj+1] == 0){ if((x == 5&&si >= 5)||(x == 12&&si < 5)) return true; else return false; } else return false; } //士:斜着走不能出田字格 else if(x == 6||x == 13){ if(Math.abs(gj-sj)==1&&Math.abs(gi-si)==1){ if(x == 6&&si >= 7&&sj >= 3&&sj <= 5) return true; else if(x == 13&&si <= 2&&sj >= 3&&sj <= 5) return true; else return false; } else return false; } //将:不能出田字格且不能会面 else if(x == 7||x == 14){ if((Math.abs(gj-sj)==1&&gi - si ==0)||(gj - sj ==0&&Math.abs(gi-si)==1)){ if(x == 7&&si >= 7&&sj >= 3&&sj <= 5) return true; else if(x == 14&&si <= 2&&sj >= 3&&sj <= 5) return true; else return false; } else return false; } //炮:隔一个 else if(x == 2||x == 9){ //若要吃棋子,必须中间有且只有一枚棋子 if(x*y!=0){ int t = 0; if(gi == si){ for(int m = Math.min(gj, sj); m <= Math.max(gj, sj); m++){ if(place[gi][m] != 0) t++; } } else if(gj == sj){ for(int m = Math.min(gi, si); m <= Math.max(gi, si); m++){ if(place[m][gj] != 0) t++; } } if(t == 3) return true; } //若为不吃棋子的情况,中间不可以有其他棋子,且只能走直线 else { int t = 0; if(gi == si){ for(int m = Math.min(gj, sj); m <= Math.max(gj, sj); m++){ if(place[gi][m] != 0) t++; } } else if(gj == sj){ for(int m = Math.min(gi, si); m <= Math.max(gi, si); m++){ if(place[m][gj] != 0) t++; } } if(t == 1) return true; else return false; } } //兵:不能后退,且过了河才可以左右移动 else if(x == 1||x == 8){ //判断是否过河 if(x == 1){ if(gi >=5){ if(gi - si == 1&&gj == sj) return true; else return false; } else if((gi - si == 1&&sj - gj == 0)||(gi - si == 0&&Math.abs(sj-gj) == 1)) return true; else return false; } else if(x == 8){ if(gi <5){ if(si - gi == 1&&gj == sj) return true; else return false; } else if(((si - gi == 1&&sj - gj == 0))||(gi - si == 0&&Math.abs(sj-gj) == 1)) return true; else return false; } else return false; } return false; }
長いリストです。ここでは、大砲と将軍を別々に考える必要があります。大砲には直線と間隔をあけた 2 つの移動方法があり、どちらも移動する必要があります。それはさらに面倒です
//判断将是否会面 public boolean meet(){ int jiangi=0, jiangj=0, shuaii=0, shuaij=0, temp=0; for(int i=0; i<10; i++){ for(int j=0; j<9; j++){ if(place[i][j]==7){ shuaii = i; shuaij = j; } else if(place[i][j]==14){ jiangi = i; jiangj = j; } } } if(shuaij == jiangj){ for(int i=jiangi+1; i<shuaii; i++){ if(place[i][shuaij] != 0) temp++; } } else return false;//没会面 if(temp != 0) return false;//没会面 else return true;//会面了 }
赤と黒が順番にチェスをします
私は、将軍たちが会うかどうかを判断する別の方法を書きました。対面する将軍は、将軍自身の動きだけではありません。その結果、他のチェスの駒の動きも含まれる可能性があるため、これもブール関数です。前の関数と関数は面を返しません。移動するとき、ゲーム数を記録するためにパラメーター x を定義しました。彼の奇数と偶数に従って、どちらの側のターンになるかを決定します。このようにして、チェスのルールが実装されます。
# 間違いが起こるのは避けられないため、リグレットチェス機能を追加する方が適切です。
2 つのポイントの値を交換するとき (またはピースをキャプチャする場合)、前の値を記録し、アクション リスナーが後悔のクリックを聞いたときにそれを元に戻す必要があります。
手を後悔できるのは 1 回だけです。チェスの駒が最初に動かなかった場合、その手を後悔することはできません。
お好みの背景を追加し、チェスをプレイしやすくするために、どちら側のターンであるかをマークします。
背景を追加するには、チェスの駒を描画するのと同じ方法を使用できるため、チェス盤が隠れないように前に描画する必要があります。
これを追加すると、もう 1 つの明らかな問題があります。それは、右側のボタンを操作するたびに、ボタンが消えて背景画像に覆われてしまうことです。
それ以降、3 つの方法がまとめられました:
1. ボタンのペイント メソッドを書き換える;
2. ボタンをメニュー形式で左上隅に追加する;
3. 背景画像上でボタンを直接押して (スクリーンショットを撮り)、それを描画するだけです;
さらに、背景画像に「現在のチェスプレイヤー」という単語を追加して、現在のチェスプレイヤーを表示することもできます。横のチェスプレイヤー ファング将軍の写真。
ここで count パラメーターが借用されてリスナーに渡され、コンストラクターが書き換えられます。
int count=1; if(listener.count==1){ //画帥 bg.drawImage(chess[6], 708, 322, 50, 50, null); }else if(listener.count==-1){ //画将 bg.drawImage(chess[13], 708, 322, 50, 50, null); }
作品ができるたびに、数えて(-1)、どちら側にマークを付けて、絵を描きます。
結果の写真を添付します:
以上がJavaを使用して中国のチェスゲームを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。