2020軟件工程作業03


軟件工程 2020軟件工程作業
作業要求 https://edu.cnblogs.com/campus/zswxy/software-engineering-2017-1/homework/10494
作業目的 實現一個命令行程序,不妨稱之為Sudoku
作業正文 如下
其他參考文獻 https://www.runoob.com/python3/python3-tutorial.html
https://github.com/changorz/work/tree/master/20177583/src
https://blog.csdn.net/qq_40871196/article/details/89431987

Github項目地址

https://github.com/zxw0621/demo/tree/master/20177596/src

PSP表格

PSP2.1 Personal Software Process Stages 預估耗時(分鍾) 實際耗時(分鍾)
Planning 計划 30 20
Estimate 估計這個任務需要多少時間 600 700
Development 開發 300 200
Analysis 需求分析 (包括學習新技術) 30 20
Design Spec 生成設計文檔 30 30
Design Review 設計復審 60 30
Coding Standard 代碼規范 (為目前的開發制定合適的規范) 30 20
Design 具體設計 30 30
Coding 具體編碼 60 60
Code Review 代碼復審 60 20
Test 測試(自我測試,修改代碼,提交修改) 30 10
Reporting 報告 20 20
Test Repor 測試報告 20 20
Size Measurement 計算工作量 20 20
Postmortem & Process Improvement Plan 事后總結, 並提出過程改進計划 30 30
合計 1350 1230

思路描述


審題

  1. 按照數獨游戲的規定,給一張含有若干的數字隨機分布在網格的圖,在每個位置上的數在列和行上不能重復出現,在4、6、8、9階的數獨表中,每個小宮格內不能有重復的數出現。
  2. 用cmd命令行的形式讀出寫入文件,並傳入參數。
  3. 要實現多個九宮格一起處理,且解答情況唯一。
  4. 要求用java和c++,這里順便學習下python(從大一剛學那會就學習過一點點,后來忙於學習學校安排的課程后沒怎么學了,以后還想接觸些膾炙人口的新鮮事物,比如某些大佬開口就是什么大數據,雲計算,人工智能的)

功能模塊設計

流程圖

1.定位模塊

