1. 程式人生 > >五子棋遊戲製作的詳細思路及原理

五子棋遊戲製作的詳細思路及原理

五子棋設計思路文件

一、程式設計原理、目的以及演算法

運用java swing和awt框架實現五子棋的繪圖,按鈕的事件響應等功能。主要分為三個類:主要UI類、棋子類、以及棋盤類。在原有的五子棋的基礎上增加了四子棋和六子棋的擴充套件玩法,對於六子棋來說,玩家需要每人一次下兩顆棋子,四子棋和五子棋的判定依據相同,增加娛樂性。

在演算法方面主要有兩個難點,第一,需要將棋譜的繪製座標轉化為基本的資料結構,例如棋子和網格交點的座標均採用鄰接矩陣的表示方式來儲存。第二,五子棋的判定輸贏的演算法,即,橫向掃描,豎向掃描,斜向掃描,其中,斜向掃描最為困難,需要將棋盤分為兩個部分依次進行。具體的偽碼描述如下:

           輸贏判斷偽碼描述:

                     for everychesses{

                                chessesare not null && chesses have played;                               

                                count++;

                                ifcount is 5, winner

}

                                棋子座標轉化為鄰接矩陣的偽碼描述:

                                          forevery chesses{

chess[][].X ← X

                                                     chess[][].y ← Y

                                          }

二、         程式的流程框圖,以及UML圖

主要UI的邏輯框圖


後端演算法實現的主要框圖


這個設計採用了單一職責原則,將前端與後端的業務邏輯進行了分離,降低整個程式的耦合度,我們可以在以上的UML圖中看到這個彼此的依賴關係。

三、演算法的重難點

整個五子棋遊戲在開發過程中遇到最為困難的是搭建基本資料結構的演算法,判定輸贏的演算法,使用者點選非網格處時,棋子自動修正至正確的位置上,涉及到對矩陣座標的轉換,以及對矩陣的遍歷,尤其是矩陣的斜向遍歷,以下就會通過原始碼分析的方式來進行解讀。

1、 關於座標轉換矩陣的演算法

我們知道,五子棋的棋盤是由若干的直線通過交錯來進行繪製的,那麼,每條直線的交點座標之間應該具有一定的規律,這個交點的座標可以用矩陣來儲存,那麼我們就能定義一個五子棋棋譜的行數、列數和行列之間的間隔差。

publicstaticfinalintMARGIN = 30; // 邊距

publicstaticfinalintGRID_SPAN = 35; // 網路距離

publicstaticfinalintROW = 15;     // 行數

publicstaticfinalintCOW = 15;     // 列數

這我們能看到,我們定義了行數和列數,並且網路(格)距離我們也定義了,網路距離的數值是相對於容器的座標,邊距就是我們所謂的容器邊緣的距離。

畫出棋譜

//畫出棋盤的橫向線條

for(inti = 0 ;i <= ROW ;i++) {

g.drawLine(MARGIN,MARGIN +i * GRID_SPAN,MARGIN +COW *GRID_SPAN,MARGIN +i * GRID_SPAN);

             }

//畫出棋盤的縱向線條

for(inti = 0;i <= COW ;i++) {

g.drawLine(MARGIN +i * GRID_SPAN,MARGIN,MARGIN +i * GRID_SPAN,MARGIN +ROW *GRID_SPAN);

        }


這裡我們進行了兩次遍歷分別畫橫向線和縱向線,drawLine中的前兩個引數表示起始位置的座標,後面兩個引數表示終止位置的座標,那麼起始位置應該是一個間隔進行數的i倍,因此可以進行遍歷畫圖,同時每個網格交點的座標可以儲存到棋子物件中。

2、使用者點選非網格位置,棋子自動修正落子點的演算法

//通過滑鼠的座標換算成索引下標

xIndex = (e.getX() -MARGIN +GRID_SPAN/2)/GRID_SPAN ;

yIndex = (e.getY() -MARGIN +GRID_SPAN/2)/GRID_SPAN ;       

drawX = (int)((e.getX() - MARGIN +GRID_SPAN/2)/GRID_SPAN)*GRID_SPAN + MARGIN ;

drawY = (int)((e.getY() -MARGIN +GRID_SPAN/2)/GRID_SPAN)*GRID_SPAN + MARGIN ;

前兩行表示的是滑鼠點選的位置轉化為五子棋棋子的下標索引,後兩行是五子棋棋子繪製的絕對座標,由於變數名全部採用的是int型別,所以很容易就能取到整數。這個演算法的核心思路是:當用戶滑鼠點選網格交點以外,但是我們可以通過計算(滑鼠座標加上半個網格長度,除以網格數量後取餘數),找到距離滑鼠點選位置最近的那個網格點,那麼就能將棋子畫在網格的交點上了。

3、判斷輸贏的演算法描述

