目录
1.目的
编写程序实现9*9“数独”小游戏,游戏中包含9个3×3格的小九宫格,并提供一定数量的数字。根据这些数字,利用逻辑和推理,在其它的空格上填入1到9的数字。每个数字在每个小九宫格内只能出现一次,每个数字在每行、每列也只能出现一次。每次游戏开始给出部分数字,根据给定数字进行推理填充剩余空格数据,并编写GUI界面实现游戏。
2.代码结构
1)APPStart.java
这个类的作用是启动数独应用程序。
package hlc.shudu.app;
import hlc.shudu.ui.ShuduMainFrame;
public class AppStart {
/**
* 主方法是Java应用程序的入口点。
* @param args 一个用于接收命令行参数的字符串数组
*/
public static void main(String[] args) {
// 创建一个ShuduMainFrame类的实例,这是应用程序的主窗口。
ShuduMainFrame mainFrame = new ShuduMainFrame();
// 将mainFrame设置为可见,这将启动并显示数独应用程序的主窗口。
mainFrame.setVisible(true);
}
}
2)ShuduHelper.java
这个类通过随机选择位置并检查规则来生成一个有效的数独棋盘。
package hlc.shudu.src;
public class ShuduHelper {
private static int[][] maps = new int[9][9]; // 定义一个名为ShuduHelper的公共类。
private static int[] canPutSum = new int[9];
static int[] used = new int[9];
static boolean isOk = true;
// 声明三个静态变量:
// canPutSum:一个长度为9的一维数组,用来记录每一行中可以放置某个数字的位置数。
// used:一个长度为9的一维数组,用来记录某个数字已经使用的位置。
// isOk:一个布尔变量,用来标记棋盘是否成功生成。
public static int[][] getMap() {
do {
isOk = true;
initMaps();
} while (!isOk);
return maps;
}
// 定义一个公共静态方法getMap,用来生成并返回数独棋盘。
// 通过调用initMaps方法初始化棋盘,如果isOk为false,则重新生成,直到生成成功。
private static void initMaps() {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
maps[i][j] = -1;
}
}
// 初始化maps数组,把所有位置设置为-1,表示空位。
for (int num = 1; num <= 9; num++) {
for (int i = 0; i < 9; i++) {
used[i] = -1;
canPutSum[i] = -1;
}
// 遍历数字1到9,并在每次循环开始时初始化used和canPutSum数组的元素为-1。
for (int i = 0; i < 9; i++) {
if (canPutSum[i] == -1) {
canPutSum[i] = getCanPutSum(i, num);
}
if (canPutSum[i] == 1) {
used[i] = -1;
}
if (canPutSum[i] == 0) {
canPutSum[i] = -1;
used[i] = -1;
if (i > 0) {
if (used[i - 1] != -1) {
clearNum(i - 1, num);
}
i -= 2;
continue;
} else {
isOk = false;
return;
}
} else {
boolean flag = false;
while (!flag) {
int j = (int) (Math.random() * 9);
int ii = (i / 3) * 3 + j / 3;
int jj = (i % 3) * 3 + j % 3;
if (maps[ii][jj] == -1 && j != used[i] && isCanPut(ii, jj, num)) {
maps[ii][jj] = num;
used[i] = j;
canPutSum[i] -= 1;
flag = true;
}
}
}
}
}
}
// 这个部分负责在数独棋盘中放置数字:
// 检查canPutSum[i]是否为-1,如果是则调用getCanPutSum方法计算可以放置数字的位置数。
// 如果某行中只有一个位置可以放置数字,则将used[i]设置为-1。
// 如果没有位置可以放置数字且当前行不为第一行,则调用clearNum方法清除上一行的数字并重新尝试。
// 在找到可以放置的位置后,将数字放置在该位置,并更新used和canPutSum。
private static void clearNum(int i, int num) {
for (int j = 0; j < 9; j++) {
int ii = (i / 3) * 3 + j / 3;
int jj = (i % 3) * 3 + j % 3;
if (maps[ii][jj] == num) {
maps[ii][jj] = -1;
}
}
}
// 定义clearNum方法,清除某行中指定的数字。
private static int getCanPutSum(int i, int num) {
int sum = 0;
for (int j = 0; j < 9; j++) {
int ii = (i / 3) * 3 + j / 3;
int jj = i % 3 * 3 + j % 3;
if (maps[ii][jj] == -1 && isCanPut(ii, jj, num)) {
++sum;
}
}
return sum;
}
// 定义getCanPutSum方法,计算并返回某行中可以放置指定数字的位置数。
private static boolean isCanPut(int ii, int jj, int num) {
for (int i = 0; i < 9; i++) {
if (maps[ii][i] == num) {
return false;
}
if (maps[i][jj] == num) {
return false;
}
}
return true;
}
}
3)SelectNumFrame.java
这个类创建了一个自定义的对话框,用于数独游戏中选择数字。
package hlc.shudu.ui;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class SelectNumFrame extends JDialog implements MouseListener {
//定义一个名为SelectNumFrame的公共类,继承自JDialog并实现MouseListener接口。
//这个类是一个对话框,能够响应鼠标事件。
p