基于JavaFX2.2的简单五子棋游戏

功能需求

1、15*15 交叉线的五子棋面板
2、五个特殊的交叉点是实心小圆点,中间的称为天元,四周的称为星(有点强迫症,不在乎外表的可以忽略)
2、黑白棋的交替落子
3、胜负的判定
4、棋子落在交叉线上
5、棋子不可以下在棋盘外和已经有棋子的位置

游戏分为四个部分:

  • 实体层,游戏的主体,胜负的判定
  • 视图层,游戏面板的实现
  • 控制层,实现鼠标点击事件
  • 测试层,测试功能

项目的结构如下:
在这里插入图片描述

实体层

知识点:this 显式激活构造方法
其实涉及到的算法不难,主要是连子的计数,分为横向,纵向和两个对角线方向,从刚落下的棋子开始往前数,再往后数,计算连在一起的同色棋子个数(注意开始的棋子不要重复计算),只要有一个方向上的数目大于等于 5 就判断输赢。

package entity;

import javafx.scene.control.*;

public class FiveChess {
	
	/**
	 * 维度
	 * 初始化由黑方开始下
	 */
	private int n;
	private double width;
	private double height;
	private double cellLen;
	
	private char[][] chess;
	
	private char currentSide;

	public FiveChess() {
		this(15,560,560,40,'B');
	}
	
	public FiveChess(int n, double width, double height, double cellLen,char currentSide) {
		this.n = n;
		this.width = width;
		this.height = height;
		this.cellLen = cellLen;
		this.currentSide = currentSide;
		this.chess = new char[n+1][n+1];
		initChess();
	}
	
	/**
	 * 对棋盘进行初始化
	 */
	public void initChess() {
		for(int i=0;i<=n;i++) 
			for(int j=0;j<=n;j++)
				chess[i][j] = '0';
	}
	
	public int getN() {
		return n;
	}

	public void setN(int n) {
		this.n = n;
	}

	public double getWidth() {
		return width;
	}

	public void setWidth(double width) {
		this.width = width;
	}

	public double getHeight() {
		return height;
	}

	public void setHeight(double height) {
		this.height = height;
	}

	public double getCellLen() {
		return cellLen;
	}
	
	public void setCellLen(double cellLen) {
		this.cellLen = cellLen;
	}
	
	public char getCurrentSide() {
		return currentSide;
	}
	
	public void setCurrentSide(char side) {
		this.currentSide = side;
	}
	
	public char[][] getChess() {
		return chess;
	}
	
	/**
	 * 检查是否越界
	 * @param x
	 * @param y
	 * @return
	 */
	public boolean overArea(int x,int y) {
		if(x>=0 && x<=n && y>=0 && y<=n)
			return false;
		else
			return true;
	}
	
	/**
	 * 落子
	 * @param x
	 * @param y
	 */
	public boolean play(int x,int y) {
		if(!overArea(x,y) && chess[x][y]=='0') {
			chess[x][y] = currentSide;
			return true;
		} else {
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
	        alert.setTitle("警告");
	        alert.setContentText("棋子不可以下在此处!");
	        alert.showAndWait();
	        return false;
		}
	}
	
	/**
	 * 换边
	 */
	public void changeSide() {
		setCurrentSide(currentSide=='B'?'W':'B');
	}
	
	/**
	 * 判断游戏是否结束
	 * true代表结束游戏 ,false代表继续游戏
	 * @param row
	 * @param col
	 * @param chessColor
	 * @return
	 */
	public boolean judgeGame(int row,int col,char chessColor) {
		int level = level(row,col,chessColor);
		int vertical = vertical(row,col,chessColor);
		int left = leftOblique(row,col,chessColor);
		int right = rightOblique(row,col,chessColor);
		changeSide();
		if(level>=5 || vertical>=5 || left>=5 || right>=5)
			return true;
		else
			return false;
	}
	
	/**
	 * 检查棋子在水平横线上是否连成五子
	 * @return
	 */
	public int level(int row,int col,char chessColor) {
		int line = 1;
		int i = row-1;
		for(;chess[i][col]==chessColor && !overArea(i,col);i--) 
			line++;
		for(i=row+1;chess[i][col]==chessColor && !overArea(i,col);i++)
			line++;
		return line;
	}
	
	/**
	 * 检查棋子在垂直竖线上是否连成五子
	 * @param row
	 * @param col
	 * @param chessColor
	 * @return
	 */
	public int vertical(int row,int col,char chessColor) {
		int line = 1;
		int j=col-1;
		for(;chess[row][j]==chessColor && !overArea(row,j);j--) 
			line++;
		for(j=col+1;chess[row][j]==chessColor && !overArea(row,j);j++)
			line++;
		return line;
	}
	
	/**
	 * 检查左倾斜线上的棋子是否连成五子
	 * @param row
	 * @param col
	 * @param chessColor
	 * @return
	 */
	public int leftOblique(int row,int col,char chessColor) {
		int line = 1;
		int i = row-1,j = col-1;
		for(;chess[i][j]==chessColor && !overArea(i,j);i--,j--) 
			line++;
		for(i=row+1,j=col+1;chess[i][j]==chessColor && !overArea(i,j);i++,j++)
			line++;
		return line;
	}
	