判斷輸贏的演算法在橫向和豎向方向比較簡單,但是斜向判斷有一定難度。判斷輸贏的思路就是通過使用者每次下一步棋子,進行橫向縱向斜向掃描,累計到5顆子即可判斷輸贏。下面就是一些演算法實現:


斜向掃描判定


就用類似的思路進行遍歷即可(以下是圖解)

這部分功能的實現在現階段沒有尋找到一個更加好的演算法,因此只能重複程式碼段來進行黑白棋子的交替判斷,後續程式碼的重構過程中在加以改進。

以下貼出的原始碼有詳細註釋

package 五子棋對戰版;

import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Random;

import javax.sound.sampled.AudioInputStream;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

//主要UI類
public class mainUI extends JFrame {
	//例項化棋譜
	 chessMap Board ;
	 
	 
	JButton StartorRestart  ;  //開始和重新開始迴圈按鈕
	JButton FourPoint;			//四子琪按鈕			增加娛樂性
	JButton SixPoint;			//六子棋子按鈕			哈哈好玩
	JButton FivePoint;			//五子棋按鈕
	
	//勝利者輸出資訊
	JLabel WinerInfor ;
	JLabel Info;			//面板資訊,提示玩家現在玩的是几子棋
	JLabel Who;			//輸出那個玩家下棋
	
	//圖片載入
	ImageIcon Black = new ImageIcon("黑子.png");
	ImageIcon White = new ImageIcon("白子.png");
	ImageIcon SixPointPNG = new ImageIcon("sixBTN.png");
	ImageIcon FourPointPNG = new ImageIcon("fourBTN.png");	//匯入圖片
	ImageIcon FivePointPNG = new ImageIcon("fiveBTN.png");
	ImageIcon StartGame = new ImageIcon("StartGame.png");
	ImageIcon ReStartGame = new ImageIcon("ReStartGame.png");
	
	boolean flag = true ;			//這個標籤用來控制按鈕,當開始按鈕開啟時,其他的按鈕不能響應
	