def new_locate(_x_, _y_, _a_, _b_):  #上面的版本是學習小鄧同學的定位
    '''
    新版定位
    :param _x_:
    :param _y_:
    :return:
    '''
    if M % 3 == 0:   #通過向下取整計算出 大的九宮格能分成幾行幾列的小九宮格
        _c_ = 3
        _r_ = int(M / 3)
    elif M % 2 == 0:
        _c_ = 2
        _r_ = int(M / 2)
    _a_ = int(_x_ // _c_ * _c_)
    _b_ = int(_y_ // _r_ * _r_)c_:_r_
    return _a_, _b_, _c_, _r_   #這里返回 _a_: 當前元素所在的小九宮格 左上角的橫坐標
                               #         _b_: 當前元素所在的小九宮格 左上角的縱坐標
                               #         _c_: 大九宮格被分成了 r行 c列的小九宮格
                               #         _r_:


# def locate(_x_, _y_, _a_, _b_):     #莽夫判斷  respect阿傳
#     '''
#     確定當前元素所在九宮格位置
#     :param _x_:
#     :param _y_:
#     :param a:
#     :param b:
#     :return:
#     '''
#     if 0 <= _x_ < 3 and 0 <= _y_ < 3:
#         _a_ = 0
#         _b_ = 0
#
#     if 3 <= _x_ < 6 and 0 <= _y_ < 3:
#         _a_ = 3
#         _b_ = 0
#
#     if 6 <= _x_ < 9 and 0 <= _y_ < 3:
#         _a_ = 6
#         _b_ = 0
#
#     if 0 <= _x_ < 3 and 3 <= _y_ < 6:
#         _a_ = 0
#         _b_ = 3
#
#     if 0 <= _x_ < 3 and 6 <= _y_ < 9:
#         _a_ = 0
#         _b_ = 6
#
#     if 3 <= _x_ < 6 and 3 <= _y_ < 6:
#         _a_ = 3
#         _b_ = 3
#
#     if 3 <= _x_ < 6 and 6 <= _y_ < 9:
#         _a_ = 3
#         _b_ = 6
#
#     if 6 <= _x_ < 9 and 3 <= _y_ < 6:
#         _a_ = 6
#         _b_ = 3
#
#     if 6 <= _x_ < 9 and 6 <= _y_ < 9:
#         _a_ = 6
#         _b_ = 6
#     return _a_, _b_

2.行列無重復判斷模塊

def fun(_x_, _y_):
    '''
    確定行列上不重復
    :param inde__x_:
    :param _y_:
    :param num:
    :return:
    '''

    for _i_ in range(M):
        if _i_ != _x_ and DATA[_i_][_y_] == DATA[_x_][_y_]:#遍歷行
            return 0
    for j in range(M):
        if j != _y_ and DATA[_x_][j] == DATA[_x_][_y_]:#遍歷列
            return 0
    _a_ = 0
    _b_ = 0
    _a_, _b_, _c_, _r_ = new_locate(_x_, _y_, _a_, _b_) 
    for _i_ in range(_a_, _a_ + _c_):
        for j in range(_b_, _b_ + _r_):
            if _i_ != _x_ and j != _y_ and DATA[_i_][j] == DATA[_x_][_y_]:#遍歷小九宮格
                return 0
    return 1

3.深度優先搜索模塊

def dfs(_x_, _y_):
    '''
    深搜
    :param _x_:
    :param _y_:
    :return:
    '''
#這里就相當於給沒填數字的格子 嘗試可能填的數
    if _x_ > M - 1:
        disp()
    elif DATA[_x_][_y_] != 0:
        if _y_ == M - 1:
            dfs(_x_ + 1, 0)
        else:
            dfs(_x_, _y_ + 1)
    else:
        for _i_ in range(1, M + 1):
            DATA[_x_][_y_] = _i_  #從1到M 賦值嘗試
            if fun(_x_, _y_) == 1:
                if _y_ == M - 1:
                    dfs(_x_ + 1, 0)
                else:
                    dfs(_x_, _y_ + 1)
        DATA[_x_][_y_] = 0  #回溯

4.文件的寫入讀出

for line in FP.readlines(): #讀出
    arr = line.strip().split(" ")
    if arr[0] >= '0':
        int_arr = list(map(int, arr))
        DATA.append(int_arr)
#分行讀出 每隔一個空格讀一個數  map函數用於將讀取到的內容轉int整型 保存成列表數組List
寫入有個write函數就完事了

5.命令行輸入

python命令行輸入用 import sys
 然后用sys.argv[x]數組輸入
sys.argv[0]表示的是你的py文件名   用sys.argv[1......]  按你輸入的順序賦值給你要的參數變量

命令行輸入圖片

性能改進


改進了定位模塊 上文有提到 實現3-9階九宮格都可以定位

心路歷程


一拿到題目的時候,我是拒絕的。彭琛老師發布的作業也太快了,媽媽再也不用擔心我手指不靈活了,媽媽再也不用擔心我會出門花錢了,媽媽再也不用擔心洗發水用的完了,這算法 題,我裂開,這怎么做,算法我學了啥。大一:彭琛老師教給我們冒泡排序法。大二:數據結構課上,冒泡排序法,我一氣呵成,老師說我這發量還不行。大三:算法課上,各種指針嵌套遞歸回溯,一到實驗課,冒泡排序法信手捏來。預測大四:《論冒泡排序法的基本思想》朱旭煒20177596.doc。其實沒有老師發布的作業,我真不會接觸算法這些東西,既然發布了,還是先端正下態度哈。完成代碼編寫的過程也是十分艱辛,在CSDN上也看了一些其他大佬的實現思路,結合作業的要求完成。

​ 關於《構建之法》:

下次我一定看! 滑稽

單元測試


import unittest

from sudoku import new_locate

class MyTestCase(unittest.TestCase):
    def test_fun(self):
        test_num=new_locate(5,8,0,0)
        self.assertEqual(test_num,(3,6,3,3))


if __name__ == '__main__':
    unittest.main()
#計算新定位模塊是否能正常計算出_a_,_b_,_c_,_r_

靜態檢測(工具:PyLint)


​ 剛完成的代碼那會,點pylint,出來好多啊,結合上次作業出現的問題總結下:

  1. 寫完代碼前,點擊Code - > Reformat Code, 在pycharm最上面那條找得到,這個效果是整理代碼,點完這個都能消除很多提醒和警告
  2. 變量命名的方法,提醒你大寫你就全大寫,提醒snake命名就寫成_name_ 像這樣的,當然我也不知道這樣規范不,請大佬教育下我
  3. def函數塊里面要寫注釋,這個提醒也太人性化了,怕別人看你的代碼時候看不懂,不然就C0116提醒了,這個搞了我好久,專門折磨我這種強迫症,類似的不寫注釋還有C0114,寫在最上面就好了,告訴別人你這整個代碼干嘛用的
  4. 還有就是要簡化 i f 判斷,特別是多個並列條件的判斷
  5. 還有減少else后面不必要的return ,不要寫else: 這樣的,第一個判斷里面有return的話,程序都出去了,沒必要再else:return return x
  6. 暫無其他問題了,以后碰到會繼續補充,也請大佬們指指點點下

總結


​ 雖然沒做過算法題,通過自己查資料,咨詢大佬后還是對問題的解答有所思路的,python挺好用的。希望彭琛老師發布作業的速度可以慢點,頂不住,早點開學吧,我太難了。

giao

大佬の指指點點


  • @不負真人:你這函數沒引入DATA可以直接操作DATA的值嗎?
def dfs(_x_, _y_):
    '''
    深搜
    :param _x_:
    :param _y_:
    :return:
    '''
#這里就相當於給沒填數字的格子 嘗試可能填的數
    if _x_ > M - 1:
        disp()
    elif DATA[_x_][_y_] != 0:  # < - 為啥能直接用?
        if _y_ == M - 1:
            dfs(_x_ + 1, 0)
        else:
            dfs(_x_, _y_ + 1)
    else:
        for _i_ in range(1, M + 1):
            DATA[_x_][_y_] = _i_  #從1到M 賦值嘗試
            if fun(_x_, _y_) == 1:
                if _y_ == M - 1:
                    dfs(_x_ + 1, 0)
                else:
                    dfs(_x_, _y_ + 1)
        DATA[_x_][_y_] = 0  #回溯

博主親自給這位爺查閱資料,尋找一些不會讓自己尷尬且強有力的論證,在python語言中:

  1. 在函數中對全局變量只是進行引用而不是進行修改時,不需要使用global關鍵字

  2. 修改全局變量,需要使用global聲明

  3. 列表、字典等如果只是修改其中元素的值,可以直接使用全局變量,不需要global聲明

    參考文獻:https://www.cnblogs.com/yymn/p/11299805.html

  • @不負真人:你這個定位m=5怎么辦?問題是你好像沒排除啊!沒排除這幾個情況!c和r都沒有不會報錯嗎?沒進到這里面,c和r沒有值啊?是沒有c和r吧,這會返回0?
def new_locate(_x_, _y_, _a_, _b_):  #上面的版本是學習小鄧同學的定位
    '''
    新版定位
    :param _x_:
    :param _y_:
    :return:
    '''
    if M % 3 == 0:   #通過向下取整計算出 大的九宮格能分成幾行幾列的小九宮格
        _c_ = 3
        _r_ = int(M / 3)
    elif M % 2 == 0:
        _c_ = 2
        _r_ = int(M / 2)
    _a_ = int(_x_ // _c_ * _c_)
    _b_ = int(_y_ // _r_ * _r_)c_:_r_
    return _a_, _b_, _c_, _r_   #這里返回 _a_: 當前元素所在的小九宮格 左上角的橫坐標
                               #         _b_: 當前元素所在的小九宮格 左上角的縱坐標
                               #         _c_: 大九宮格被分成了 c行 r列的小九宮格
                               #         _r_:

我:應該會返回0吧,你先試試。表面嘴硬,實則來一波單元測試。

import unittest
from sudoku import new_locate

class MyTestCase(unittest.TestCase):
    def test_something(self):
        test_num=new_locate(0,0,0,0)  #M=3 or 5 or 7
        self.assertEqual(test_num,(0,0,0,0) )


if __name__ == '__main__':
    unittest.main()

pytest: ZeroDivisionError: integer division or modulo by zero(你除0的樣子真下飯)

改進:

def new_locate(_x_, _y_, _a_, _b_):
    '''
    新版定位
    :param _x_:
    :param _y_:
    :return:
    '''
    _c_ = 0 #< - 提前賦值0
    _r_ = 0
    if 105 % M != 0:  這個里是如果M不等於3、5、7,根據題意不考慮
        if M % 3 == 0:
            _c_ = 3
            _r_ = int(M / 3)
        elif M % 2 == 0:
            _c_ = 2
            _r_ = int(M / 2)
        _a_ = int(_x_ // _c_ * _c_)
        _b_ = int(_y_ // _r_ * _r_)
    return _a_, _b_, _c_, _r_ 這里如果M=3 or 5 or 7,返回 0 0 0 0
  • @不負真人:你的不行,你怕是沒看題目要求吧!

image-20200321211332931

對比下我的:image-20200321211415597

img

我又開始上網沖浪,查閱資料image-20200321211900151

python命令行輸入,輸入參數時參數名做參數古被識別為參數做參數名 ???

還是改下吧

NAME_M = sys.argv[1]
NAME_N = sys.argv[3]
N = int(sys.argv[4])
M = int(sys.argv[2])
NAME_IN_FILE = sys.argv[5]
NAME_OUT_FILE = sys.argv[7]
IN_FILE = sys.argv[6]
OUT_FILE = sys.argv[8]


完事兒

參考文獻:https://www.cnblogs.com/ouyangpeng/p/8537616.html

感謝@不負真人大佬的指指點點

大佬:我是fw[1]

后期修改


def dfs(_x_, _y_):
    '''
    深搜
    :param _x_:
    :param _y_:
    :return:
    '''
    global F  #加入F判斷值  每個九宮格答案唯一  為最先找到得解答情況
    if _x_ > M - 1 and F == 0:
        disp()
        F = 1
    elif DATA[_x_][_y_] != 0:
        if _y_ == M - 1:
            dfs(_x_ + 1, 0)
        else:
            dfs(_x_, _y_ + 1)
    else:
        for _i_ in range(1, M + 1):
            DATA[_x_][_y_] = _i_
            if fun(_x_, _y_) == 1:
                if _y_ == M - 1:
                    dfs(_x_ + 1, 0)
                else:
                    dfs(_x_, _y_ + 1)
        DATA[_x_][_y_] = 0

for i in range(N):
    if i > 0:
        DATA[M * (i - 1):M * i - 1] = DATA[M * i:M * (i + 1)]
        print('')
        OP.write('\n')
    dfs(0, 0)
    F = 0  #在解答另外一個九宮格時 先初始化判斷值

各階宮格


3 × 3

image-20200328143008320

4 × 4

image-20200328143110983

5 × 5

image-20200328143222917

6 × 6

image-20200328143255130

7 × 7

image-20200328143327595

8 × 8

image-20200328143352792

9 × 9

image-20200328143426371

自評分


QQ截圖20200329163310

糾錯


    _c_ = 0
    _r_ = 0
    if 105 % M != 0:
        if M % 3 == 0:
            _r_ = 3             #<-行列混淆了 導致6,8階錯誤
            _c_ = int(M / 3)
        elif M % 2 == 0:
            _r_ = 2
            _c_ = int(M / 2)
        _a_ = int(_x_ // _c_ * _c_)
        _b_ = int(_y_ // _r_ * _r_)
    return _a_, _b_, _c_, _r_

改正后:

6 × 6

image-20200405142233745

8 × 8

image-20200405142149482


  1. 來自大佬的自嘲,自稱廢物。 ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM