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