第一篇:Java五子棋實現報告
一、實驗目的
(1)使用Java編寫五子棋程序
(2)掌握編寫過程的一些類和類成員的使用,并且了解五子棋制作過程的一些步驟和了解一些算法。
二、實驗環境
在電子樓2樓,裝有My Eclipse 的計算機上進行
三、實驗內容
編寫一個五子棋程序。程序主要實現以下功能:
1.實現五子棋界面,要求人性化界面簡潔美觀; 2.實現黑白色輪流下棋功能,能提示下棋方; 3.實現連成五子自動判斷功能; 4.實現時間設置功能,認輸功能;
核心代碼如下:
1.我的第一步是設計界面。在這個過程的要使用到以下的步驟:
1.使用MyEclipse 創建一個Project關于這個工程,加入兩個類,分別是ChessFrame和Chess,而ChessFrame是這個工程中最重要的一個部分。創建過程中要繼承JFrame類,并且要繼承Runnable 和 MouseListener 這兩個接口,分別是用來監聽鼠標的移動和時間的變化。2.在給這個JFrame設置大小和顏色等一些東西。這里最主要的是使用了兩個函數,是以前沒見過的:
1.這個是用來設置默認的窗口關閉事件的
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);2.這兩個是用來獲得屏幕的大小的
Toolkit.getDefaultToolkit().getScreenSize().height;Toolkit.getDefaultToolkit().getScreenSize().width;
3.把本地的背景圖片加到這個窗口中,作為這個窗口的背景圖:
使用的到的類有BufferedImage和 ImageIO這兩個類,這兩個類是專門用來處理這種功能的。主要的代碼如下:
BufferedImage bg = null;bg = ImageIO.read(new File(“e:/background.jpg”));g.drawImage(bg,0,0,this);這樣這個圖片就加到了這個窗口的背景去了。
這里有一個改進就是雙緩沖技術,可以防止閃屏。這個技術就是在界面和內存都有一幅圖,我們的改動不是直接畫界面,而是內存中先畫好然后把內存中直接顯示出來,那樣就沒有了一前一后的,那就沒有了閃屏的事情發生了。
4.就是畫棋盤和寫一些游戲信息:
這步比較簡單,也沒什么可以說的,用到的一些畫線的函數,和寫String的一些函數。
以上做完以后就可以出現以下的界面:
1.我的第二步就是增加對mouse的點擊和移動的處理,這樣以后就可以用來下棋。在這個過程的要使用到以下的步驟: 1.增加對mouse的監視,然后重寫它的一些函數:
1.我們在ChessFrame的構造函數中加入了addMouseListener()函數,然后重寫關于這個的四個函數,我們這這里不重寫所有的函數,就改寫一個MousePress函數就可以了。改寫的代碼如下:
public void mousePress(MouseEvent arg0){
this.x = arg0.getX();this.y = arg0.getY();if(this.canplay)
} this.repaint();現在要處理的就是加上棋子了,我在這個做了一下小改動可以更加準確的定位下棋的位置:
if(x >= 10 && x <= 374 && y >= 72 && y <= 450){
int sx1 =(this.x72)/ 20;int yx1 =(this.x72)% 20;if(yx1 >= 10){ } if(yy2 >= 10){ } sy2++;sx1++;就是這個,我們通過監控鼠標的就可以得到點擊的X,Y坐標,我在這里通過對它求余,假如余數大于10(就是一個格子的一半)那就給+1,不然不變。后面的畫棋子是很簡單的一個過程,使用的是現成的函數(drawoval)
2.這部要做的就是記錄棋子和五子連的判斷:
1.我們通過一個數組int給保存棋子,如果是0就是沒子,1表示是黑子,2表示白子。在每次重繪的時候遍歷這個數組顯示,這樣就可以保存棋子了。2.判斷五子連起來然后獲勝的算法: 這個算法是鑒戒例子上的:
private boolean isline(int x, int y, int xchange, int ychange, int color){
int tempx = xchange;int tempy = ychange;int count = 1;while(x + xchange >= 0 && y + ychange >= 0
&& color == chess1[x + xchange][y + ychange]){ count++;if(xchange!= 0){ } if(ychange!= 0){ if(ychange < 0){ xchange++;
}
}
}
} ychange--;ychange++;} else { xchange = tempx;ychange = tempy;while(xychange >= 0
} if(count >= 5){
} return true;return false;} else { && color == chess1[xychange]){ count++;if(xchange!= 0){ } if(ychange!= 0){
} if(ychange < 0){
} ychange--;ychange++;} else { xchange++;中心思想就是要判斷就要判斷8個方向,其中有的只是相反的方向,我們使用關于X,Y的相對的變化來判斷,并且使用count來計數,如果到了5個就可以判斷勝利啦。
1.我的第三步就是時間的變化和一些鍵的設置
1.關于時間的變化主要是在于線程的使用,這里我們這個JFrame它繼承了Runnable 這個接口,不過我們要重寫Run函數,這個run函數的代碼如下: public void run(){
if(this.second > 0){
while(true){
this.repaint();if(this.isblack){
this.ss1--;
if(this.ss1 == 0){
JOptionPane
.showMessageDialog(this, “黑方超時~~~~?¤游戲結束”);
this.message1=“0:0:0”;
{
“白方超時~~~~?¤?¤游戲結束”);this.message2=“0:0:0”;this.canplay = false;
{
{ }
this.ss2--;
if(this.ss2 == 0){
this.message1 = this.ss
1/ 3600 + “ : ”
+(this.ss1 / 60this.ss1 / 60 *
this.ss1=-1;
this.canplay = false;
}else if(this.ss1>0)3600 * 60)60this.ss2 / 3600 + “ : ”
+(this.ss2this.ss2 / 3600 * 60 * 60);
this.repaint();}else { }
try {
}
Thread.sleep(1000);e.printStackTrace();} catch(InterruptedException e){ 這個函數是用來事時間的變化,所以每操作以后就讓線程sleep(1000)就可以了,那樣就是一秒鐘。這樣就可以倒計時了。2.現在我們要點擊一個按鈕要它有響應。
這里我們其實就沒用到什么button,那為什么會有反應呢,因為我們通過鼠標的點擊范圍來確定要響應什么函數,這就是這里面的秘密.在public void mouseClicked(MouseEvent arg0)函數里有下面這些if的判斷
if(x1 >= 404 && x1 <= 473 && y1 >= 74 && y1 <= 103)if(x1 >= 404 && x1 <= 473 && y1 >= 127 && y1 <= 155)if(x1 >= 404 && x1 <= 473 && y1 >= 179 && y1 <= 208)if(x1 >= 404 && x1 <= 473 && y1 >= 286 && y1 <= 316)if(x1 >= 404 && x1 <= 473 && y1 >= 338 && y1 <= 367)if(x1 >= 404 && x1 <= 473 && y1 >= 390 && y1 <= 419)這就是為了確定鼠標的范圍,然后相對調用函數。
其他還有就是一些Debug處理,在程序已經處理了,結果的還是蠻可以處理的,不過只能是人人對戰。
四、實驗心得與小結
這次試驗總的來說沒有想像中那么難,還有視屏的幫助,感覺起還是很容易動手的,不過由于自己沒上心,沒有做比較大的改動,最主要的人機的對戰沒做出來是滿遺憾的,不過通過這個試驗,讓我學習了不少的知識,比如雙緩沖,mouselistener 等許多許多的知識,還有關于五子棋算法的設計也是一部分。不管怎么說還是有學到知識的,沒什么改動,但對現有的知識的掌握還是很可以的。
五、指導教師評議
成績評定:
指導教師簽名:
第二篇:五子棋JAVA語言課程設計報告
《Java語言程序設計》
課程設計報告
學 院: 信息科學技術學院 班 級: 軟件技術2班 姓 名: 王更新 學 號: 1108900505 指導教師: 郭韶升 課設時間: 2014-03-17 至2014-03-26
二O一四 年 三月 二十六 日
目 錄
一、設計要求…………………………………………....2
二、設計步驟…………………………………………....2 2.1程序流程圖………………………….…………...2 2.2程序的功能分配……………………….………...3
三、設計正文…………………………………………....6 3.1創建棋盤類……………………………………….6 3.2判斷輸贏功能實現……………………………….9 3.3測試結果……………………………………….....9
四、心得體會…………………………………………...12
五、參考文獻…………………………………………...12 附錄(源代碼)……………………………………….13
一、課程設計要求
設計一個15╳15圍棋棋盤,由兩玩家交替進行對戰,并可以實現以下功能: 1.選擇落子的先后順序 2.重置棋盤 3.刷新重新開始 4.退出提示
并且規定退出者判為負,但退出過程中要有提示。以防不小心點錯了。最后判斷某一方是否為五子連珠。
實現一個簡單的多用戶五子棋的游戲程序,包括如下兩個界面(1)選擇對弈桌(執黑、執白)。
(2)在游戲界面,有開始,退出(游戲未結束、點退出自動判負);
二、設計步驟
2.1程序流程圖
2.2 程序的功能分配
a.棋盤的繪制
public void draw_qipan(Graphics G)//畫棋盤 15*15{
G.setColor(Color.lightGray);
G.fill3DRect(10,10,300,300,true);
G.setColor(Color.black);
for(int i=1;i<16;i++){
G.drawLine(20,20*i,300,20*i);
G.drawLine(20*i,20,20*i,300);
} } b.添加按鈕
Button b1=new Button(“開始”);Button b2=new Button(“重置游戲”);Label lblWin=new Label(“ ”);Checkbox ckbHB[]=new Checkbox[3];Button exist = new Button(“退出”);public void init(){
ckbHB[0]=new Checkbox(“執白”,ckgHB,false);
ckbHB[1]=new Checkbox(“執黑”,ckgHB,false);
ckbHB[2]=new Checkbox(“觀看”,ckgHB, false);}
c.鼠標棋子的觸發事件
public void mouseClicked(MouseEvent e){
Graphics g=getGraphics();
int x1,y1;
x1=e.getX();
y1=e.getY();
if(e.getX()<20 || e.getX()>300 || e.getY()<20 || e.getY()>300){
return;
}
if(x1%20>10){
x1+=10;
}
if(y1%20>10){ y1+=10;
}
x1=x1/20*20;
y1=y1/20*20;
set_Qizi(x1,y1);
m*=(-1);}
d.按鈕的觸發事件
public void actionPerformed(ActionEvent e){
Graphics g=getGraphics();
if(e.getSource()==b1){
Game_start();
}
else{
Game_re();
}
if(e.getSource()==exist){
Game_re();
lblWin.setText(Get_qizi_color(color_Qizi)+“輸了!”);
intGame_Start=0;
}
e.判斷落子的位置及畫出相應的黑白棋子 public void set_Qizi(int x,int y)//落子{
if(intGame_Start==0)//判斷游戲未開始{
return;
}
if(intGame_Body[x/20][y/20]!=0){
return;
}
Graphics g=getGraphics();
if(color_Qizi==1)//判斷黑子還是白子{
g.setColor(Color.black);
color_Qizi=0;
}
else{
g.setColor(Color.white);
color_Qizi=1;
}
g.fillOval(x-10,y-10,20,20);
intGame_Body[x/20][y/20]=color_Qizi+1;}
f.判斷勝負
if(Game_win_1(x/20,y/20))//判斷輸贏1{
lblWin.setText(Get_qizi_color(color_Qizi)+“贏了!”);
intGame_Start=0;
}
if(Game_win_2(x/20,y/20))//判斷輸贏2{
lblWin.setText(Get_qizi_color(color_Qizi)+“贏了!”);
intGame_Start=0;} if(Game_win_3(x/20,y/20))//判斷輸贏3{ lblWin.setText(Get_qizi_color(color_Qizi)+“贏了!”);intGame_Start=0;} if(Game_win_4(x/20,y/20))//判斷輸贏4{ lblWin.setText(Get_qizi_color(color_Qizi)+“贏了!”);
intGame_Start=0;} }
三、設計正文
3.1創建棋盤類
Public class WcyChess extends Applet ActionListener,MouseListener,MouseMotionListener,ItemListener{ int color_Qizi=0;//旗子的顏色標識 0:白子 1:黑子
int intGame_Start=0;//游戲開始標志 0未開始 1游戲中
int intGame_Body[][]=new int[16][16];//設置棋盤棋子狀態
int m=-1;Button b1=new Button(“開始”);Button b2=new Button(“重置游戲”);Label lblWin=new Label(“ ”);Checkbox ckbHB[]=new Checkbox[3];Button exist = new Button(“退出”);CheckboxGroup ckgHB=new CheckboxGroup();NetchatClient chat=new NetchatClient();public void init(){
setLayout(null);
addMouseListener(this);
add(b1);
b1.setBounds(330,50,80,30);
b1.addActionListener(this);
add(b2);
b2.setBounds(330,90,80,30);
b2.addActionListener(this);
ckbHB[0]=new Checkbox(“執白”,ckgHB,false);
ckbHB[0].setBounds(320,20,60,30);
ckbHB[1]=new Checkbox(“執黑”,ckgHB,false);
ckbHB[1].setBounds(380,20,60,30);
ckbHB[2]=new Checkbox(“觀看”,ckgHB, false);
add(ckbHB[0]);
add(ckbHB[1]);
add(ckbHB[2]);
ckbHB[0].addItemListener(this);
ckbHB[1].addItemListener(this);
add(lblWin);
lblWin.setBounds(330,180,80,30);
lblWin.setBackground(Color.red);
lblWin.setText(“勝利者!”);//沒有顯示?
ckbHB[2].setBounds(440, 20,60, 30);
add(exist);
exist.setBounds(330,130,80,30);
implements
//
exist.addActionListener(this);add(chat);chat.setBounds(20, 500, 300, 300);chat.frame();chat.setVisible(true);Game_start_csh();setSize(500,600);setVisible(true);} public void itemStateChanged(ItemEvent e){ if(ckbHB[0].getState())//選擇黑子還是白子{
color_Qizi=0;} else{
color_Qizi=1;} } public void mousePressed(MouseEvent e){} public void mouseClicked(MouseEvent e){ Graphics g=getGraphics();int x1,y1;x1=e.getX();y1=e.getY();if(e.getX()<20 || e.getX()>300 || e.getY()<20 || e.getY()>300){
return;} if(x1%20>10){
x1+=10;} if(y1%20>10){
y1+=10;} x1=x1/20*20;y1=y1/20*20;set_Qizi(x1,y1);m*=(-1);} public void actionPerformed(ActionEvent e){ Graphics g=getGraphics();if(e.getSource()==b1){
Game_start();} else {
Game_re();}
} if(e.getSource()==exist){
Game_re();
lblWin.setText(Get_qizi_color(color_Qizi)+“輸了!”);
intGame_Start=0;} } public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mouseReleased(MouseEvent e){} public void mouseDragged(MouseEvent e){} public void mouseMoved(MouseEvent e){} public void paint(Graphics g){ draw_qipan(g);
3.2判斷輸贏功能實現
if(Game_win_1(x/20,y/20)){ //判斷輸贏1
lblWin.setText(Get_qizi_color(color_Qizi)+“贏了!”);
intGame_Start=0;} if(Game_win_2(x/20,y/20)){ //判斷輸贏2
lblWin.setText(Get_qizi_color(color_Qizi)+“贏了!”);
intGame_Start=0;}
if(Game_win_3(x/20,y/20))//判斷輸贏3{
lblWin.setText(Get_qizi_color(color_Qizi)+“贏了!”);
intGame_Start=0;}
if(Game_win_4(x/20,y/20))//判斷輸贏4{
lblWin.setText(Get_qizi_color(color_Qizi)+“贏了!”);
intGame_Start=0;}
3.3 測試結果
a.進入游戲界面
游戲開始的界面有三個選擇項,用戶可以選擇相應的角色,選擇 完畢后點擊開始進入游戲。
b.選擇角色,開始下棋
首先達到五個棋子連在一塊的贏了,并在紅色區域顯示誰贏了!c.下完后,重新開始
下完一盤后游戲停止,點擊重新開始,界面回到初始界面,選擇角色繼續游戲.d.游戲中點退出,自動判輸
在下棋的過程當中誰中途退出,即點擊退出,系統自動判斷誰輸
四、課程設計心得體會
通過此次課程設計,將我本學期所學的JAVA知識得到鞏固和應用,在設計的過程中我遇到了很到問題,不過在老師和同學們的幫助和自己的思考下還是很好的完成了。這此課程設計還讓我懂得了寫程序不能閉門造車,要努力拓寬知識面,開闊視野,拓展思維。它還讓我學會了在網上查閱那些無限的資料。由于自己的分析設計和程序經驗不足,該系統設計和實現過程中,還有許多沒有完善的地方,比如用戶界面設計不夠美觀,異常出錯處理比較差等多方面問題,這些都有待進一步完善和提高。對于文中出現的不足和系統中出現的問題敬請老師指導。
五、參考文獻
1.吳其慶編著.Java程序設計實例教程.北京:冶金工業出版社 2.柳西玲.許斌編著.Java語言應用開發基礎.北京:清華大學出版社 3.丁振凡 Java 語言實用教程 :北京郵電大學出版社
附錄(源代碼)
import java.net.*;import java.io.*;import java.applet.*;import java.awt.*;import java.awt.event.*;import java.applet.Applet;import java.awt.Color;Public class wuziqi extends Applet implements ActionListener,MouseListener,MouseMotionListener,ItemListener{ int color_Qizi=0;//旗子的顏色標識 0:白子 1:黑子 int intGame_Start=0;//游戲開始標志 0未開始 1游戲中
int intGame_Body[][]=new int[16][16];//設置棋盤棋子狀態
int m=-1;Button b1=new Button(“開始”);Button b2=new Button(“重新開始”);Label lblWin=new Label(“ ”);Checkbox ckbHB[]=new Checkbox[3];Button exist = new Button(“退出”);CheckboxGroup ckgHB=new CheckboxGroup();public void init(){
setLayout(null);
addMouseListener(this);
add(b1);
b1.setBounds(330,50,80,30);
b1.addActionListener(this);
add(b2);
b2.setBounds(330,90,80,30);
b2.addActionListener(this);
ckbHB[0]=new Checkbox(“執白”,ckgHB,false);
ckbHB[0].setBounds(320,20,60,30);
ckbHB[1]=new Checkbox(“執黑”,ckgHB,false);
ckbHB[1].setBounds(380,20,60,30);
ckbHB[2]=new Checkbox(“觀看”,ckgHB, false);
add(ckbHB[0]);
add(ckbHB[1]);
add(ckbHB[2]);
ckbHB[0].addItemListener(this);
ckbHB[1].addItemListener(this);
add(lblWin);
lblWin.setBounds(330,180,80,30);
lblWin.setBackground(Color.red);
e.getY()<20 || e.getY()>300){
lblWin.setText(“勝利者!”);//沒有顯示?
ckbHB[2].setBounds(440, 20,60, 30);add(exist);
exist.setBounds(330,130,80,30);exist.addActionListener(this);Game_start_csh();setSize(500,600);setVisible(true);}
public void itemStateChanged(ItemEvent e){ if(ckbHB[0].getState())//選擇黑子還是白子 {
color_Qizi=0;} else {
color_Qizi=1;} }
public void mousePressed(MouseEvent e){} public void mouseClicked(MouseEvent e){ Graphics g=getGraphics();int x1,y1;x1=e.getX();y1=e.getY();
if(e.getX()<20 || e.getX()>300 ||
return;}
if(x1%20>10){
x1+=10;}
if(y1%20>10){
y1+=10;}
x1=x1/20*20;y1=y1/20*20;set_Qizi(x1,y1);m*=(-1)}
public void actionPerformed(ActionEvent e){ Graphics g=getGraphics();if(e.getSource()==b1){
Game_start();
} else{
// 輸了!“);
贏了!”);
Game_re();}
if(e.getSource()==exist){
Game_re();
color_Qizi=m;
lblWin.setText(Get_qizi_color(color_Qizi)+“
intGame_Start=0;
}
}
public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mouseReleased(MouseEvent e){} public void mouseDragged(MouseEvent e){} public void mouseMoved(MouseEvent e){} public void paint(Graphics g){ draw_qipan(g);}
public void set_Qizi(int x,int y){ //落子
if(intGame_Start==0){//判斷游戲未開始
return;}
if(intGame_Body[x/20][y/20]!=0){
return;}
Graphics g=getGraphics();
if(color_Qizi==1){//判斷黑子還是白子
g.setColor(Color.black);
color_Qizi=0;} else{
g.setColor(Color.white);
color_Qizi=1;}
g.fillOval(x-10,y-10,20,20);
intGame_Body[x/20][y/20]=color_Qizi+1;if(Game_win_1(x/20,y/20)){ //判斷輸贏1 lblWin.setText(Get_qizi_color(color_Qizi)+”
intGame_Start=0;
了!“);
贏了!”);
贏了!“);
15*15
}
if(Game_win_2(x/20,y/20)){ //判斷輸贏2{
lblWin.setText(Get_qizi_color(color_Qizi)+”贏
intGame_Start=0;}
if(Game_win_3(x/20,y/20)){ //判斷輸贏3
lblWin.setText(Get_qizi_color(color_Qizi)+“
intGame_Start=0;}
if(Game_win_4(x/20,y/20)){ //判斷輸贏4
lblWin.setText(Get_qizi_color(color_Qizi)+”
intGame_Start=0;} }
public String Get_qizi_color(int x){
if(x==0){
return “黑子”;} else {
return “白子”;} }
public void draw_qipan(Graphics G){ //畫棋盤 G.setColor(Color.lightGray);
G.fill3DRect(10,10,300,300,true);G.setColor(Color.black);for(int i=1;i<16;i++){
G.drawLine(20,20*i,300,20*i);
G.drawLine(20*i,20,20*i,300);} }
public void Game_start(){ //游戲開始
intGame_Start=1;
Game_btn_enable(false);
b2.setEnabled(true);} public void Game_start_csh(){//游戲開始初始化
intGame_Start=0;
Game_btn_enable(true);
b2.setEnabled(false);
ckbHB[0].setState(true);
for(int i=0;i<16;i++){
for(int j=0;j<16;j++){
intGame_Body[i][j]=0;
}
}
lblWin.setText(“");} public void Game_re(){ //重新開始游戲
repaint();
Game_start_csh();} public void Game_btn_enable(boolean e){ //設置組件狀態
b1.setEnabled(e);
b2.setEnabled(e);
ckbHB[0].setEnabled(e);
ckbHB[1].setEnabled(e);} public boolean Game_win_1(int x,int y){ //橫向判斷輸贏
int x1,y1,t=1;
x1=x;
y1=y;
for(int i=1;i<5;i++){
if(x1>15){
break;
}
if(intGame_Body[x1+i][y1]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
for(int i=1;i<5;i++){
if(x1<1){){
t+=1;
}
else{
break;
}
}
if(t>4){
return true;
}
else{
return false;
} } public boolean Game_win_2(int x,int y){ //縱向判斷輸贏
int x1,y1,t=1;
x1=x;
y1=y;
for(int i=1;i<5;i++){
if(x1>15){
break;
}
if(intGame_Body[x1][y1+i]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
for(int i=1;i<5;i++){
if(x1<1){
break;
}
if(intGame_Body[x1][y1-i]==intGame_Body[x][y]){
t+=1;
}
break;
}
if(intGame_Body[x1-i][y1]==intGame_Body[x][y]
else{
break;
}
}
if(t>4){
return true;
}
else{
return false;
} } public boolean Game_win_3(int x,int y){ //左斜判斷輸贏
int x1,y1,t=1;
x1=x;
y1=y;
for(int i=1;i<5;i++){
if(x1>15){
break;
}
if(intGame_Body[x1+i][y1-i]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
for(int i=1;i<5;i++){
if(x1<1){
break;
}
if(intGame_Body[x1-i][y1+i]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
if(t>4){
return true;
}
else{
return false;
} } public boolean Game_win_4(int x,int y){ //左斜判斷輸贏
int x1,y1,t=1;
x1=x;
y1=y;
for(int i=1;i<5;i++){
if(x1>15){
break;
}
if(intGame_Body[x1+i][y1+i]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
for(int i=1;i<5;i++){
if(x1<1){
break;
} if(intGame_Body[x1-i][y1-i]==intGame_Body[x][y]){
t+=1;
}
else{
break;
}
}
if(t>4){
return true;
}
else{
return false;
} } }
第三篇:五子棋游戲總體設計與實現
4.系統總體設計與實現
4.1 總體設計分析
總體設計是軟件開發過程中的另一個重要階段,在這一階段中將根據需求分析中提出的邏輯模型,科學合理地進行物理模型的設計。這個階段的主要目標是將反映用戶信息需求的邏輯方案轉換成物理方案,并為下一階段提供必要的技術資料。
4.1.1 總體設計原則
(1)整體性:軟件是作為統一整體而存在的。因此,在總體設計中要從整個軟件的角度進行考慮。
(2)靈活性:為保持軟件長久的生命力,要求該手機游戲軟件具有很強的環境適應性。為此,游戲軟件應具有較好的開放性和結構的可變性。
(3)可靠性:可靠性是指軟件抵御外界干擾的能力及受外界干擾時的恢復能力。
(4)經濟性:經濟性是指在滿足游戲軟件需求的前提下,盡可能地減小游戲軟件的開銷。
4.1.2 軟件模塊總體設計
軟件中各模塊之間的關系通常利用層次圖來表示。它是一種一系列多層次的用樹形結構的矩形框描繪數據的層次結構框圖。一個單獨的矩形框作為樹形結構的頂層,各個數據的子集由下面的各層矩形框代表,最底層的各個矩形框代表組成這個數據的實際數據元素(不能再分割的元素),它代表完整的數據結構。這模式非常適合于需求分析階段的需要,層次方框圖對數據結構描繪隨著結構精細化也越來越詳細。反復細化沿著圖中每條路徑,從對頂層信息的分類開始,直到確定了數據結構的全部細節為止。
開始游戲重新游戲游戲選項悔棋認輸五子棋游戲背景音樂退出游戲先后手設置游戲設置棋盤底紋設置棋盤大小設置游戲幫助幫助關于 圖4-1 游戲功能結構
本研究中將游戲軟件分為三大模塊,如圖4-1所示,包括:游戲選項、游戲設置和幫助。按照在調研中搜集的資料對每個模塊的功能進行編排制作。依據上述功能的分析,本研究中,將游戲軟件在三大模塊的基礎上又對每一大模塊又分為幾個子模塊:
游戲選項包括六個模塊:開始游戲、重新游戲、悔棋、認輸、背景音樂和退出游戲。
游戲設置包括三個模塊:先后手設置、棋盤底紋顏色設置和棋盤大小設置。
幫助包括兩個模塊:游戲幫助和關于。
4.2 游戲設計
4.2.1 游戲前的準備
本游戲在開發之前需要做一些前期準備工作,尤其是對于精通五子棋游戲的Java 游戲開發者來說。通常情況下,一款運用起來比較熟練地 J2ME 開發工具
是必不可少的。本游戲使用的是J2ME的簡化開發工具 Sun Java(TM)Wireless Toolkit 2.5.2 for CLDC,他需先將Java虛擬機安裝調試好之后才能使用。WTK 2.5.2 不帶有文本編輯功能,所以需要另尋搭配使用。本游戲采用 Ultra Edit 進行編輯。本游戲需要幾張后綴名為.png格式的卡通圖,除了一張用作五子棋游戲的 Logo 外,其余的都將在游戲中使用。4.2.2 游戲界面和事件驅動設計
游戲的界面設計采取傳統游戲界面風格,如圖4-2所示。游戲設計中采用傳統界面游戲風格,首先啟動游戲,然后進入游戲開始界面,界面中放置“設置”、“開局”、“幫助”、“關于”四個選項供玩家選擇。其中“設置”選項主要是對游戲的相關功能進行設置,如游戲難度設置。另外還有“悔棋”、“重玩”等項目的設置。除此之外還包括查看游戲幫助、游戲介紹等。
圖4-2 游戲界面設計
所謂事件驅動,簡單地說就是你點什么按鈕(即產生什么事件),電腦執行什么操作(即調用什么函數)。當然事件不僅限于用戶的操作。我們知道,事件是事件驅動的核心自然是。從事件角度說,一個事件收集器、一個事件發送器和一個事
件處理器組成了事件驅動程序的基本結構。事件收集器專門負責收集包括來自硬件的(如時鐘事件等)、來自用戶的(如鍵盤、鼠標事件等)及來自軟件的(如應用程序本身、操作系統等)的所有事件。將收集器收集到的事件分發到目標對象中則由事件發送器負責完成。具體的事件響應工作則由事件處理器完成,它需要運用虛函數機制(函數名取為類似于 Handle Msg 的一個名字),它往往要到實現階段才完全確定。事件處理器對于框架的使用者來說是他們唯一能夠看到的。棋類游戲通常具備兩個重要特性,首先是對戰雙方輪流落子,其次是落子間隔通常是不確定的,尤其是對戰后期,可能每一步棋都要經過深思熟慮,無論是人還是計算機,都無法對時間間隔有事先的預期。基于以上兩個特性,本游戲摒棄了大多數游戲采用的線程或定時器驅動游戲的方法,而采用了事件驅動的方法,即玩家的鍵盤或觸摸筆觸發游戲的下一個動作。事件驅動大大減少了不必要的工作量,只有玩家發出消息時,計算機才啟動運算,而在玩家思考期間,計算機不做任何運算和重繪操作。4.2.3 游戲的類設計
五子棋游戲屬于二維棋類游戲,因此可以定義一個 Chesses 類來表示棋子,用一個 Chess 類型的二維數組來包含棋盤上的所有棋子,對于該棋子玩家的區分使用Chesses 的 boolean 型的變量 is Player1 來區分。可以考慮直接生成數組的每一個對象而不是在數組建立后,而是把每一個棋子對象(Chesses)放在游戲的進行中生成,這主要是考慮到移動設備的資源有限,盡可能減少系統資源占用。這樣在游戲進行時,可以避免還沒有下的棋子在一開始就占用了系統內存,玩家每下一步棋,在數組相應位置生成該棋子的對象。
對于游戲中的每一類的設計,首先就是一個 MIDlet 類,Gobang 類繼承自MIDlet 類,通過方法 start App,pause App,destroy App 來通知游戲的開始,暫停和銷毀結束,用于連接設備的應用程序管理器(Application Manager)。
本游戲共由7個類組成,它們各自的功能如下:
(1)Gobang MIDlet類
負責程序的啟動和屏幕之間的切換;
(2)Gobang Canvas 類
玩家的對戰平臺,他繼承于 Canvas 類;(3)Setting 類
用于創建游戲的各項設置參數表單;
(4)Gobang Logic 類
游戲的邏輯類,負責勝負判斷和計算機落子;
(5)Dot 類
棋子類,包含了棋子的位置信息;(6)Help 類
游戲的幫助類,包含五子棋的一些常識信息和五子棋教學內容;(7)About類
游戲的關于類,包含游戲的版本、版權等信息。各個類之間的關系如圖4-3所示:
圖4-3游戲類設計
4.2.4 游戲的流程設計
對于棋盤界面的更新,游戲進行繪制棋子時是按照棋子的二維數組來完成的,玩家下棋后,設置is Player1 值,程序修改數組相應位置,然后重新繪制(repaint)。為了使游戲的操作盡可能的簡便,本文設計上不在游戲進入時設計菜
單,玩家可以直接開始對戰,而是在開始游戲的過程中設置重新開始和退出的按鈕。即一鍵開始,運行即玩,重來或退出都使用一鍵操作。游戲流程的設計依據主要是游戲的界面設計和游戲的類的設計。游戲啟動時,Gobang MIDlet 對象先顯示游戲的主屏幕,在屏幕下方一側是出軟鍵(軟鍵指描述抽象客戶端設備如何顯示),另一側是用軟件構成的菜單,菜單元素主要有“開局”、“游戲設置”、“游戲幫助”、“關于”選項。當玩家選擇“游戲設置”軟鍵時,則顯示游戲參數設置表單;當玩家選擇“開局”軟鍵時,則顯示游戲對戰主界面;當玩家選擇“游戲幫助”軟鍵時,則顯示游戲幫助表單;當玩家選擇“關于”軟鍵時,則顯示游戲關于表單。玩家進入游戲參數設置表單,當玩家按下“確定”軟鍵時,則確認當前游戲參數,返回游戲主屏幕;當玩家按下“取消”軟鍵時,則放棄此次對游戲的修改,直接返回游戲主屏幕。玩家進入游戲對戰畫布,對戰中畫布有兩個軟鍵,當玩家按下“返回主菜單”軟鍵時,則退出游戲到達游戲主菜單;當玩家按下“悔棋”軟鍵時,則進行悔棋操作;當游戲結束時,“悔棋”軟鍵被換成了“重玩”軟鍵。玩家進入游戲介紹表單,當玩家按下“確定”軟鍵時,返回游戲主屏幕。4.2.5 游戲算法的設計
1、五子棋的獲勝組合
有哪些獲勝組合是在一場五子棋的游戲中計算機必須要知道的,因此,獲勝組合的總數必須要求得。在本文中我們假定當前的棋盤為15*15:
(1)每一列的獲勝組合是11,共15列,計算水平方向的獲勝組合數,所以水平方向的獲勝組合數為:11*15=165。
(2)每一行的獲勝組合是11,共15列,則可計算垂直方向的獲勝組合總數,垂直方向的獲勝組合數為:11*15=165。
(3)同理,可計算正對角線方向的獲勝組合總數,正對角線上的獲勝組合總數為11+(10+9+8+7+6+5+4+3+2+1)*2=121。
(4)計算反對角線上的獲勝組合總數。計算反對角線方向的獲勝組合總數可計算為11+(10+9+8+7+6+5+4+3+2+1)*2=121。這樣可計算得所有的獲勝組合數為:165+165+121+121=572。
2、設計獲勝棋型
通過上面的計算,一個15*15的屋子棋盤在此已經計算出了會有572中獲勝方式,因此,我們就可以利用數組建立一些常規棋型,棋型的主要作用是:
(1)判斷是否有任何一方獲勝;
(2)根據當前格局判斷最可能的落子方式。
然而在現實中,高手留給我們的經驗就是把握前奏,如“沖四”、“活三”,除了“連五”以外,這些也是同向勝利的捷徑。
3、攻擊與防守
獲勝棋型的算法是中性的,不區分計算機和玩家,這就涉及到攻擊和防守何者優先的問題。而許多高手都認為五子棋的根本是“防守”,“攻擊”是靈魂。進攻是取勝的手段,是防守的延續和發展。許多經驗和研究表明,一個棋手只要掌握了全面的、基本的防守原理和技巧,就能和比自己棋力高一個等級的進攻型選手對抗,起碼能立于不敗之地。對手進過越偏激,則防守的效果越好。沒有進攻的防守就像只開花不結果,沒有實際意義,頑強的防守是反攻的前奏,沒有進攻的延續,防守也失去了價值。而這缺一不可。根據以上原理,計算機在接受最佳的攻擊位置之前,還要計算當前玩家的最佳攻擊位置。如果玩家存在最佳攻擊位置,那么計算機就將下一步的棋子擺在玩家的最佳攻擊位置上以阻止玩家的進攻,否則計算機便將棋子下在自己的最佳攻擊位置上進行攻擊。
4、用到的典型算法(1)坐標變換算法
游戲的實質其實是對所下棋子的位置進行操作和判斷,因此將己方、對方以及棋盤上空點的位置坐標存儲在相應的List中。我對所下棋子的坐標進行了處理,因為我所采用的棋盤為15*15,所以棋子橫坐標為0到14的整數,縱坐標也為0到14的整數。因此,每次在棋盤上下子之后,計算機在存儲該點的坐標時,便要對坐標進行加工。假設左上角點為firstPoint,它的實際坐標為(x1,y1),而我是將它作為(0,0)存儲的,其它的坐標,其它點都是以該點為標準進行變換的,假設棋盤上每個格子的寬度為w,某實際點為(x2,y2),變換后的坐標為(x,y),x=(x2-x1)/w,y=(y2-y1)/w。
(2)勝負判斷算法
勝負判斷的規則很簡單,就是判斷游戲雙方的棋子在同一條水平線、同一條豎線或是同一條斜線上誰先出現5個連續的棋子,誰先達到這樣的目標,誰就獲得勝利。在本設計中,是在每次下完一個子后進行判斷,看己方是否達到了勝利的標準,若勝利游戲便結束;否則,游戲繼續。
(3)人工智能算法
人工智能算法的主體思想分為以下三個步驟:
第一步:根據雙方的當前的形勢循環地假設性的分別給自己和對方下一子(在某個范圍內下子),并判斷此棋子能帶來的形勢上的變化,如能不能沖4,能不能形成我方或敵方雙3等。
第二步:根據上一步結果,組合每一步棋子所帶來的所有結果(如某一步棋子可能形成我方1個活3,1個沖4(我叫它半活4)等),包括敵方和我方的。
第三步:根據用戶給的規則對上一步結果進行排序,并選子(有進攻形、防守形規則)。
5、典型類的具體設計(1)應用程序類
Gobang 類用于連接設備的應用程序管理器(Application Manager),Gobang類繼承自 MIDlet 類,通過 Gobang 類的方法 start App,pause App,destroy App 來通知游戲的開始,暫停和銷毀結束。源代碼如下:
package com.occo.j2me.game.gobang;import javax.microedition.lcdui.Display;
import javax.microedition.midlet.MIDlet;public class Gobang extends MIDlet
//定義游戲界面的 Canvas 類 Gobang Canvas 的對象 Gobang public { Gobang Canvas gobang;Gobang(){
super();
gobang=new Gobang Canvas(this);//生成 Gobang Canvas 類的對象 gobang
} protected void start App(){
Display.get Display(this).set Current(gobang);
} protected void pause App(){
} protected void destroy App(boolean arg0){
}} //在屏幕上繪出游戲見面 gobang(2)游戲界面類
Gobang Canvas 類繼承自 Canvas,游戲的核心類是 Gobang Canvas 類,此類將完成游戲的繪圖、互動、控制、邏輯、等所有功能,此類的框架代碼如下:
Package com.occo.j2me.game.gobang;import javax.microedition.lcdui.Displayable;import javax.microedition.lcdui.Command;import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command Listener;public Gobang Canvas(Gobang gobang){
this.gobang=gobang;
}
protected void paint(Graphics g){
}
import javax.microedition.lcdui.Graphics;public class Gobang Canvas extends Canvas implements Command Listener{protected Gobang gobang;
public Gobang Canvas(){
}
}(3)棋子類
整個棋盤是一個 Chesses 類型的二維數組,棋盤上的每一個棋子都對應著一個Chesses 的對象,此類定義了一個棋子,源代碼如下:
package com.occo.j2me.game.gobang;public Chesses(){
}
public class Chesses {boolean is Player1;
public Chesses(boolean is Player1){
this.is Player1=is Player1;
}}
4.3 游戲實現
4.3.1 主類的實現
YpkWuZiQiActivity類是五子棋游戲的主類,同時也是五子棋游戲的入口,它繼承自Activity類。進入程序后,首先調用init()方法,init()方法通過調用setContentView(R.layout.welcomeview)顯示登錄該游戲的第一個界面。welcomeview.xml是一個布局文件,里面存儲了界面信息。該界面中有四個Button,分別為welButton1、welButton12、welButton3、welButton4,點擊每個Button都會觸發一個事件,其中點擊welButton1和welButton2還會給它的成員變量FIGHTINGMODE賦值,因為在人人對戰和人機對戰是寫在同一個ChessBoard類中的,所以需要通過FIGHTINGMODE的值來區分是人人對戰還是人機對戰。
點擊welButton1時,FIGHTINGMODE=1,然后會調用initTwo()方法,該方法通過調用setContentView(R.layout.chess)方法,來顯示對戰的界面。chess.xml文件存儲了對戰界面的信息。在chess.xml文件中調用了ChessBoard類,該類中主要定義了棋盤的信息,下文會對該類做具體的介紹的。在對戰界面中也有四個Button,分別是b1、b2、b3、b4。
首先來介紹一下b2,該Button的功能是返回主頁,調用init()方法就可以實現。b3的功能是重新開始,這個也只需要調用initTwo()方法。b3的功能是退出,調用了系統方法:System.exit(1)。下面重點介紹一下b1,該Button的功能是悔棋。該Button設定的點擊事件詳細內容如下:
b1.setOnClickListener(new OnClickListener(){ public void onClick(View v){ ChessBoard chess =(ChessBoard)findViewById(R.id.chess);Point temp = null;if(chess.whoRun == 1){
if(chess.firstPlayer.getMyPoints().size()>=1 &&chess.secondPlayer!=null){ temp=chess.secondPlayer.getMyPoints().get(chess.secondPlayer.getMyPoints().size()-1);
chess.secondPlayer.getMyPoints().remove(temp);chess.freePoints.add(temp);temp=chess.firstPlayer.getMyPoints().get(chess.firstPlayer.getMyPoints().size()-1);chess.firstPlayer.getMyPoints().remove(temp);chess.freePoints.add(temp);chess.freshCanvas();
}
} if(chess.whoRun == 2){ if(chess.firstPlayer.getMyPoints().size()>=1 && chess.secondPlayer!=null){ temp=chess.firstPlayer.getMyPoints().get(chess.firstPlayer.getMyPoints().size()-1);chess.firstPlayer.getMyPoints().remove(temp);chess.freePoints.add(temp);temp=chess.secondPlayer.getMyPoints().get(chess.secondPlayer.getMyPoints().size()-1);chess.secondPlayer.getMyPoints().remove(temp);chess.freePoints.add(temp);chess.freshCanvas();
} })首先獲取ChessBoard對象,該對象繼承自View,詳細的定義了棋盤信息,主要負責顯示棋盤的內容。接下來判斷一下觸發悔棋事件的是哪一個玩家,再判斷是否符合悔棋的條件,這個條件很簡單,就是棋盤上至少要有兩個棋子。之后便進行悔棋操作,分別將兩個玩家最后下的棋子取出,程序實現就是將兩個ArrayList的最后一個元素remove出來,再分別放到記錄棋盤中沒有棋子的點的}
}
集合中,最后更新一下畫布,主要是調用ChessBoard的invalidate()方法。通過以上步驟之后,呈現在我們面前的便是悔完棋的畫面了。
點擊welButton2時,FIGHTINGMODE=2,之后的步驟便會點擊welButton1是相同的了,不同的是,由于對戰模式的改變,從人人對戰變成了人機對戰。
點擊welButton
3時,通
過
initThree()
方
法
調
用setContentView(R.layout.netchess)方法實現網絡對戰。詳細的對戰實現細節將會在下文一一介紹。在這個界面中只保留了兩個Button:b2和b4。這兩個Button所實現的功能和上面的b2和b4是相同的。
最后,welButton4比較簡單。它所實現的功能為退出應用程序,調用System.exit(1)方法。4.3.2 游戲設置類的實現
游戲設置表單用來對游戲參數進行設置,包括棋盤大小、先手選擇、智能級別。表單中使用了 Gauge 和 Choice Group 兩種高級用戶界面組件。
1、棋盤尺寸選擇
標準的五子棋棋盤為 15*15,但為了滿足不同玩家的需求,這里提供了大小為10*10 到 20*20 的棋盤,用戶可以通過 Gauge 組件改變。棋盤的最小值為 10,而Gauge 組件的最小值為 0,所以當前的 Gauge 值需要角上 10 才是當前棋盤大小。創建 Gauge 組件的代碼如下:
form = new Form(“ 游戲設置”);// 創建參數設置表單并添加標簽 gauge Size = new Gauge(“棋盤規格: ” + board Size + “ X ” + board Size, true, 10, board Size-10);//棋盤規格
form.append(gauge Size);
圖4-4 棋盤尺寸的設計
在Gauge交互模式下可以為Gauge對象所在的表單對象綁定一個Item State Listener 事件監聽器,并在監聽器上捕捉 Gauge 對象的事件,當 Gauge 的值發生變化時就會觸發事件。這里將根據 Gauge 的當前值改變標簽,顯示當前的棋盤大小。其代碼如下:
public void item State Changed(Item item){
if(item == gauge Size)//當 Gauge 組件發生變化時
{
int bs = gauge Size.get Value()+ 10;//獲取當前的 Gauge 值并計算棋盤大小(加10)
gauge Size.set Label(“棋盤規格: ” + bs + “ X ” + bs);//改變 Gauge 組件的標簽
}
}
2、難度選擇
游戲的難易程度根據計算機的智能級別來控制,創建及添加選項的方法和復選框一樣,所不同的是在創建 Choice Group 對象時,類型設置為 1(單選)。對于單選框,set Selected Index 只能用來指定某個選項被選中,因此,布爾值 selected 的值必然為 true,否則便沒有意義。
游戲共有 3 個難度級別,分別是:拜師學藝、棋行天下、誰與爭鋒(此游戲中并未作出區分),初始情況下為拜師學藝,該選項的索引值為 0。創建難度選擇單選框的代碼如下:
level = 1;//默認情況下的難度級別
choicelevel = new Choice Group(“電腦智能級別:”, 1);//創建難度級別選項組 choicelevel.append(“拜師學藝”, null);//難度 1 choicelevel.append(“棋行天下”, null);//難度 2 choicelevel.append(“誰與爭鋒”, null);//難度 3
choicelevel.set Selected Index(level-1 , true);//設置默認情況為難度 1,索引值為0
form.append(choicelevel);//將選項組添加到主表單中
游戲設置選項表單還有兩個 Command 對象,分別用于玩家卻熱和取消,所以表單需要監聽軟鍵事件和組件事件:
public class Setting implements Command Listener, Item State Listener
3、棋手選擇
選擇先手和難度等級用 Choice Group 組件來實現。Choice Group 組件用來構造選擇框,其構造函數如下:
Choice Group(String label, int choice Type)選擇先手的選項框為選擇組件,屬性為復選框,標簽名為空。創建好選擇組件后,逐條添加選項元素。添加選項的方法如下:
int append(String string Part, Image image Part)該方法追加一個選項元素到選擇組中,追加的選項為選擇組中的最后一個元素,選擇組的大小加 1。
對于多選類型的 Choice Group,還可以設置個別選項的選擇狀態。設置初始選擇狀態的方法如下:
void set Selected Index(int element Num, Boolean selected)這里創建一個只有一個選項元素的多選框用于玩家設置是否計算機先行,在默認情況下為true,創建完成多選框后將其添加到主表單中,代碼如下:
Computer First = true;//在默認情況下為計算機先行 choice First = new Choice Group(null, 2);//創建復選框 choice First.append(“電腦先手”, null);//添加選項元素
choice First.set Selected Index(0, Computer First);//設置多選框的默認狀態 form.append(choice First);//將多選框添加到主表單中 4.3.3 棋子類的實現
1、棋子的行列位置
此五子棋游戲是一個二維棋類游戲,所以定了了一個 Dot 類來表示棋子。由于移動設備的局限性,所以程序不在下每一步棋時生成一個對象,而是在游戲進行時,玩家或者計算機沒下一步棋,在數組相應位置生成該棋子的對象,而將已經下過的棋子保存到數組中隨時檢索,這樣可以避免過多棋子對象占用系統內存。Dot 類的 UML 圖如圖 4-5 所示:
圖4-5棋子行列設計
Dot 類主要有兩個變量 row 和 col,分別表示行和列:
public int row;//行
public int col;//列
2、檢查越位
棋子的位置并非是任意的,玩家和計算機每走一步棋之前都要線檢查該位置的合法性,即棋子是否在棋盤上,否則判為無效落子。檢查是否越界的代碼如下:
public boolean is In Board(int board Size)//判斷棋子是否越界(超出棋盤){ return row >= 0 && row < board Size && col >= 0 && col < board Size;}
3、修改棋子位置
在創建好 Dot 對象后,Dot 類提供了兩種方法更改棋子位置,包括設置行列位置和從已有棋子中復制參數。
public void set Row Col(int r, int c)//設置棋子位置
{
row = r;col = c;
}
public void copy From(Dot d)//復制已有的棋子
{
row = d.row;
col = d.col;
} 4.3.4 對戰邏輯類的實現
1、建立數據結構
本程序以數組保存當前盤面的情況,每個位置可能有三種狀態:空、玩家的落子、計算機的落子,分別用 0、1、2 來表示。代碼如下:
public static int PLAYER_NONE = 0;//該位置為空
public static int PLAYER_COMPUTER = 1;//該位置有電腦的落子
public static int PLAYER_HUMAN = 2;//該位置有玩家的落子
棋盤在初始情況下為空,即棋子上沒有任何棋子,在Gobang Logic類的構造函數中對棋盤進行初始化:
table = new int[board Size][board Size];//創建棋盤數組 for(int r = 0;r < board Size;r++){
for(int c = 0;c < board Size;c++)
table[r][c] = 0;//初始化盤面為空 }
除了記錄棋盤上每個位置的落子狀態外,程序還將對每種狀態的位置個數進行統計,以對算法進行簡化。對三種狀態的統計存儲在整型數組中,該數組為全局變量。
private int player Counter[];
在 Gobang Logic 類的構造函數中對三種狀態的計數進行初始化,即棋盤上都是空、計算機的落子或玩家的落子狀態的個數為 0,在數據結構上,把空也當做某一特殊玩家。
初始化代碼如下:
player Counter = new int[3];//落子狀態計數器
player Counter[0] = board Size * board Size;//整個棋盤都是空的狀態 player Counter[1] = 0;//電腦落子0 player Counter[2] = 0;//玩家落子0
2、落子和悔棋
這里使用了一個 Dot 類棋子對象來記錄最后一步棋的位置,當玩家下了一步棋后需要將上一步重新繪制,以消除旗子上的引導框。另外,還是用了堆棧來存儲最近的幾步落子,以便玩家悔棋。
private Dot last Dot;//棋子對象,存儲最后一步落子 private Stack steps;//棋子對象的堆棧
最后一步棋子和棋子堆棧在 Gobang Logic 類的構造函數中進行初始化;
last Dot = new Dot(board Size);//創建棋子對象用來存儲最后一步棋,初始化
位置為棋盤中央steps = new Stack();//堆棧對象,用來存儲最近的幾部棋在棋盤上落子的代碼如下:
private void go At(int row, int col, int player)//電腦或人在 row、col 位置上走
{
int last Row = last Dot.row;//記錄上一步的行坐標
int last Col = last Dot.col;//記錄上一步的列坐標
table[row][col] = player;//當前位置填充玩家代碼
last Dot.set Row Col(row, col);//將這一部設置為“最后一步”
game Canvas.repaint At(last Row, last Col);//重新繪制上一步(將引導框去掉)
game Canvas.repaint At(row, col);//繪制當前這步
switch(player)//統計雙方落子數量
{
case 1:
player Counter[1]++;//電腦的步數
break;
case 2:
player Counter[2]++;//玩家的步數
break;
}
player Counter[0]--;//空白的個數
if(steps.size()> 10)//堆棧數量超過上限(10)
steps.remove Element At(0);//清除棧底
steps.push(new Dot(row, col));//將當前這步棋子壓入堆棧
}
Stack(堆棧類)從 Vector 集成而來,它使用 push()方法進入堆棧,需要時使用 pop()方法從堆棧的頂部將其取出。悔棋動作由玩家做出,從數據結構來看,是同時后退兩步(將最后兩步棋位置的落子狀態設置為空)。
Stack 類的 peek()方法將獲取棧頂對象,但不移。悔棋代碼如下: :
public boolean undo()//悔棋
{
if(steps.size()>= 3)
{
Dot d = new Dot();//創建棋子對象
d.copy From((Dot)steps.pop());//從堆棧彈出的棋子中復制行列位置坐標
table[d.row][d.col] = 0;//將該位置設置為空
game Canvas.repaint At(d.row, d.col);//在棋盤上重新繪制該位置
d.copy From((Dot)steps.pop());//從堆棧彈出的棋子中復制行列位置坐標
table[d.row][d.col] = 0;//將該位置設置為空
game Canvas.repaint At(d.row, d.col);//在棋盤上重新繪制該位置
d.copy From((Dot)steps.peek());//獲取棧頂對象,作為最后一步棋存儲 last Dot.copy From(d);
game Canvas.repaint At(d.row, d.col);//重新繪制最后一步(添加引導框)return true;//悔棋成功
}
else
{
return false;
//悔棋失敗
}
} 4.4 本章小結
本章主要內容是游戲的實現,包括主類的實現,如構造函數、事件處理等,游戲幫助和介紹表單類的實現,游戲設置類的實現,如棋盤、選手、難度等,旗子類的實現,如棋子行列位置、檢查越界等,對戰邏輯類的實現,如落子和悔棋、邏輯運算等的實現。
第四篇:java五子棋游戲_控制臺_總結報告
總結
一、目的:
1、完成瘋狂java講義第四章作業
2、提升代碼能力
3、熟悉java語言
二、環境:
Windows8.1系統、jdk1.8、記事本(需要把文件擴展名改成java)
三、遇到的問題:
1、錯誤需要為class、interface或enum的問題
這個問題,經調試發現是因為注釋的時候使用了嵌套注釋,即在跨行注釋/* */里面添加了跨行注釋
2、如何提取控制臺輸入的問題
這個問題,根據書上例子,采用bufferedreader解決,具體可以參見api文檔.3、斜方向棋子的檢測問題
這個問題,解決它所需要的算法,著實讓我頭疼了一下.因為我是以棋盤左邊第一列為基準進行斜上方和斜下方的檢測,以及以棋盤最后一列為基準進行斜上方和斜下方的檢測.第一列的檢測會好做很多,因為只需要兩層嵌套for循環的i和j相加或相減就可以實現斜方向的遞進.而以最后一列的,則需要讓兩層嵌套for循環i和j的初始值設定為棋盤大小,然后遞減.這就導致無法直接用i和j相加或相減來實現遞進.我的解決辦法是引入額外的變量reduce(具體詳見源碼),從0開始遞增,這樣就可以用i和reduce的相加或相減來實現遞進.四、所做的內容: 和大多數五子棋游戲代碼一樣,我也是采用一個二維數組board來作為棋盤.同時采用一個全局變量boardsize來指定這個二維數組的大小,類似于這樣:board[boardsize][boardsize].然后使用水平、豎直、斜方向來檢測游戲是否出現結果。
有棋盤初始化函數,對二維數組board[][]進行賦值.有棋盤打印函數實現棋盤的顯示.一個棋子輸入函數.一個勝負檢測函數.一個信息輸出函數.然后在main函數里面采用while循環實現游戲的流程.列舉幾個很有用的變量:
Board[][];//字符串型,作為棋盤的二維數組,是全局變量
Boardsize;//int型,控制棋盤大小,是全局變量
E_o_t;//布爾變量,用來判斷main函數中的while循環是否結束.即實現游戲是否結束功能.W_steps,B_steps;//int型,用來記錄白棋,黑棋連在一起的棋子的個數,它們中的任何一個值達到5,則代表相應的棋手贏了.Reduce;//int型,在勝負檢測函數中斜方向的檢測用到,前面用介紹.控制臺用到的命令:
Javac;//用來編譯記事本寫的程序.Java;//用來執行編譯過的程序
五、總結:
這次的作業,感覺對自己的代碼能力有一定的提升,同時,對java編程有了更深的認識, 同時了解到在java編程中,幾乎所有的全局變量和方法函數,需要被定義成static.也認識到java提供的一些方法函數功能十分強大,例如bufferedreader.六、源碼:
importjava.io.InputStreamReader;importjava.io.BufferedReader;public class test2{ private static String[][] board;private static intboard_size=16;
private static boolean PLAYER=true;//棋手,默認白棋先下.false代表黑棋,true代表白棋 private static booleane_o_n=true;//作為循環(游戲)是否結束的依據,意思為end or not.public static void board_init(){ board=new String[board_size][board_size];for(inti=0;i for(int j=0;j board[i][j]=“+”; } } } public static void board_print(){ for(inti=0;i if(i==0){ for(intbou=0;bou if(bou==0) System.out.print(bou+“-------”); else if(bou>=1&&bou<=9) System.out.print(“0”+bou+“-”); else System.out.print(bou+“-”); } System.out.print(“n”); } for(int j=0;j if(j==0){ System.out.print(i+1+“t”+board[i][j]); } else System.out.print(“-”+board[i][j]); } } System.out.print(“n”);} for(intbou=0;bou if(bou==0) System.out.print(“--------”); else if(bou>=1&&bou<=9) System.out.print(“0”+bou+“-”); else System.out.print(bou+“-”); } System.out.print(“n”); //實現棋子輸入并調換棋手 public static void qizi_input(inta,int b){ int x=a-1; int y=b-1; if(x>=0&&y if(true==PLAYER){ board[x][y]=“●”; PLAYER=false; } else{ } } else board[x][y]=“○”;PLAYER=true; System.out.println(“【棋子必須落在棋盤上且該位置沒有已下的棋子!】”); } public static void WINNERis(){ //實現判斷勝負方法并輸出輸贏信息 intB_steps=0;intW_steps=0;for(inti=0;i for(int j=0;j if(board[i][j]==“●”){ W_steps++; } else{ W_steps=0;} if(board[i][j]==“○”){ B_steps++;} else{ B_steps=0;} if(5==W_steps){ System.out.print(“【白棋贏了O(∩_∩)O!黑棋輸了~(╯﹏╰)~】”);e_o_n=false;break;} if(5==B_steps){ System.out.print(“【黑棋贏了O(∩_∩)O!白棋輸了~(╯﹏╰)~】”); e_o_n=false; break; } } W_steps=0;B_steps=0; } for(int j=0;j for(inti=0;i if(board[i][j]==“●”){ W_steps++;} else{ W_steps=0;} if(board[i][j]==“○”){ B_steps++;} else{ B_steps=0;} if(5==W_steps){ System.out.print(“【白棋贏了O(∩_∩)O!黑棋輸了~(╯﹏╰)~】”);e_o_n=false;break;} “); ”); if(5==B_steps){ System.out.print(“【黑棋贏了O(∩_∩)O!白棋輸了~(╯﹏╰)~】”); e_o_n=false; break; } } W_steps=0;B_steps=0; } for(inti=0;i for(int j=0;j if(i+j if(board[i+j][j]==“●”){ W_steps++;} else{ W_steps=0;} if(board[i+j][j]==“○”){ B_steps++;} else{ B_steps=0;} if(5==W_steps){ System.out.print(“【白棋贏了O(∩_∩)O!黑棋輸了~(╯﹏╰)~】 e_o_n=false;break;} if(5==B_steps){ System.out.print(”【黑棋贏了O(∩_∩)O!白棋輸了~(╯﹏╰)~】 e_o_n=false; break; } } else continue;} for(int j=0;j if(board[i-j][j]==“●”){ “); ”); W_steps++;} else{ W_steps=0;} if(board[i-j][j]==“○”){ B_steps++;} else{ B_steps=0;} if(5==W_steps){ System.out.print(“【白棋贏了O(∩_∩)O!黑棋輸了~(╯﹏╰)~】 e_o_n=false;break;} if(5==B_steps){ System.out.print(”【黑棋贏了O(∩_∩)O!白棋輸了~(╯﹏╰)~】 e_o_n=false; break; } } else continue;} W_steps=0;B_steps=0; } for(inti=board_size-2;i>0;i--){ //實現最右列的斜方向的判斷 int reduce=0;for(int j=board_size-1;j>0;j--){ if(i-reduce>0){ if(board[i-reduce][j]==“●”){ W_steps++;} else{ W_steps=0;} if(board[i-reduce][j]==“○”){ B_steps++;} “); ”); “); ”); else{ B_steps=0;} if(5==W_steps){ System.out.print(“【白棋贏了O(∩_∩)O!黑棋輸了~(╯﹏╰)~】 e_o_n=false;break;} if(5==B_steps){ System.out.print(”【黑棋贏了O(∩_∩)O!白棋輸了~(╯﹏╰)~】 e_o_n=false; break; } reduce++;} else continue;} reduce=0;for(int j=board_size-1;j>0;j--){ if(board_size>i+reduce){ if(board[i+reduce][j]==“●”){ W_steps++; } else{ W_steps=0; } if(board[i+reduce][j]==“○”){ B_steps++; } else{ B_steps=0; } if(5==W_steps){ System.out.print(“【白棋贏了O(∩_∩)O!黑棋輸了~(╯﹏╰)~】 e_o_n=false;break;} if(5==B_steps){ System.out.print(”【黑棋贏了O(∩_∩)O!白棋輸了~(╯﹏╰)~】 e_o_n=false; break; } reduce++; } else continue; } W_steps=0; B_steps=0; } } public static void INFO_SHOW(){ //顯示棋盤及必要信息:落子方重新開始退出游戲 System.out.println(“【輸入格式為:‘1,1’或者‘88,99’】”); if(true==PLAYER) System.out.print(“【想重新開始嗎?請輸入暗號88,88】【想退出游戲嗎?請輸入暗號66,66】n【現在落子方是白棋:”); else System.out.print(“【想重新開始嗎?請輸入暗號88,88】【想退出游戲嗎?請輸入暗號66,66】n【現在落子方是黑棋:”);} public static void main(String[] args)throws java.io.IOException { /** **實現整個邏輯流程的實現,** **黑白兩方的步數統計 **勝負信息輸出*/ test2 WUZIQI= new test2();//創建對象 System.out.print(“【控制臺五子棋,超高逼格版】n【默認白棋先下,你無法改變,這就是命!】n【請務必根據指示操作】n”); WUZIQI.board_init(); WUZIQI.board_print(); //實現電腦控制臺的輸入讀取 BufferedReader P_INPUT= new BufferedReader(new InputStreamReader(System.in)); String str_input= null; //循環體實現游戲框架 while(e_o_n){ INFO_SHOW(); } } str_input=P_INPUT.readLine();String[] posStrArr=str_input.split(“,”);intxPos=Integer.parseInt(posStrArr[0]);intyPos=Integer.parseInt(posStrArr[1]);if(88==xPos&&88==yPos){ WUZIQI.board_init();continue;} if(66==xPos&&66==yPos){ e_o_n=false;continue;} qizi_input(xPos,yPos);WUZIQI.board_print();WINNERis();System.out.println(“n【游戲結束,再見哦,親!】”); } 《JAVA程序設計》 實習報告 實習題目 學生姓名 學生學號 學生姓名 學生學號 學生姓名 學生學號 所在專業 所在班級 指導教師 實習時間 成績: 老師評語: 五子棋 計算機網絡技術 11/6/27—11/7/1 五子棋 下面是五子棋的部分截圖: 這里實現了服務器:數據的保存及轉發; 聯網對戰:桌位的選擇、悔棋、認輸、和棋; 聊天模塊:文本聊天、語音聊天; 練習模式:難度的劃分、悔棋。 這些功能是如何實現的呢?下面來一步步分解。服務器 1、服務器與客戶端是用socket來連接的。連接成功后,客戶端會把客戶的登陸的信息(用戶名、性別、頭像)發往服務器。服務器是通過鏈表來記錄每個用戶的信息。 class Node{ String username=null;//用戶昵稱 String tableNum=null;//桌 號及座位號,格式是:桌號:座位號 int score;//分數 Socket Socket=null;//套接字 ObjectOutputStream output=null;//輸出流 ObjectInputStream input=null;//輸入流 Node next=null;//保存鏈表中下一節點的指針 } 2、下面是服務器通過鏈表記錄的客戶對像流來轉發數據給相應的客戶端。代碼還是簡單明了的。如: if(type2.equalsIgnoreCase(“重新開局”)) { } String isResart=(String) tobody.output.writeObject(“下棋操作”);tobody.output.flush(); tobody.output.writeObject(“重新開局”);tobody.output.flush(); tobody.output.writeObject(isResart);tobody.output.flush();node.input.readObject();//System.out.println(“isResart:”+isResart); 3、由于這是一個可以有十六個玩家進來的游戲,那么怎樣確定哪個玩家與哪個玩家在同一張桌子上下棋呢?我這里用到的鏈表記錄的String tableNum=null;//桌 號及座位號,格式是:桌號:座位號。 如第一張桌第一個坐位與第二個坐位的記錄是:0:0;0:1。以此類推。1:0,1:1;2:0,2:1…… 服務器的根據桌號與坐位號來轉發數據的。用IF語句判斷。獲得對手的對像流來發送數據。 //獲取發送對象 String table=node.tableNum.substring(0, String String tableNum=null; if(Integer.parseInt(seat)==0) tobody=userInfoList.findtable(tableNum); tableNum=table+“:”+1;tableNum=table+“:”+0;else node.tableNum.indexOf(“:”));seat=node.tableNum.substring(node.tableNum.indexOf(“:”)+1); 客戶端 1、棋盤里的棋子是用一個整型二維數組來記錄的。GramP[x][y],x代表橫的格數,并是具體坐標;y代表豎的格數,并是具體坐標;x* 28、y*28就是具體坐標。0代表沒有棋子,1代表白棋,2代表黑棋。 2、判斷輸贏的方法很簡單,每下一個棋子,都要判斷一次。在當前棋子的0、45、90、135度方向上判斷是否有五個同樣的棋子相連。這里用到了y=kx+b函數來計算。要分開黑棋與白棋的判斷,定義一個入口參數,增加代碼的復用性,輸與贏會用到重畫方法,所以也定義了Graphics g入口參數。代碼如下: public void isWin(int chessID,Graphics g) { //橫向判斷 for(int k=0;k<19;k++){ } whiteScore=0; //豎向判斷 for(int h=0;h<19;h++){ if(GramP[x][h]==chessID){ { } whiteScore=0;++whiteScore;}else if(GramP[k][y]==chessID){ }else { } //如果大于五子連珠,就為贏 if(whiteScore>=5){ } win_tip(chessID,g);break;whiteScore=0;++whiteScore; } if(whiteScore>=5){ } win_tip(chessID,g);break;whiteScore=0;//135向判斷 int b1;b1=y-x;if(b1>=0){ { for(int a=-b1,b=0;a<19;a++,b++){ if(GramP[a][b]==chessID){ { ++whiteScore;for(int a=0,b=b1;b<19;a++,b++){ } whiteScore=0; if(GramP[a][b]==chessID){ { } if(whiteScore>=5){ } win_tip(chessID,g);break;whiteScore=0;++whiteScore; }else }else }else } } } if(whiteScore>=5){ } win_tip(chessID,g);break;whiteScore=0;whiteScore=0;//45向判斷 int b2;b2=x+y;if(b2<=18){ { for(int c=18,d=b2-18;d<19;c--,d++){ if(GramP[c][d]==chessID){ ++whiteScore;for(int c=b2,d=0;c>=0;c--,d++){ } whiteScore=0;if(GramP[c][d]==chessID){ }else { } if(whiteScore>=5){ } win_tip(chessID,g);break; whiteScore=0;++whiteScore;}else } } } }else { } if(whiteScore>=5){ } win_tip(chessID,g);break; whiteScore=0;whiteScore=0;//平局 int count=0;for(int i=0;i<19;i++){ } if(count==180){ } win_tip(3,g);for(int j=0;j<19;j++){ } if(GramP[i][j]==chessID){ } count++; 3、悔棋分為悔一步還是悔兩步。由一個布爾變量來判斷,如果下完棋再悔棋,只悔一個棋。如果沒下棋,就悔兩個棋。由一維的字符串數組ReGame[]來記錄下棋的先后順序。格式中: ReGame[R++]=x+“:”+y;下面是悔兩個棋子的代碼。 public void regretGrame2() for(int i=0;i<361;i++){ if(ReGame[i]==null){ } } { } //System.out.println(ReGame[i-1]);//System.out.println(ReGame[i-2]);String X1=ReGame[i-1].substring(0, String String X2=ReGame[i-2].substring(0, String GramP[Integer.parseInt(X1)][Integer.parseInt(Y1)]=0;GramP[Integer.parseInt(X2)][Integer.parseInt(Y2)]=0;ReGame[i-1]=null;ReGame[i-2]=null;R-=2;break;ReGame[i-1].indexOf(“:”));Y1=ReGame[i-1].substring(ReGame[i-1].indexOf(“:”)+1);ReGame[i-2].indexOf(“:”));Y2=ReGame[i-2].substring(ReGame[i-2].indexOf(“:”)+1);repaint();悔一個棋子的,類似。 這只是悔棋函數,只能應用于本用戶進行悔棋操,與電腦下棋的悔棋,就直接調用這個函數即可。 但是在聯網模式中,通過對像流向服務器發送悔棋標識,再由服務器轉發給對手,如果對手同意的吧,對手就會調用悔棋函數,進行自身棋盤的悔棋,同時會向服務器返回一個yes1或yes2標識,發起方收到了,也會調用悔棋函數進行悔棋操作。如果對方不同意,則會返回一個no標識,發起方只會提示玩家,而不進行悔棋操作。 認輸及和棋的步驟類似,不再累述。下面是悔棋操作的部分主要代碼: 發起請求悔棋: //請求悔棋 public void isRegretGrame(){ if(R>=2&&!isEnd)//只有兩個棋子以上才可以悔棋,否則數組會越界.分勝負時也不能悔棋 { { if(flag)//下棋前,悔棋 { try { } oos.writeObject(“下棋操作”);oos.flush();oos.writeObject(“悔棋”);oos.flush();oos.writeObject(“isRegret2”);oos.flush(); e.printStackTrace();} catch(IOException e){ }else //下棋后,悔棋 { } try { } oos.writeObject(“下棋操作”);oos.flush();oos.writeObject(“悔棋”);oos.flush();oos.writeObject(“isRegret1”);oos.flush();e.printStackTrace();} catch(IOException e){ }else JOptionPane.showMessageDialog(this, “不能執行悔棋操作”, “警告”, JOptionPane.WARNING_MESSAGE);} } 服務器轉發悔棋請求: 這只是服務轉發的悔棋部分的數據。 String type=(String)node.input.readObject();//讀取信息類型 { if(type2.equalsIgnoreCase(“悔棋”)) { String isRegret=(String)if(type.equalsIgnoreCase(“下棋操作”))node.input.readObject(); } } tobody.output.writeObject(“下棋操作”);tobody.output.flush(); tobody.output.writeObject(“悔棋”);tobody.output.flush(); tobody.output.writeObject(isRegret);tobody.output.flush();收接悔棋請求:下面代碼是在客戶端收接數據的線程里的。 String type=(String)ois.readObject();if(type.equalsIgnoreCase(“下棋操作”)){ if(type2.equalsIgnoreCase(“悔棋”)) {){ JOptionPane.showMessageDialog(this, “對方不同意悔棋 String isRegret=(String)ois.readObject();if(”yes2“.equalsIgnoreCase(isRegret)){ } else if(”yes1“.equalsIgnoreCase(isRegret)){ regretGrame1(); regretGrame2(); }else if(”no1“.equalsIgnoreCase(isRegret)||”no2“.equalsIgnoreCase(isRegret)”, “提示”,JOptionPane.WARNING_MESSAGE); } else if(“isRegret2”.equalsIgnoreCase(isRegret)){ int result = JOptionPane.showConfirmDialog(this, “對方請求悔棋,是否同意?”, “提示”, JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE); if(result == JOptionPane.YES_OPTION){ oos.writeObject(“下棋操作”);oos.flush(); oos.writeObject(“悔棋”); } oos.flush(); oos.writeObject(“yes2”);oos.flush();regretGrame2(); }else if(result==JOptionPane.NO_OPTION){ //System.out.println(“對方不同意悔棋”); oos.writeObject(“下棋操作”);oos.flush(); oos.writeObject(“悔棋”);oos.flush(); oos.writeObject(“no2”);oos.flush();} else if(“isRegret1”.equalsIgnoreCase(isRegret)){ int result = JOptionPane.showConfirmDialog(this, “對方請求悔棋,是否同意?”, “提示”, JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE); } if(result == JOptionPane.YES_OPTION){ oos.writeObject(“下棋操作”);oos.flush(); oos.writeObject(“悔棋”);oos.flush(); oos.writeObject(“yes1”);oos.flush(); regretGrame1(); } 聊天模塊 1、文字聊天,也是通過服務器轉發數據的,客戶端就接收與顯示。在這里不再詳說了。 2、重點是語音聊天,這里的語音連接,首先通過服務器轉發發起方的語音標識,對方收到后,如果選擇“是”,那它就會通過服務器轉發IP地址給發起方,并同時起動serversocket監聽。發起方收到對方同意語音連接的標識與IP地址后,就可以與對方連接了,語音鏈路就建起了。斷開的思路也是差不多的。練習模式 1、電腦下棋的算法: 通過遍歷棋盤,計算權值,哪個位置的權值最高,就在哪個位置下棋。權值的大小預定為: //黑白白空 50 //空白白空 100 //黑白白白空 500 //空白白白空 1000 //黑白白白白空 5000 //空白白白白空 10000 //白白白白白 100000 首先假定下棋點,再計算權值之和的大小。 權值之和=0度方向的帶勝權值和堵敵的權值之和+45度方向的帶勝權值和堵敵的權值之和+90度方向的帶勝權值和堵敵的權值之和+135度方向的帶勝權值和堵敵的權值之和.下面代碼,假定落子點,再把四個方向上的的權值加起來。 //記錄當前假定的落子點 private int getQuan(int i,int j) { } //水平權值 private int getQuan0(int i, int j){ int samechessNumS=0;//相同棋子的個數 int samechessNumF=0;int blankNumS=0;// 空子的個數 int blankNumF=0;int q=0;//求當前位置的權值 q+=getQuan0(i,j);//得到水平方向上的權值,下面類似 q+=getQuan90(i,j);q+=getQuan135(i,j);q+=getQuan45(i,j); return q; 下面是只是求水平權值的代碼,通過一個二維二元數組來左右求索棋子的個數。 } int q=0,qS=0,qF=0;int [][]ij0=new int[2][2];//計算權值用的 ij0[0][0]=ij0[0][1]=i;ij0[1][0]=ij0[1][1]=j;samechessNumS=getsamechessNum0(ij0,back);//得到黑子數目 if(ij0[0][0]>=0) //得到速勝權值 ij0[0][0]=ij0[0][1]=i;ij0[1][0]=ij0[1][1]=j;samechessNumF=getsamechessNum0(ij0,white);//得到白子數目 if(ij0[0][0]>=0) if(curchess[ij0[0][0]][ij0[1][0]]==Chess)blankNumF++;if(curchess[ij0[0][0]][ij0[1][0]]==Chess)blankNumS++;if(ij0[0][1]<19)if(curchess[ij0[0][1]][ij0[1][1]]==Chess)blankNumS++;qS=getQuanpart(samechessNumS,blankNumS);if(ij0[0][1]<19)if(curchess[ij0[0][1]][ij0[1][1]]==Chess)blankNumF++;qF=getQuanpart(samechessNumF,blankNumF);//得到堵敵權值 q=qS+qF;return q;//得到水平方向的同子數目 private int getsamechessNum0(int[][] qij, int chessID){ int num=1;//存儲相同棋子數目,當前點滿足條件 qij[0][0]--;//向左探索我們只探索臨近的4個點,注意不要出邊界 while(qij[0][0]>=0&&num<5){ } qij[0][1]++;//向右求索 while(qij[0][1]<19&&num<5)if(curchess[qij[0][0]][qij[1][0]]!=chessID)break;num++;qij[0][0]--; } { } return num;if(curchess[qij[0][1]][qij[1][1]]!=chessID)break;num++;qij[0][1]++;//求得某一方向上的一半權值 private int getQuanpart(int sameChessNum, int blankNum){ } if(sameChessNum==2&&blankNum==1)return q2o;else if(sameChessNum==2&&blankNum==2)return q2;else if(sameChessNum==3&&blankNum==1)return q3o;else if(sameChessNum==3&&blankNum==2)return q3;else if(sameChessNum==4&&blankNum==1)return q4o;else if(sameChessNum==4&&blankNum==2)return q4;else if(sameChessNum==5)return q5;else return 0; 2、劃分難度等級 我這里,是通過改變它的預定權值的大小,而達到改變難度的。 3、悔棋,比對戰模式(即聯網對戰)的悔棋還簡單。只需用到悔兩個棋子的悔棋函數即可。第五篇:五子棋實習報告