游戏描述
一个五子棋游戏,能实现双方黑白对决,当一方获胜时给出提示信息,利用Javafx实现GUI界面实现
上手须知
jdk11以上由于官方已经讲javafx组件分离,需要自己下载相应的组件,需要点击configuration然后在vm options中添加下面参数,注意将你的javafx插件路径替换成你自己的(jdk1.8的盆友请忽略)
--module-path "E:\jdk11\javafx-sdk-11.0.2\lib" --add-modules=javafx.controls,javafx.fxml
源码地址
https://github.com/441712875al/five-chess
项目结构
一、实体层
FiveChess类
- 提供五子棋实体包含的所有信息
- 判断游戏是否结束
- play方法改变chess[][]棋盘中的数据
package entity;
import enums.Side;
public class FiveChess{
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;
}
/**
* 维度
*/
private int n;
private double width;
private double height;
/**
* 小方格的大小
*/
private double cellLen;
/**
* 当前棋手
*/
private Side currentSide=Side.BLACK;
public char getFlag() {
return flag;
}
private char flag=' ';
private int[][] chess;
public int[][] getChess() {
return chess;
}
public void setChess(int[][] chess) {
this.chess = chess;
}
public Side getCurrentSide() {
return currentSide;
}
public void setCurrentSide(Side currentSide) {
this.currentSide = currentSide;
}
public FiveChess(double width,double height,double cellLen){
this.width=width;
this.height=height;
this.cellLen=cellLen;
chess=new int[(int)height][(int)width];
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
chess[i][j]=' ';
}
public void play(int x,int y){
//将当前的棋子放置到(x,y)
if(chess[x][y]==' '){
chess[x][y]=currentSide.getCode();
changeSide();
}
}
public void changeSide(){
//更换下棋方
setCurrentSide(currentSide==Side.BLACK?Side.WHITE:Side.BLACK);
}
public boolean judgeGame(int row, int col, Side chessColor){
//判断游戏是否结束
if(rowJudge(row,col,chessColor)&&colJudge(row,col,chessColor)&&mainDiagonalJudge(row,col,chessColor)&&DeputyDiagonalJudge(row,col,chessColor))
return true;
return false;
}
/**
* 横向判断五子连线
* @param row
* @param col
* @param chessColor
* @return
*/
public boolean rowJudge(int row,int col,Side chessColor){
int count = 0;
for(int j = col;j<width;j++){
if(chess[row][j]!=chessColor.getCode())
break;
count++;
}
for(int j=col-1;j>=0;j--){
if(chess[row][j]!=chessColor.getCode())
break;
count++;
}
if(count>=5)
return false;
return true;
}
/**
* 纵向判断
* @param row
* @param col
* @param chessColor
* @return
*/
public boolean colJudge(int row,int col,Side chessColor){
int count=0;
for(int i=row;i<height;i++){
if(chess[i][col]!=chessColor.getCode())
break;
count++;
}
for(int i=row-1;i>=0;i--){
if(chess[i][col]!=chessColor.getCode())
break;
count++;
}
if(count>=5)
return false;
return true;
}
/**
* 主对角线方向
* @param row
* @param col
* @param chessColor
* @return
*/
public boolean mainDiagonalJudge(int row,int col,Side chessColor){
int count=0;
for(int i=row,j=col;i<height&&j<width;i++,j++){
if(chess[i][j]!=chessColor.getCode())
break;
count++;
}
for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--){
if(chess[i][j]!=chessColor.getCode())
break;
count++;
}
if(count>=5)
return false;
return true;
}
/**
* 副对角线方向
* @param row
* @param col
* @param chessColor
* @return
*/
public boolean DeputyDiagonalJudge(int row,int col,Side chessColor){
int count=0;
for(int i=row,j=col;i>=0&&j<width;i--,j++){
if(chess[i][j]!=chessColor.getCode())
break;
count++;
}
for(int i=row+1,j=col-1;i<height&&j>=0;i++,j--){
if(chess[i][j]!=chessColor.getCode())
break;
count++;
}
if(count>=5)
return false;
return true;
}
}
二、视图层
ChessPane
类继承Pane类实现棋盘和五子棋的绘制
package view;
import entity.FiveChess;
import enums.Side;
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 {
public Canvas canvas;
public GraphicsContext gc;
public FiveChess fiveChess;
public Canvas getCanvas() {
return canvas;
}
public GraphicsContext getGc() {
return gc;
}
public FiveChess getFiveChess() {
return fiveChess;
}
public void setFiveChess(FiveChess fiveChess) {
this.fiveChess = fiveChess;
}
public ChessPane(FiveChess fiveChess){
this.fiveChess=fiveChess;
double cell=fiveChess.getCellLen();
drawPane(cell);
drawChess(cell);
getChildren().add(canvas);
}
/*渲染棋盘*/
public void drawPane(double cell){
canvas = new Canvas(800,700);
gc = canvas.getGraphicsContext2D();
gc.clearRect(0,0,canvas.getWidth(),canvas.getHeight());
//绘制棋盘
gc.setStroke(Color.BLACK);
for(int i=0;i<fiveChess.getWidth();i++)
for(int j=0;j<fiveChess.getHeight();j++){
gc.strokeRect(100+i*cell,100+cell*j,cell,cell); //画出小方格
}
}
/*渲染棋子*/
public void drawChess(double cell){
/*获取棋子的位置*/
int[][] chess=fiveChess.getChess();
for(int i=0;i<fiveChess.getHeight();i++)
for(int j=0;j<fiveChess.getWidth();j++){
if(chess[i][j]== Side.BLACK.getCode()){
gc.setFill(Color.BLACK);
gc.fillOval(100+i*cell-cell/2,100+j*cell-cell/2,cell,cell);//画棋子
}
else if(chess[i][j]==Side.WHITE.getCode()){
gc.setFill(Color.WHITE);
gc.fillOval(100+i*cell-cell/2,100+j*cell-cell/2,cell,cell);
gc.strokeOval(100+i*cell-cell/2,100+j*cell-cell/2,cell,cell);
}
}
}
}
三、控制器
PlayAction
类继承自事件处理器EventHandler
并传递的参数是鼠标事件,表示接受鼠标点击面板事件,该类可以使用lamda表达式替换。
package controller;
import entity.FiveChess;
import enums.Side;
import javafx.event.EventHandler;
import javafx.scene.control.Alert;
import javafx.scene.input.MouseEvent;
import view.ChessPane;
import java.io.*;
/**
* 时间处理类,可以使用lamda表达式替代
*/
public class PlayAction implements EventHandler<MouseEvent> {
/*fiveChess表示五子棋游戏模型*/
private FiveChess fiveChess;
/*chessPane表示五子棋显示面板*/
private ChessPane chessPane;
public PlayAction(FiveChess fiveChess,ChessPane chessPane){
this.chessPane=chessPane;
this.fiveChess = fiveChess;
}
@Override
public void handle(MouseEvent event){
//获取棋盘的小方格的大小
double cell = fiveChess.getCellLen();
//获取鼠标点击坐标
double x = event.getX();
double y = event.getY();
/*映射到数组中的坐标*/
int i = (int)((x-100+cell/2)/cell);
int j = (int)((y-100+cell/2)/cell);
/*记录下落子位置*/
try (FileOutputStream out = new FileOutputStream(new File(System.getProperty("user.dir") + "/src/记录.txt"),true)) {
out.write(new String(fiveChess.getCurrentSide().getDesc()+"("+j+","+i+")\n").getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
/*改变棋盘状态*/
fiveChess.play(i,j);
/*重新渲染棋子*/
chessPane.drawChess(cell);
/*判断是否结束*/
if(!fiveChess.judgeGame(i,j,fiveChess.getCurrentSide()== Side.BLACK?Side.WHITE:Side.BLACK)){
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("五子棋游戏");
alert.setHeaderText("提示信息");
String msg = (fiveChess.getCurrentSide()==Side.BLACK?Side.WHITE:Side.BLACK).getDesc()+"取得胜利!";
alert.setContentText(msg);
try (FileOutputStream out = new FileOutputStream(new File(System.getProperty("user.dir") + "/src/记录.txt"),true)) {
out.write(msg.getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
alert.showAndWait();
}
}
}
四、测试
import controller.PlayAction;
import entity.FiveChess;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.stage.Stage;
import view.ChessPane;
import javax.print.attribute.standard.Fidelity;
import java.io.*;
public class Test extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
FiveChess fiveChess = new FiveChess(20,20,28.0);
ChessPane chessPane=new ChessPane(fiveChess);
/*记录下棋盘信息*/
try(FileOutputStream out = new FileOutputStream(new File(System.getProperty("user.dir")+"/src/记录.txt"),true)){
out.write(new String("棋局开始,黑子先行\n").getBytes());
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
/*注册时间处理器*/
chessPane.setOnMouseClicked(new PlayAction(fiveChess,chessPane));
/*显示舞台*/
Scene scene=new Scene(chessPane,800,700);
primaryStage.setScene(scene);
primaryStage.setTitle("五子棋游戏");
primaryStage.show();
}
}
效果图
查看src
目录下的记录.txt
文件保存的本次对局的记录