Sudoku

个人项目-数独游戏

0. 前言

个人简介

作者:icode_499
学校:北京理工大学
专业:计算机科学与技术专业

项目简介

任务:生成数独终局并且能求解数独问题的控制台程序。

1. PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划
· Estimate· 估计这个任务需要多少时间3030
Development开发
· Analysis· 需求分析 (包括学习新技术)12020+
· Design Spec· 生成设计文档9030+
· Design Review· 设计复审 (和同事审核设计文档)-
· Coding Standard· 代码规范 (为目前的开发制定合适的规范)-
· Design· 具体设计9030+
· Coding· 具体编码600300+
· Code Review· 代码复审6010+
· Test· 测试(自我测试,修改代码,提交修改)12030+
Reporting报告
· Test Report· 测试报告60
· Size Measurement· 计算工作量20
· Postmortem & Process Improvement Plan· 事后总结, 并提出过程改进计划30
合计920

iteration-1 需求

  1. 在命令行中使用-c 参数加数字 N(1<=N<=1000000)控制生成数独终局的数量,例如下述命令将生成 20 个数独终局至文件中。
    sudoku -c 20
    
  2. 将生成的数独终局用一个文本文件(假设名字叫 sudoku.txt)的形式保存起来,每次生成的 txt 文件需要覆盖上次生成的 txt 文件,文件内的格式如下,数与数之间由空格分开,终局与终局之间空一行,行末无空格。
  3. 程序在处理命令行参数时,不仅能处理格式正确的参数,还能够处理各种异常的情况。
  4. 在生成数独矩阵时,左上角的第一个数为:(学号后两位相加)% 9 + 1。例如学生 A 学号后 2 位是 80,则该数字为(8+0)% 9 + 1 = 9,那么生成的数独棋盘应如下(x 表示满足数独规则的任意数字)。

解题思路

  1. 按照需求4,我的学号后两位为65,则左上角的第一个数为(6+5)% 9 + 1 = 3。
  2. 按照要求1,最多要生成 1000000 个不同的数独终局。
  3. 数独终局的生成思路:
    经过学习,我发现可以这样构建一个合法的数独:对于这个给定的数独终局,从第二行开始,每行分别是第一行左移 3,6,1,7,4,2,5,8 列的结果。
    这样构建出来的数独终局可以分解成 9 个 3 × 3 3 \times 3 3×3 的表,每个表中都有 1-9 九个不重复数字。
    而题目中要求我生成的数独终局左上角第一个数为 3,第一行还有 8 个空可以随意填入 {1, 2, 4, 5, 6, 7, 8, 9} 这 8 个数字,相当于是 8 个数字的全排列,这样可以得到 8!= 40320 种数独终局。我们将这样的数独终局称为基础数独终局。
    但是这还并未达到预期要生成的最大数独终局数,于是我们可以在已生成的数独终局上进行变换产生新的数独终局。
    注意到,对于任何数独,都可以任意交换它的1-3行,4-6行,7-9行,1-3列,4-6列,7-9列,而使得交换后的数独仍然是一个合法的数独。
    对于本项目而言,由于第 1 行第 1 个数字固定为 3,因此我们不能和第一行数据交换,因此本项目提出了这样的变换策略:
    (1) 任意交换4-6行。
    (2) 任意交换7-9行。
    这样可以使数独终局数目变为原来的 3 ! × 3 ! = 36 3! \times 3! =36 3!×3!=36 倍,此时数独终局一共 36 × 40320 = 1451520 36 \times 40320=1451520 36×40320=1451520 种终局,已经超过了 1000000 种,已经满足需求了。

设计实现

主函数流程图

在这里插入图片描述

关键类介绍

这里只介绍关键的实现,给出两个关键类的定义:

  1. Sudoku类
/* Sudoku.h */
#pragma once
#include "include.h"

class Sudoku
{
private:
	int data[9][9]; // 数独终局
	/* exMid[0]=5表示 交换后中间三行的第一行是基础数独终局的第(5+1)=6行
	  也即交换后第4行数据换为第6行数据 */
	int exMid[3];
	int exLast[3];
	void exchangeMid(const int _numMid);
	void exchangeLast(const int _numLast);
	void setRow(const int num, const int row[9]); // 将row的数据写入第num行

public:
	Sudoku();
	Sudoku(const int data[9][9]);
	~Sudoku();
	void writeToFile(FILE *fp) const;	// 将data数据写入文件
	void setFirstRow(const int firstRow[9]);	// 设置首行数据
	void createFromFirstRow();// 由首行数据分别移动{3,6,1,4,7,2,5,8}得到数独终局
	void createNew(const int _num, FILE *outputFile, int flag = 0); // 36种变换
};
  1. SudokuGenerator类
#pragma once
#include "include.h"
#include "Sudoku.h"

class SudokuGenerator
{
private:
	FILE *outputFile; // 输出文件,sudoku.txt
	int sudokuNum;	  // 需要生成的数独终局数量
	int firstRow[9]{};

public:
	SudokuGenerator(const std::string &outputFile, const int sudokuNum);
	~SudokuGenerator();
	void GenerateSudoku(); // 生成数独终局
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

icode_499

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值