1. 程式人生 > >軟件工程第二次作業——數獨

軟件工程第二次作業——數獨

不足 ron ini dom 心得 inpu 沖突 學c++ 循環

1. 項目需求:利用程序隨機構造N個已解答的數獨棋盤

2. 輸入:數獨棋盤題目個數N (0 < N <= 1000000)

3. 輸出:隨機生成N個不重復的已解答完畢的數獨棋盤, 並輸出到sudotiku.txt,每個數獨棋盤中間隔一行

可執行文件exe,用法:(sudotiku.exe -c 20)(其中20為題目個數)

頭文件sudoku.h:

#ifndef SUDOKU_H
#define SUDOKU_H

bool Sudoku_Row(int sudo[9][9], int row, int num);
bool Sudoku_Col(int sudo[9][9], int col, int num);
bool Sudoku_Square(int sudo[9][9], int row, int col, int num);
void print_sudoku(int sudo[9][9]);
bool makeSquare(int sudo[9][9], int num);

#endif

源程序:

#include "pch.h"
#include <iostream>
#include <ctime>
#include <fstream>
#include <stdlib.h>
#include "sudoku.h"
using namespace std;
#define Random(x) (rand()%x)
bool flag = false;

void Init_sudo(int(*sudo)[9])
{
for(int r=0;r<9;r++)
{
for (int c = 0; c < 9; c++)
sudo[r][c] = 0;
}
sudo[0][0] = 1;//初始化數獨,使第一個數為1
}
void Init_sudo_part(int(*sudo)[9])
{
for (int r = 3; r < 9; r++)
{
for (int c = 0; c < 9; c++)
sudo[r][c] = 0;
}
for (int r = 0; r < 3; r++)
{
for (int c = 3; c < 9; c++)
sudo[r][c] = 0;
}
}
bool check_sudo(int sudo[9])
{
int temp;
for (int i = 0; i < 9; i++)
{
temp = sudo[i];
for (int j = i + 1;j < 9; j++)
{
if (sudo[j] == temp)
return false;
}
}
return true;
}
//行檢查
bool Sudoku_Row(int sudo[9][9], int row, int num)
{
bool flag = false;//沖突標誌
for (int i = 0; i < 9; i++)
{
if (sudo[row][i] == num)
{
flag = true;
break;
}
}
return flag;
}
//列檢查
bool Sudoku_Col(int sudo[9][9], int col, int num)
{
bool flag = false;
for (int i = 0; i < 9; i++)
{
if (sudo[i][col] == num)
{
flag = true;
break;
}
}
return flag;
}
//宮檢查
bool Sudoku_Square(int sudo[9][9], int row,int col, int num)
{
bool flag = false;
int Square_Row = row / 3 * 3;
int Square_col = col / 3 * 3;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{

if (sudo[Square_Row+i][Square_col+j] == num)
{
flag = true;
break;
}
}
}
return flag;
}
void print_sudoku(int sudo[9][9])
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
cout << sudo[i][j] << ‘ ‘;
}
cout << endl;
}
cout << endl;
}
//生成宮格
bool makeSquare(int sudo[9][9], int num)
{
int square_row = (num / 3) * 3;
int square_col = (num % 3) * 3;
int x, y;
int temp;
if (num = 0) //第一個宮格
{
for (int i = 1; i < 9; i++)
{
x = square_row + i / 3;
y = square_col + i % 3;
temp = Random(8) + 2;//生成2~9的隨機數
if (!Sudoku_Square(sudo, x, y, temp) && !Sudoku_Col(sudo,
y, temp) && !Sudoku_Row(sudo, x, temp))
{
sudo[x][y] = temp;
}
else i--;
}
}
else //生成其他宮格
{
int try_count = 0;
temp = Random(9) + 1;//生成1~9的隨機數
for (int i = 0; i < 9; i++)
{
x = square_row + i / 3;
y = square_col + i % 3;
temp++;
temp = temp % 10;//循環隨機數在1~9範圍內
if (!Sudoku_Square(sudo, x, y, temp) && !Sudoku_Col(sudo,
y, temp) && !Sudoku_Row(sudo, x, temp) && temp != 0)
{
sudo[x][y] = temp;
try_count = 0;
}
else
{
i--;
try_count++;
}
if (try_count > 10)
{
return false;
break;
}//若所有可能試完則返回無解
}

}
return true;//有解
}
int main(int argc, char *argv[])
{
int N = atoi(argv[argc-1]);
int(*sudo)[9] = new int[9][9];
ofstream outfile;
outfile.open("sudoku.text");//輸出到文檔
if (N > 0 && N <= 1000000)
{
srand(unsigned int(time(NULL)));//初始化種子為當前時間
bool retry;//重試
int retry_count = 0;//重試次數
for (int i = 0; i < N;)
{
retry = false;
if (retry_count == 0)
{
Init_sudo(sudo);
makeSquare(sudo, 0);
}
else Init_sudo_part(sudo);
for (int j = 1; j < 9; j++)
{
bool flag = makeSquare(sudo, j);
if (!flag)
{
retry = true;
break;
}
}
if (!retry)
{
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
outfile << sudo[row][col] << ‘ ‘;
}
outfile << endl;
}//輸出一個數獨矩陣
outfile << endl;
retry_count = 0;
i++;
}
else
{
retry_count++;
}//無解重試
}
outfile.close();
}
else cout << "please input a proper number:" << endl;
return 0;
}

輸出到sudoku.txt中:

技術分享圖片

程序分析:輸出和生成宮格所用的時間比較多,還有待完善改進,但生成的數獨沒有重復的。這次項目我耗時比較長,也查了許多資料和百度參考別人的經驗。我用的是VS2017版本,在調試過程需要在頭文件加#include "pch.h"。

心得體會:通過這次作業,我發現我存在了很多有關於算法和編程方面的不足,程序中一點細微的問題都要處理比較久,但值得開心的是學到了一些知識,以後要加強算法和編程方面的練習。

課外任務:大一學過一點C語言,現在正在自學C++,目前能夠看懂一些比較基礎的程序代碼和編寫一些簡單的程序,算法是個薄弱環節,距離一個合格的IT專業畢業生還有很大的差距,需要提高算法能力和編程能力,還有優化代碼的能力。以下這個表是我目前的技能水平和期待課程結束後能達到的水平:

技術分享圖片

軟件工程第二次作業——數獨