	//建構函式
	mainUI() {
		
		
		Board = new chessMap() ;   //例項化棋盤物件
		
		//設定主視窗資訊
		setTitle("好玩五子棋遊戲");
		setBounds(100, 100, 900, 600);
		setResizable(false);
		setDefaultCloseOperation(3);
		
		//提示玩家資訊的標籤例項化
		Info = new JLabel() ;
		Info.setLocation(690,50);
		Info.setSize(140, 50);
		Info.setText("<html><body><div style='color:#fd0060;font-size:25px;font-family:華文黑體;'>五子棋</div></body></html>");
		
		WinerInfor = new JLabel();
		WinerInfor.setLocation(670, 380);
		WinerInfor.setSize(130, 50);
		
		Black.setImage(Black.getImage().getScaledInstance(50, 50, Image.SCALE_DEFAULT));
		White.setImage(White.getImage().getScaledInstance(50, 50, Image.SCALE_DEFAULT));
		
		Who = new JLabel();
		Who.setLocation(710, 450);
		Who.setSize(50,50);
		

		//例項化按鈕物件
		//開始重開按鈕
		StartorRestart = new JButton();
		StartGame.setImage(StartGame.getImage().getScaledInstance(130, 50, Image.SCALE_DEFAULT));
		ReStartGame.setImage(ReStartGame.getImage().getScaledInstance(130, 50, Image.SCALE_DEFAULT));
		StartorRestart.setIcon(StartGame);
		StartorRestart.setBorderPainted(false);
		StartorRestart.setBorder(null);
		StartorRestart.setLocation(670, 100);
		StartorRestart.setSize(130,50);
		
		//四子棋按鈕
		FourPointPNG.setImage(FourPointPNG.getImage().getScaledInstance(130, 50, Image.SCALE_DEFAULT));//設定大小
		FourPoint = new JButton();
		FourPoint.setIcon(FourPointPNG);
		FourPoint.setBorderPainted(false);	//不畫邊框		
		FourPoint.setBorder(null);			//邊框為空
		FourPoint.setLocation(670, 170);
		FourPoint.setSize(130, 50);
		
		//六子棋按鈕
		SixPoint = new JButton();
		SixPointPNG.setImage(SixPointPNG.getImage().getScaledInstance(130, 50, Image.SCALE_DEFAULT));
		SixPoint.setIcon(SixPointPNG);
		SixPoint.setBorderPainted(false);
		SixPoint.setBorder(null);
		SixPoint.setLocation(670, 240);
		SixPoint.setSize(130, 50);
		
		//五子棋按鈕
		FivePoint = new JButton();
		FivePointPNG.setImage(FivePointPNG.getImage().getScaledInstance(130, 50, Image.SCALE_DEFAULT));
		FivePoint.setIcon(FivePointPNG);
		FivePoint.setBorderPainted(false);
		FivePoint.setBorder(null);	
		FivePoint.setLocation(670, 310);
		FivePoint.setSize(130, 50);
		
		
		
		//新增事件監聽響應
		UIlistener li = new UIlistener();
		StartorRestart.addActionListener(li);
		FourPoint.addActionListener(li);
		SixPoint.addActionListener(li);
		FivePoint.addActionListener(li);
		
		//容器不知道什麼用
		Container container = getContentPane();			//容器,好像也沒什麼用,不知道有啥用
		container.add(Board);

		
		//棋盤物件的流式佈局設定為空,方便在指定位置新增按鈕
		Board.setLayout(null);
		Board.add(StartorRestart);
		Board.add(FourPoint);
		Board.add(SixPoint) ;
		Board.add(FivePoint);
		Board.add(Info);
		Board.add(WinerInfor);
		Board.add(Who);
		//棋盤新增到主視窗
		add(Board,BorderLayout.CENTER);
		
		//Board.setOpaque(true) ;		//設定透明度,然而並沒什麼卵用

		//主視窗可見
		setVisible(true);
		
		//這裡我使用多執行緒技術,接收從後端傳來的輸贏訊息,從而返回給玩家到底哪方贏了
		Thread WinnerPointer = new Thread(new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				//判斷贏家
						while(true) {
							//Who.setText(Board.whoPlay());
							if (Board.whoPlay() == "白手") {
								Who.setIcon(White);
							}
							if (Board.whoPlay() == "黑手") {
								Who.setIcon(Black);
							}					
							String aString =Board.winner()  ;
							System.out.println("test");					//好像沒有這句話執行緒啟動不了了,不知道為啥
							if (aString != null) {
								System.out.println(aString);
								WinerInfor.setText("<html><body><div style='color:#fd0000;font-size:20px;font-family:華文黑體;'>"+Board.winner()+"</div></body></html>");
							}
						}
			}
		}) ;
		WinnerPointer.start();
	}
	private class UIlistener implements ActionListener{

		@Override
		public void actionPerformed(ActionEvent e) {
			// TODO Auto-generated method stub
			Object object = e.getSource() ;
			if (object == StartorRestart) {
				
				if (StartorRestart.getIcon() == StartGame) {
					StartorRestart.setIcon(ReStartGame);
					Board.start();
					//Info.setText("五子棋");
					System.out.println("開始 遊戲按鈕響應");	
					flag = false ;
				}
				else if (StartorRestart.getIcon() == ReStartGame) {
					StartorRestart.setIcon(StartGame);
					Board.restart();
					//Info.setText("五子棋");
					System.out.println("重新 遊戲按鈕響應");
					flag = true ;
				}
			}
			if (flag) {
				if (object == FourPoint) {
					System.out.println("四子琪好玩哦!!");
					Board.fourPoint();
					Info.setText("<html><body><div style='color:#fd0060;font-size:25px;font-family:華文黑體;'>四子棋</div></body></html>");
				}
				if (object == SixPoint) {
					System.out.println("六子棋好玩");
					Board.sixPoint();
					Info.setText("<html><body><div style='color:#fd0060;font-size:25px;font-family:華文黑體;'>六子棋</div></body></html>");
				}
				if (object == FivePoint) {
					Board.fivePoint();
					Info.setText("<html><body><div style='color:#fd0060;font-size:25px;font-family:華文黑體;'>五子棋</div></body></html>");
				}
			}
		}
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		mainUI main = new mainUI();
		
	}
}
package 五子棋對戰版;
//棋子類

import java.awt.Color;
import java.awt.Image;

public class chessPoint {
	public static final int R = 15 ; //棋子半徑
	private  int x ;					//棋子的x座標
	private  int y ;					//棋子的y座標
	private Color color ;			//棋子的顏色
	//索引下標
	private int visited = -1 ; 		//表示這個棋子是否被下過,-1代表沒有下,1代表下過了
	chessPoint(){
		
	}
	chessPoint(int visited,int X,int Y){
		this.x = X;
		this.y = Y;
		this.visited = visited ;
	}
	//初始化使用
	public void setUnvisited(int Unvisited) {
		this.visited = Unvisited;
	}
	//獲取是否訪問過
	public int getVisited(){
		return visited ;
	}
	//設定顏色
	public void setColor(Color color){
		this.color = color;
	}
	//獲取棋子的顏色
	public Color getColor() {
		return color ;
	}
	
	public int getX() {
		return x;
	}
	public int getY() {
		return y;
	}
	
//	public static void main(String[] args) {
//		
//	}
	
}
package 五子棋對戰版;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.RadialGradientPaint;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.text.html.HTMLDocument.HTMLReader.BlockAction;
import 五子棋對戰版.chessPoint;