	/**
	 * 检查右倾斜线上的棋子是否连成五子
	 * @param row
	 * @param col
	 * @param chessColor
	 * @return
	 */
	public int rightOblique(int row,int col,char chessColor) {
		int line = 1;
		int i = row-1,j = col+1;
		for(;chess[i][j]==chessColor && !overArea(i,j);i--,j++)
			line++;
		for(i=row+1,j=col-1;chess[i][j]==chessColor && !overArea(i,j);i++,j--)
			line++;
		return line;
	}
}

视图层

package view;

import entity.FiveChess;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;

public class ChessPane extends Pane {
	
	private FiveChess fiveChess;
	private Canvas canvas;
	private GraphicsContext gc;
	
	//棋盘距窗口边框左、上的距离
	private double align = 70;
	
	public ChessPane(FiveChess fiveChess) {
		this.fiveChess = fiveChess;
		draw();
		getChildren().add(canvas);
	}
	
	public double getAlign() {
		return align;
	}

	public void setAlign(double align) {
		this.align = align;
	}

	/**
	 * 绘制棋盘
	 */
	public void draw() {
		canvas = new Canvas(700,700);
		this.gc = canvas.getGraphicsContext2D();
		
		double cell = fiveChess.getCellLen();
		
		//填充棋盘颜色
		gc.setFill(Color.BURLYWOOD);
		gc.fillRect(align-15, align-15, fiveChess.getWidth()+30, fiveChess.getHeight()+30);
		
		for(int y=1;y<fiveChess.getN();y++) {
			//画横线
			gc.strokeLine(align, y*cell+align, fiveChess.getWidth()+align, y*cell+align);
		}
		
		for(int x=1;x<fiveChess.getN();x++) {
			//画竖线
			gc.strokeLine(x*cell+align, align, x*cell+align, fiveChess.getHeight()+align);
		}
		
		/**
		* 天元(7,7),四个星位(3,3),(3,11),(11,3),(11,11)
		* 不想要这五个点的可以不要这一部分,没有什么影响
		**/
		for(int i=3;i<=14;i+=4) 
			for(int j=3;j<=14;) {
				gc.setFill(Color.BLACK);
				//画天元
				if(i == 7) {
					j = 7;
					gc.strokeOval(i*cell+align-4, j*cell+align-4, 8, 8);
					gc.fillOval(i*cell+align-4, j*cell+align-4, 8, 8);
					break;
				}
				//画星位
				else {
					gc.strokeOval(i*cell+align-4, j*cell+align-4, 8, 8);
					gc.fillOval(i*cell+align-4, j*cell+align-4, 8, 8);
					j += 8;
				}
			}
		
		//边框加粗
		gc.setLineWidth(3.0f);
		gc.strokeRect(align, align, fiveChess.getWidth(), fiveChess.getHeight());
		
	}

	/**
	 * 绘制棋子
	 */
	public void paintChess(int x,int y) {
		
		double cell = fiveChess.getCellLen();
		
		if(fiveChess.getCurrentSide() == 'B')
			gc.setFill(Color.BLACK);
		else
			gc.setFill(Color.WHITE);
		gc.strokeOval(align+x*cell-cell/2, align+y*cell-cell/2, cell, cell);
		gc.fillOval(align+x*cell-cell/2, align+y*cell-cell/2, cell, cell);
		
	}
	
}

控制层

package controler;

import entity.FiveChess;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.input.MouseEvent;
import view.ChessPane;

public class PlayAction implements EventHandler<MouseEvent> {

	private FiveChess fiveChess;
	private ChessPane chessPane;
	
	public PlayAction(FiveChess fiveChess, ChessPane chessPane) {
		this.fiveChess = fiveChess;
		this.chessPane = chessPane;
	}

	@Override
	public void handle(MouseEvent event) {
		// TODO Auto-generated method stub
		double cellLen = fiveChess.getCellLen();
		
		//定位
		int x = (int)((event.getX()-chessPane.getAlign()+cellLen/2)/cellLen);
		int y = (int)((event.getY()-chessPane.getAlign()+cellLen/2)/cellLen);
		
		//如果棋子的位置合法就画出棋子
		if(fiveChess.play(x, y))
			chessPane.paintChess(x, y);
		
		if(fiveChess.judgeGame(x, y, fiveChess.getCurrentSide())) {
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
	        alert.setTitle("五子棋游戏");
	        alert.setContentText("游戏结束,"+fiveChess.getCurrentSide()+"获胜!");
	        alert.showAndWait();
		}
	}
}

测试层

package test;

import controler.PlayAction;
import entity.FiveChess;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import view.ChessPane;

public class Test extends Application {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Application.launch(args);
	}

	@Override
	public void start(Stage primaryStage) throws Exception {
		
		FiveChess fiveChess = new FiveChess();
		ChessPane chessPane = new ChessPane(fiveChess);
		PlayAction playAction = new PlayAction(fiveChess,chessPane);
		
		chessPane.setOnMouseClicked(playAction);
        
		Scene scene = new Scene(chessPane,700,700);

		primaryStage.setScene(scene);
		primaryStage.setTitle("五子棋");
		primaryStage.show();
		
	}

}

效果图

在这里插入图片描述

  • 5
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值