`
MouseLearnJava
  • 浏览: 467127 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Swing数独游戏(三):数独难题生成

阅读更多
前面两篇博文介绍了数独终盘生成的两种方法。

Swing数独游戏(一):终盘生成之矩阵转换法 ==> http://mouselearnjava.iteye.com/blog/1941483
Swing数独游戏(二):终盘生成之随机法 ==> http://mouselearnjava.iteye.com/blog/1941693

拥有了数独终盘之后,我们需要在这个终盘上挖去一些数字,然后就能产生数独难题。

在这篇博文中将简单介绍一下“挖洞”法生成数独难题的方式,并采用随机挖洞的方式,对同一份数独终盘产生不同难度的数独难题。

“挖洞”的方式可以有多种实现,一般有四种方式:

参考自:http://zhangroup.aporc.org/images/files/Paper_3485.pdf



本文采用随机法来实现。


生成的步骤如下:
1. 首先采用前面两篇文章提供的产生数独终盘的方式,产生1000个.txt文件,作为每一关关卡的数独终盘。

Swing数独游戏(一):终盘生成之矩阵转换法 ==> http://mouselearnjava.iteye.com/blog/1941483
Swing数独游戏(二):终盘生成之随机法 ==> http://mouselearnjava.iteye.com/blog/1941693

2. 每个数独终盘由9个 3 * 3 的块组成,根据设定的关卡难度随机产生一个适合关卡难度的随机数,比如5, 然后在某个 3*3的块中随机剔除5个数。

剔除数据的位置记为1,代表这个位置没有数字,用户可以输入数字。保留数字的位置记为0, 用于在页面上显示出数字,但用户不能对其进行修改操作。

比如:

我们可以定义游戏难度为四个等级:简单,中等,困难和非常困难。

定义每个困难等级随机数剔除数据的数目:

简单 --> [4,5]
中等 --> [5,6]
困难 --> [5,8]
非常困难 --> [6,9]


/**
	 * 根据不同的游戏难度,获取随机数
	 */
	public int getRandomNumberByLevel(DifficultyLevel level) {
		int randomValue = 5;

		switch (level) {
		case EASY:
			/**
			 * 产生随机数[4,5]
			 */
			randomValue = random.nextInt(2) + 4;
			break;
		case MEDIUM:
			/**
			 * 产生随机数[5,6]
			 */
			randomValue = random.nextInt(2) + 5;
			break;
		case DIFFICULT:
			/**
			 * 产生随机数[5,8]
			 */
			randomValue = random.nextInt(4) + 5;
			break;
		case EVIL:
			/**
			 * 产生随机数[6,9]
			 */
			randomValue = random.nextInt(4) + 6;
			break;
		default:
			break;

		}
		return randomValue;
	}



3. 根据关卡的数独终盘及其根据困难等级随机挖空某些数据产生的文件一起,共同确定数独难题

比如,第一关对应的数独终盘如下图所示,终盘内容存储在文件1.txt中。


结合为简单难度产生的“挖洞”后的文件,生成对应的数独难题:

  • 简单难度==>




  • 同理可以获得中等难度,困难难度等对应的数独难题。
  • 中等难度==>



  • 困难难度==>





这样一来,不同困难难度的数独难题就产生了,一个关卡,根据剔除数据个数的不同,将为每个困难等级产生一个挖洞文件,也就是有四个数独难题。如果随机产生1000个数独终盘,那么玩家可以玩4000个数独题目,每个困难等级1000个关卡可供选择。

总结:

本篇文章使用简单的随机剔除数据的方法去产生数独难题,这个方法比较方便简单。但是并不能保证解的唯一性,也就是一道数独难题可能拥有超过一个解法。如果用户填入的数据都满足数独条件,那么他的解就是可用的,有效的,可以通过该关卡。
另外随机剔除数据可能没有剔除某些数据的关联性,可能使得尽管剔除的数据不少,但是玩起来并不难的情况。




下面是随机剔除数据的一个工具类:

package my.sudoku.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import java.util.logging.Logger;

import my.sudoku.constant.SudokuContants;
import my.sudoku.enums.DifficultyLevel;

public class HoleDigUtils {

	private static final Logger logger = Logger
			.getLogger("my.sudoku.utils.HoleDigUtils");

	private Random random = new Random();

	public void digHolesByGameDifficulty(int numOfFiles, DifficultyLevel level) {
		for (int num = 1; num <= numOfFiles; num++) {
			int[][] array = new int[9][9];
			int randomInt = 0;
			for (int i = 0; i < 9; i++) {

				randomInt = getRandomNumberByLevel(level);

				int[] randomPositions = populateRandomArray(randomInt);

				for (int j = 0; j < randomPositions.length; j++) {
					int col = (i % 3) * 3 + (randomPositions[j] - 1) % 3;
					int row = (i / 3) * 3 + ((randomPositions[j] - 1) / 3);

					array[row][col] = 1;
				}
				/**
				 * 将array写入文件
				 */
				BufferedWriter bw = null;
				try {
					bw = new BufferedWriter(new FileWriter(new File(
							SudokuContants.SUDOKU_FOLDER_NAME, buildFileName(
									level, num))));
				} catch (IOException e) {
					logger.severe(e.getMessage());
				}
				StringBuilder sb = new StringBuilder();
				for (int k = 0; k < 9; k++) {
					sb.setLength(0);
					for (int j = 0; j < 9; j++) {
						sb.append(array[k][j]);
						sb.append(",");
					}
					try {
						bw.write(sb.substring(0, sb.length() - 1).toString());
						bw.newLine();
					} catch (IOException e) {
						logger.severe(e.getMessage());
					}

				}
				if (bw != null) {
					try {
						bw.close();
					} catch (IOException e) {
						logger.severe(e.getMessage());
					} finally {
						bw = null;
					}
				}

			}
		}
	}

	private String buildFileName(DifficultyLevel level, int fileNumberl) {
		StringBuilder sb = new StringBuilder();

		sb.append(fileNumberl);
		switch (level) {
		case EASY:
			sb.append("_easy.txt");
			break;

		case MEDIUM:
			sb.append("_medium.txt");
			break;
		case DIFFICULT:
			sb.append("_difficult.txt");
			break;
		case EVIL:
			sb.append("_evil.txt");
			break;
		default:
			break;

		}

		return sb.toString();
	}

	/**
	 * 根据不同的游戏难度,获取随机数
	 */
	public int getRandomNumberByLevel(DifficultyLevel level) {
		int randomValue = 5;

		switch (level) {
		case EASY:
			/**
			 * 产生随机数[4,5]
			 */
			randomValue = random.nextInt(2) + 4;
			break;
		case MEDIUM:
			/**
			 * 产生随机数[5,7]
			 */
			randomValue = random.nextInt(3) + 5;
			break;
		case DIFFICULT:
			/**
			 * 产生随机数[5,8]
			 */
			randomValue = random.nextInt(4) + 5;
			break;
		case EVIL:
			/**
			 * 产生随机数[6,9]
			 */
			randomValue = random.nextInt(4) + 6;
			break;
		default:
			break;

		}
		return randomValue;
	}

	private int[] populateRandomArray(int numOfRandoms) {
		int[] array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
		int randomInt = 0;
		for (int i = 0; i < 20; i++) {
			randomInt = random.nextInt(8) + 1;
			int temp = array[0];
			array[0] = array[randomInt];
			array[randomInt] = temp;
		}

		int[] result = new int[numOfRandoms];

		System.arraycopy(array, 0, result, 0, numOfRandoms);

		return result;
	}
	
	public static void main(String[] args) throws IOException {
		HoleDigUtils digger = new HoleDigUtils();
		/**
		 * 采用"挖洞"法,产生不同难度的数独难题文件。
		 *  文件中 0 表示 有数据且不可编辑,1 表示不显示数据,且可编辑
		 */
		for (DifficultyLevel level : DifficultyLevel.values()) {
			digger.digHolesByGameDifficulty(
					SudokuContants.NUMBER_OF_SUDOKU_ARRAYS, level);
		}
	}

}



  • 大小: 152.4 KB
  • 大小: 42.9 KB
  • 大小: 70.3 KB
  • 大小: 65.9 KB
  • 大小: 62 KB
0
2
分享到:
评论

相关推荐

    Java数独游戏代码

    在Java中,我们可以使用Swing或JavaFX库来构建图形用户界面(GUI),这两个库提供了创建窗口、按钮、文本框等组件的工具,用于构建数独游戏的界面。 对于网页版数独游戏,开发者可能使用了HTML、CSS和JavaScript来...

    双人共战数独游戏

    而"双人共战数独游戏"则在此基础上,引入了合作元素,使得玩家可以与朋友一同解决数独难题,增加了游戏的互动性和趣味性。本文将围绕这款由Java编写的双人数独游戏,探讨其背后的技术实现与设计理念。 首先,从技术...

    数独辅助工具

    在这个"数独辅助工具"中,我们可以推测这是一个使用Java编程语言开发的应用,专门为了帮助玩家解决数独难题而设计。Java是一种跨平台的面向对象的编程语言,以其“一次编写,到处运行”的特性著称,因此这个工具可以...

    sudoku-game:用Java编写的数独游戏,可以生成和解决难题

    生成数独难题通常涉及到算法设计。其中一种可能的方法是遗传算法。遗传算法是一种启发式搜索方法,灵感来源于自然选择和遗传学。在这个应用中,算法可能会生成一系列随机的数独板,然后通过交叉、变异等操作逐步优化...

    数独小游戏毕业设计—(包含完整源码可运行).zip

    生成算法可能会包括先生成一个全填满的数独,然后随机删除一些数字,或者从已知的难题开始进行调整。 最后,源码可能还包括一些优化措施,如使用数据结构优化查找和存储,或者使用多线程提高用户体验。例如,使用位...

    java+applet源码-Sudoku:生成并能够解决数独难题的JavaApplet的源代码

    【标题】中的“java+applet源码-Sudoku”指的是一个使用Java编程语言编写的Applet程序,专门用于生成和解决数独游戏的难题。Applet是Java的一种小程序,可以在支持Java的Web浏览器中运行,为用户提供交互式体验。这...

    sudoku-swinger:带有 Swing GUI 的数独解谜器

    3. **求解算法**:"sudoku-swinger" 应该包含一个高效的数独求解算法,例如回溯法或者候选数法,用于自动解决数独难题。 五、Swing GUI 设计与交互 1. **布局管理**:Swing 提供了几种布局管理器,如 FlowLayout、...

    Sudoku Explainer:数独解释​​器 Java (Swing) GUI 解释了如何解决数独-开源

    Keith Corlett 的开源数独解释器解释了任何数独谜题,并生成了人类谜题。 这是一个 Java (Swing) GUI,基于 Nicolas Juillerat 的 DIUF Sudoku Explainer(为了速度而重写),所有提示都来自 Bernhard Hobiger 的 ...

    Sudoku:使用Java创建的迷你数独游戏

    7. **性能优化**:对于复杂度较高的算法,如解决复杂的数独难题,可能需要考虑优化算法效率。例如,通过使用候选数列表减少无效的回溯次数,或者利用特定的数独技巧进行剪枝。 8. **测试与调试**:开发过程中,使用...

    Killer-Sudoku:人工智能项目。 使用文本文件给出的约束解决一个杀手数独谜题

    8. **用户界面**:尽管题目没有提及,但一个完整的项目可能还包括用户界面,让用户可以交互式地输入数独谜题或查看解决方案,这需要对Java Swing或JavaFX等图形库有一定的了解。 通过这个项目,开发者可以深入理解...

    Sudoku Explainer:Sudoku Explainer Java(Swing)GUI解释了如何解决Sudokus-开源

    它会生成基本的(人类可解决的)数独谜题,但要花很长时间才能生成困难的数独。 除非偶然,否则它不会产生真正的难题(留给棺材)。 我的编码思想将速度放在可维护性之前,因此多段代码实现了相同的模式(样板),...

Global site tag (gtag.js) - Google Analytics