//棋盤類
public class chessMap extends JPanel implements MouseListener{

	
	//確定五子棋棋譜的大小
		public static final int MARGIN = 30; // 邊距
		public static final int GRID_SPAN = 35; // 網路距離
		public static final int ROW = 15; 	// 行數
		public static final int COW = 15; 	// 列數
		private int flag;  					//設定標籤,用來表示哪一方下棋    0表示白方,1表示黑方 
		private int drawX;					//實際要畫的座標值,這個值就是棋子在panel中的座標
		private int drawY;
		private int StepOfPlayer = 0;							//玩家的步數記錄,應用於六子棋中,記錄玩家到底是不是每次走了兩步		
		private int xIndex;										//下標索引
		private int yIndex ;
		private int countChess = 5;								//統計棋子數勝利的個數(預設是5),例如五子棋必須5顆子連,那麼這個值就是5,如果六子棋六顆連,那麼這個值就是6,以此類推
		private boolean gameover = true ;						//遊戲結束的標籤 
		
		chessPoint[][] chess = new chessPoint[16][16];			//初始化棋子,二維陣列實現x軸與y軸座標
		private String winner;				//記錄贏家
		private String blackOrwhite;  		//記錄當前在下的棋子是白還是黑,用於輸出到前端UI,告訴玩家
		
		private Image image ;									//載入圖片的類,表示載入棋譜背景
		
		
		//建構函式
		public chessMap() {
			//背景圖片載入
			try {
				image = ImageIO.read(new File("/Users/apple/Desktop/五子棋對戰版/background.jpg"));
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

			
			//初始化陣列,否則會出現空指標錯誤
			for(int i = 0 ; i<=15 ; i++) {
				for(int j = 0 ; j<=15 ; j++) {
					chess[i][j] = new chessPoint() ;
				}
			}
			
			addMouseListener(this) ;//為當前類新增滑鼠監聽
			//新增滑鼠移動的事件監聽
			addMouseMotionListener(new MouseMotionListener() {
				
				@Override
				public void mouseMoved(MouseEvent e) {
					// TODO Auto-generated method stub
					int x1 = (e.getX() - MARGIN + GRID_SPAN/2)/GRID_SPAN ;  //將滑鼠的座標轉化為網格座標      
					int y1 = (e.getY() - MARGIN + GRID_SPAN/2)/GRID_SPAN ;  
					/*這裡必須要做一個判斷:滑鼠不能一移動到棋盤外面去下棋子
					*					遊戲結束了也不能下棋
					*					已經有棋子了也不能下棋子
					*/					
					if (x1 < 0 || y1 < 0 || x1 > COW || y1 > ROW) {
						setCursor(new Cursor(Cursor.DEFAULT_CURSOR));  //在棋盤外面,游標預設形態
					}
					else {
						setCursor(new Cursor(Cursor.HAND_CURSOR));//棋盤內,游標手為形態
						//System.out.println(x1+"\t"+y1);
					}
					
				}
				
				@Override
				public void mouseDragged(MouseEvent e) {
					// TODO Auto-generated method stub
					
				}
			});
		}
		
		public void paintComponent(Graphics g) {
			super.paintComponent(g);//將這個graphics,super給它的父類
			
			g.drawImage(image, 0, -100, null);
			//畫出棋盤的橫向線條
			for(int i = 0 ; i <= ROW ; i++) {
				g.drawLine(MARGIN, MARGIN + i * GRID_SPAN, MARGIN + COW * GRID_SPAN, MARGIN + i * GRID_SPAN);
			}
			//畫出棋盤的縱向線條
			for(int i = 0; i <= COW ; i++) {
				g.drawLine(MARGIN + i * GRID_SPAN, MARGIN, MARGIN + i * GRID_SPAN, MARGIN + ROW * GRID_SPAN);
			
			}
			//重畫棋子
			for(int i = 0 ; i <= 15;i++) {
				for(int j = 0 ; j <= 15;j++) {
					if (chess[i][j] != null && chess[i][j].getVisited() == 1) {
						g.setColor(chess[i][j].getColor());
						g.fillOval(chess[i][j].getX()-7, chess[i][j].getY()-7, 14, 14);
					}
				}
			}
			if (IsWin()) {
				this.gameover = true ;
		
				return ;
			}
			System.out.println("---------------------------");
			
		}
	//判斷是否這個棋子已經下過了,如果沒有下過,則返回1,下過了返回0
	private boolean IsVisited(int i,int j) {
		return chess[i][j].getVisited() == -1 ? true:false;
	}
	
	
	//判斷輸贏
	/*			哎這個演算法實在相當複雜,腦細胞已經死亡
	 * 			思路是這樣的: 我每次進行橫、豎、撇、捺四個方向進行掃描,掃描到連子就判贏了
	 * 						這裡的程式碼重複實在無法避免了,想不出有更好的解決辦法,希望大神能指導我一下
	 * 						撇、捺的掃描是最難的,相當於一個矩陣的斜向輸出,而且要分成兩部分來進行,實在很難,完全是面向試錯的程式設計  /(ㄒoㄒ)/~~  演算法正確全靠腦補找規律
	 * 						文字實在是說不清楚,本人水平有限,還是看程式碼吧,不知道能不能看懂額    o(╯□╰)o
	 * */
	private boolean IsWin() {
		
		//黑色棋子豎向查詢
		for(int i = 0 ; i<=15;i++) {								//外層迴圈遍歷棋子陣列xIndex的X軸的座標索引	
			int count = 0;										//每次一縱列要是沒有連子,那麼就必須要將計數器清0了
			for(int j=0;j<=15;j++) {								//內層迴圈表示遍歷棋子陣列yIndex的Y軸的座標索引
				/*這裡就是進行連珠計算的邏輯演算法
				 * 必須滿足三個條件:   1、棋子陣列不能為空
				 * 				     2、棋子必須是已經下過了的。即getVisited()這個函式返回一個1值,就表示已經下過了
				 * 					3、判斷棋子顏色,這裡必須獲取到棋子的顏色才行,這樣才知道到底是哪一個棋子需要判斷連珠
				 * */			
				if (chess[i][j] !=null && chess[i][j].getVisited() == 1 && chess[i][j].getColor() == Color.black) {		
					count++;
					System.out.println(count+"黑  豎向查詢");
					if (count == countChess) {											//計數器累計到5,代表5子連在一起
						System.out.println("黑  豎向查詢勝!!!");
						winner ="黑棋勝利!";
						return true ;
					}
				}
				else {
					count = 0 ;		//發現不連續的棋子時,我需要將計數器清空為0
				}
			}
		}
		//黑色棋子橫向查詢       演算法思路同理
		for(int i = 0;i<=15;i++) {
			int count = 0 ;
			for(int j=0;j<=15;j++) {
				if (chess[j][i] != null && chess[j][i].getVisited() == 1 && chess[j][i].getColor() == Color.black) {
				count++;
				System.out.println(count+"黑   橫向查詢");
				if (count == countChess) {
					System.out.println("黑 橫向查詢勝!!");
					winner ="黑棋勝利!";
					return true ;
					}
				}
				else {
					count = 0 ; 
				}
			}
		}
		//白色棋子豎向查詢
		for(int i = 0;i<=15;i++) {
			int count = 0;
			for(int j=0;j<=15;j++) {
				if (chess[i][j] !=null && chess[i][j].getVisited() == 1 && chess[i][j].getColor() == Color.white) {
					count++;
					System.out.println(count+"白  豎向查詢");
					if (count == countChess) {
						System.out.println("白  豎向查詢勝!!");
						winner ="白棋勝利!";
						return true ;
					}
				}
				else {
					count = 0 ;
				}
			}
		}
		//白色棋子橫向查詢
		for(int i = 0;i<=15;i++) {
			int count = 0 ;
			for(int j=0;j<=15;j++) {
				if (chess[j][i] !=null && chess[j][i].getVisited() == 1 && chess[j][i].getColor() == Color.white) {
					count++;
					System.out.println(count+"白  豎向查詢");
					if (count == countChess) {
						System.out.println("白  豎向查詢勝!!");
						winner ="白棋勝利!";
						return true ;
					}
				}
				else {
					count = 0 ;
				}
			}
		}
		
		
		/*	這一層斜向的判斷是最難的,主要是把一個棋盤分成兩個部分來判斷:對角線以上,對角線以下
		 * 	外層迴圈遍歷陣列的橫座標索引節點,每次遍歷都要重置計數器
		 * 	內層迴圈的判斷很複雜,演算法很難,具體就是按照橫軸座標變化的規律,來計算縱軸座標,只能意會不可言傳(實在說不清楚,不過按照這個演算法走一遍應該就能理解了)。
		 * */
		//黑色棋子右上至左下查詢(前半部分)
	for(int i = 0 ; i <= 15; i++) {
			int count = 0 ;
			for(int j = 0 ;j <= i ; j++) {
				if (chess[j][i-j] != null &&chess[j][i-j].getVisited() == 1 && chess[j][i-j].getColor() == Color.black) {
					count++;
					System.out.println(count+"黑   斜向遍歷(前半部分)");
					if (count == countChess) {
						System.out.println("黑   斜向遍歷(前半部分)查詢勝!!!");
						winner ="黑棋勝利!";
						return true;
					}
				}
				else count = 0;
			}
		}

	//黑色棋子右上至左下查詢(後半部分)
	for(int i = 1 ; i <=15 ; i++){
		int count = 0 ;
		for(int j = i ; j<=15; j++) {
			if (chess[j][15 - j + i ] != null &&chess[j][15 - j + i ].getVisited() == 1 && chess[j][15 - j + i ].getColor() == Color.black) {
				count++;
				System.out.println(count +"黑   斜向遍歷(後半部分)");
				if (count == countChess) {
					System.out.println("黑   斜向遍歷(後半部分)查詢勝!!!");
					winner ="黑棋勝利!";
					return true ;
				}
			}
			else count = 0 ;
		}
	}
		
	//白色棋子右上至左下查詢(前部分)
	for(int i = 0 ; i <= 15; i++) {
		int count = 0 ;
		for(int j = 0 ;j <= i ; j++) {
			if (chess[j][i-j] != null &&chess[j][i-j].getVisited() == 1 && chess[j][i-j].getColor() == Color.white) {
				count++;
				System.out.println(count+"白   斜向遍歷(前半部分)");
				if (count == countChess) {
					System.out.println("白   斜向遍歷(前半部分)查詢勝!!!");
					winner ="白棋勝利!";
					return true;
				}
			}
			else count = 0;
		}
	}

	//白色棋子右上至左下查詢(後半部分)
	for(int i = 1 ; i <=15 ; i++){
		int count = 0 ;
		for(int j = i ; j<=15; j++) {
			if (chess[j][15 - j + i ] != null &&chess[j][15 - j + i ].getVisited() == 1 && chess[j][15 - j + i ].getColor() == Color.white) {
			count++;
			System.out.println(count +"白   斜向遍歷(後半部分)");
				if (count == countChess) {
				System.out.println("白   斜向遍歷(後半部分)查詢勝!!!");
				winner ="白棋勝利!";
				return true ;
				}
			}
			else count = 0 ;
		}
	}
	//黑色棋子左上至右下查詢(前部分)
	for(int i = 0 ; i <= 15 ; i++ ) {
		int count = 0 ;
		for(int j = 0 ; j+i<= 15 ; j++ ) {
			if (chess[j + i][ j ] != null &&chess[j+i][j].getVisited() == 1 && chess[j+i][ j ].getColor() == Color.black) {
				count++;
				System.out.println(count+"黑   左上至右下(前半部分)!!!");
				if (count == countChess) {
					System.out.println("黑   左上至右下(前半部分)勝!!!");
					winner ="黑棋勝利!";
					return true ;
				}
			}
			else count = 0 ;
		}
	}
	//黑色棋子左上至右下查詢(後部分)
	for(int i = 1 ; i<=15;i++) {
		int count = 0 ;
		for(int j = 0; j+i<=15 ;j++) {
			if (chess[ j ][ j+i ] != null && chess[ j ][ j+i ].getVisited() == 1 && chess[ j ][ j+i ].getColor() == Color.black) {
				count++;
				System.out.println(count+"黑   左上至右下(後半部分)!!!");
				if (count==countChess) {
					System.out.println("黑   左上至右下(後半部分)勝!!!");
					winner ="黑棋勝利!";
					return true ;
				}
			}
			else count = 0 ;
		}
	}
	//白色棋子左上至右下查詢(前部分)
	for(int i = 0 ; i <= 15 ; i++ ) {
		int count = 0 ;
		for(int j = 0 ; j+i<= 15 ; j++ ) {
			if (chess[j + i][ j ] != null &&chess[j+i][j].getVisited() == 1 && chess[j+i][ j ].getColor() == Color.white) {
				count++;
				System.out.println(count+"白   左上至右下(前半部分)!!!");
				if (count == countChess) {
					System.out.println("白   左上至右下(前半部分)勝!!!");
					winner ="白棋勝利!";
					return true ;
				}
			}
			else count = 0 ;
		}
	}
	//白色棋子左上至右下查詢(後部分)
	for(int i = 1 ; i<=15;i++) {
		int count = 0 ;
		for(int j = 0; j+i<=15 ;j++) {
			if (chess[ j ][ j+i ] != null && chess[ j ][ j+i ].getVisited() == 1 && chess[ j ][ j+i ].getColor() == Color.white) {
				count++;
				System.out.println(count+"白   左上至右下(後半部分)!!!");
				if (count==countChess) {
					System.out.println("白   左上至右下(後半部分)勝!!!");
					winner ="白棋勝利!";
					return true ;
				}
			}
			else count = 0 ;
		}
	}
		return false ;
	}
	
	//重新開始功能
	public void restart() {
		//棋子陣列重置清空
		for(int i = 0 ; i <=ROW ; i++) {
			for(int j=0;j<=COW;j++) {
				chess[i][j].setUnvisited(-1); //將所有棋子均標記為沒有訪問
			}
		}
		//遊戲重新開始的判斷標籤
		this.gameover = true ;
		this.winner = " ";
		//重畫棋盤
		repaint();
	} 
	//遊戲開始功能
	public void start() {
		this.gameover = false;
	}
	
	//四子棋設定
	public void fourPoint() {
		this.countChess = 4 ;
	}
	//五子棋設定
	public void fivePoint() {
		this.countChess = 5 ;
	}
	//五子棋設定
	public void sixPoint() {
		this.countChess = 6 ;
	}
	
	public String whoPlay() {
		return blackOrwhite;
	}
	public String winner() {
		return winner ;
	}
	
	//六子棋,因為六子棋規則不一樣,每個人需要輪流下兩顆棋子才行,所以需要一個新的功能,步數判斷來實現才行
	private void sixPointGame() {
		if (flag == 0 && IsVisited(xIndex, yIndex)) {
			chess[xIndex][yIndex] = new chessPoint(1,drawX,drawY);
			chess[xIndex][yIndex].setColor(Color.white);						
			repaint();				
			System.out.println("白");	
			this.StepOfPlayer++;
			blackOrwhite = "黑手";
			if (StepOfPlayer == 2) {
				flag = 1;
				StepOfPlayer = 0 ;
			}
		}
		else if ( flag == 1 && IsVisited(xIndex, yIndex) ) {
			chess[xIndex][yIndex] = new chessPoint(1,drawX,drawY);
			chess[xIndex][yIndex].setColor(Color.black);						
			repaint();				
			System.out.println("黑");
			this.StepOfPlayer++;
			blackOrwhite = "白手";
			if (StepOfPlayer == 2) {
				flag = 0 ;
				StepOfPlayer = 0 ;
			}
		}
	}
	//五子棋和四子棋的規則一樣,所以不用另外在寫一個功能
	private void fiveOrfourPointGame() {
		if (flag == 0 && IsVisited(xIndex, yIndex)) {
			flag = 1 ;
			chess[xIndex][yIndex] = new chessPoint(1,drawX,drawY);
			chess[xIndex][yIndex].setColor(Color.white);						
			repaint();				
			blackOrwhite = "黑手";
			System.out.println("白");
		}
		else if ( flag == 1 && IsVisited(xIndex, yIndex) ) {
			flag = 0 ;
			chess[xIndex][yIndex] = new chessPoint(1,drawX,drawY);
			chess[xIndex][yIndex].setColor(Color.black);						
			repaint();				
			blackOrwhite = "白手";
			System.out.println("黑");
		}

	}
	
	
	@Override
	public void mouseClicked(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent e) {
		// TODO Auto-generated method stub
		
		//如果遊戲結束了,那麼就停止滑鼠事件響應
		if (gameover == true) {
			return ;
		}
		
		//通過滑鼠的座標換算成索引下標
		 xIndex = (e.getX() - MARGIN + GRID_SPAN/2)/GRID_SPAN ;
		 yIndex = (e.getY() - MARGIN + GRID_SPAN/2)/GRID_SPAN ;
		drawX = (int)((e.getX() - MARGIN + GRID_SPAN/2)/GRID_SPAN)*GRID_SPAN + MARGIN ;
		drawY = (int)((e.getY() - MARGIN + GRID_SPAN/2)/GRID_SPAN)*GRID_SPAN + MARGIN ;
		System.out.println(drawX+"\t"+drawY);
		
		

		if(countChess == 5 || countChess == 4) {
			fiveOrfourPointGame();
		}
		if (countChess == 6) {
			sixPointGame();
		}
		
		//System.out.println(xIndex+"\t"+yIndex);
		//System.out.println(flag);
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub
		
	}
	
	//測試
//	public static void main(String[] args) {
//		// TODO Auto-generated method stub
//		
//		chessMap cMap = new chessMap();
//		JFrame jFrame = new JFrame("test") ;
//		jFrame.add(cMap);
//		jFrame.setBounds(100, 100, 900, 600);
//		jFrame.setDefaultCloseOperation(3);
//		jFrame.setResizable(false);
//		jFrame.setVisible(true);
//	}

}









相關推薦

五子棋遊戲製作詳細思路原理

五子棋設計思路文件 一、程式設計原理、目的以及演算法 運用java swing和awt框架實現五子棋的繪圖,按鈕的事件響應等功能。主要分為三個類:主要UI類、棋子類、以及棋盤類。在原有的五子棋的基礎上增加了四子棋和六子棋的擴充套件玩法,對於六子棋來說,玩家需要每人一次下兩顆

RIP動態路由協議配置思路原理

outer esp 本地 request 發送 orm 次優路徑 必須 toc RIP 協議配置命令: 1、配置終端設備 - PC1/2 2、配置網絡設備 R1/R2/R3/R4 router rip // 啟用路由協議 RIP

守護進程模型創建思路詳細實現代碼

flags emp val 系統時間 會話 home 控制 sleep pen Daemon(精靈)進程,是Linux中的後臺服務進程,通常獨立於控制終端並且周期性的執行某種任務或者等待處理某些發生的事件,一般采用以d結尾的名字。 特點: 沒有控制終端,不能直接和用戶交互,

Android查缺補漏(線程篇)-- AsyncTask的使用原理詳細分析

catch 返回 rri 理解 ams tee ive lean keyword 本文作者:CodingBlock 文章鏈接:http://www.cnblogs.com/codingblock/p/8515304.html 一、AsyncTask的使用 AsyncT

Construct2小遊戲製作體驗新手指南

Construct2小遊戲製作體驗及新手指南 遊戲展示 遊戲策劃 遊戲設計&製作 下載安裝遊戲 建立專案 佈局、背景及人物圖層等的建立 人物屬性行為等 建立事件

Hbase的詳細介紹底層原理

一、hbase介紹 hbase的產生背景: 當資料量過於龐大的時候 資料的快速查詢是很難實現的 GFS-------分散式儲存的 MAPERREDUCE------分散式計算的 BIGTABLE------分散式資料庫 快速查詢 hbase是什麼? hbase是一個分散式的

開發IDEA定位到.class檔案的外掛(二)專案配置原理詳細記錄

專案配置及原理詳細記錄 專案結構  HelloAction.java import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActio

RPG遊戲製作-03-人物行走A*尋路演算法

在遊戲中,可以控制人物的方法一般有:1.鍵盤 2.虛擬搖桿 3.滑鼠 4.手機觸碰。鍵盤一般是在PC端較為常用,如果在遊戲中使用wasd等操作人物的話,那麼在移植到安卓端時,就需要使用虛擬搖桿或虛擬按鈕來模擬鍵盤,以實現處理的統一性。滑鼠類似於手機的單點觸碰,而手機觸碰一般分

掃雷遊戲製作全過程01 地雷生成表示

/*用來生成地雷的的類*/ public class Mine { //雷區的長和寬及雷的個數 final int width = 5; final int height = 4; final int mine_num = 6; //為了生成雷區方便 int[]

深度學習中Attention Mechanism詳細介紹:原理、分類應用

Attention是一種用於提升基於RNN(LSTM或GRU)的Encoder + Decoder模型的效果的的機制(Mechanism),一般稱為Attention Mechanism。Attention Mechanism目前非常流行,廣泛應用於機器翻譯、語音識別、影象標

C++多型的實現原理詳細解析

C++的多型性用一句話概括就是: 在基類的函式前加上virtual關鍵字,在派生類中重寫該函式,執行時將會根據物件的實際型別來呼叫相應的函式。 如果物件型別是派生類,就呼叫派生類的函式;如果物件型別是基類,就呼叫基類的函式,此為多型的表現; 在看看以下幾點: 1. 用vir

製作rhel6的U盤系統盤詳細步驟所需軟體

準備工作先準備好兩個映象檔案  rhel-server-6.6-x86_64-boot.iso   連結:https://pan.baidu.com/s/1mjfoEZQ 密碼:mo9e  rhel-server-6.4-x86_64-dvd.iso(多了一個安裝映象)連結:

C語言編寫的五子棋遊戲 設計思路

現在已經大2了 ,學校的實訓課要我們編寫一個五子棋遊戲 ,雖然過程艱辛。但還是很有成就感的,一下是我的感悟 用C語言編寫的五子棋遊戲 這個五子棋遊戲是站長剛學C語言兩個月時所寫!! C語言製作五子棋 五子棋遊戲是一個深受人們喜愛的遊戲,通常是人機對弈,本程式設計為人與人對弈

一個實驗搞定華為hybrid-vlan基本配置原理

華為 hybrid-vlan實驗拓撲:2. 實驗需求:PC1和PC3屬於VLAN10 PC2和PC4屬於VLAN20 PC5和PC6屬於VLAN30。VLAN10和20的成員都可以和VLAN30中PC5通信,但是VLAN10和VLAN20的成員之間不能通信(通過二層技術實現此需求,就是華為Hybrid

async源碼學習 - waterfall函數的使用原理實現

color logs 這一 per () create was ret ray waterfall函數會連續執行數組中的函數,每次通過數組下一個函數的結果。然而,數組任務中的任意一個函數結果傳遞失敗,那麽該函數的下一個函數將不會執行,並且主回調函數立馬把錯誤作為參數執行。以

常用 JavaScript 小技巧原理詳解

this lin slice pen global 轉化 script lis fun 善於利用JS中的小知識的利用,可以很簡潔的編寫代碼 1. 使用!!模擬Boolean()函數 原理:邏輯非操作一個數據對象時,會先將數據對象轉換為布爾值,然後取反,兩個!!重復取反,就實

【字符編碼】Java字符編碼詳細解答問題探討

很好 cep 我們 簡單 實現 而是 tle 針對 Coding 一、前言   繼上一篇寫完字節編碼內容後,現在分析在Java中各字符編碼的問題,並且由這個問題,也引出了一個更有意思的問題,筆者也還沒有找到這個問題的答案。也希望各位園友指點指點。 二、Java字符編碼   

JS對象創建常用方式原理分析

原型模式 這樣的 前言 values 一句話 開始 creat 動態原型 1-1 ====此文章是稍早前寫的,[email protected]/* */==== 前言 俗話說“在js語言中,一切都對象”,而且創建對象的方式也有很多種,所以今天我們做一下梳理 最

solr搜索之入門原理(一)

solr solr入門 1 solr簡介solr官方文檔:http://wiki.apache.org/solr/DataImportHandler 下載地址:http://www.apache.org/dyn/closer.cgi/lucene/solr/2 solr入門我們使

String的&#39;+&#39;的性能原理

變量 height 操作 通過 效率 調用 java -h 方法 逛了幾個論壇。不少人在討論String的“+”,StringBuilder與StringBuffer等一系列的問題。先不多說了了 現分類詳述: 1、String的‘+’,底層運行。