2020软件工程作业03
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 |
思路描述
审题
- 按照数独游戏的规定,给一张含有若干的数字随机分布在网格的图,在每个位置上的数在列和行上不能重复出现,在4、6、8、9阶的数独表中,每个小宫格内不能有重复的数出现。
- 用cmd命令行的形式读出写入文件,并传入参数。
- 要实现多个九宫格一起处理,且解答情况唯一。
- 要求用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,出来好多啊,结合上次作业出现的问题总结下:
- 写完代码前,点击Code - > Reformat Code, 在pycharm最上面那条找得到,这个效果是整理代码,点完这个都能消除很多提醒和警告
- 变量命名的方法,提醒你大写你就全大写,提醒snake命名就写成_name_ 像这样的,当然我也不知道这样规范不,请大佬教育下我
- def函数块里面要写注释,这个提醒也太人性化了,怕别人看你的代码时候看不懂,不然就C0116提醒了,这个搞了我好久,专门折磨我这种强迫症,类似的不写注释还有C0114,写在最上面就好了,告诉别人你这整个代码干嘛用的
- 还有就是要简化 i f 判断,特别是多个并列条件的判断
- 还有减少else后面不必要的return ,不要写else: 这样的,第一个判断里面有return的话,程序都出去了,没必要再else:return return x
- 暂无其他问题了,以后碰到会继续补充,也请大佬们指指点点下
总结
虽然没做过算法题,通过自己查资料,咨询大佬后还是对问题的解答有所思路的,python挺好用的。希望彭琛老师发布作业的速度可以慢点,顶不住,早点开学吧,我太难了。
大佬の指指点点
- @不负真人:你这函数没引入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语言中:
-
在函数中对全局变量只是进行引用而不是进行修改时,不需要使用global关键字
-
修改全局变量,需要使用global声明
-
列表、字典等如果只是修改其中元素的值,可以直接使用全局变量,不需要global声明
- @不负真人:你这个定位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
- @不负真人:你的不行,你怕是没看题目要求吧!
对比下我的:
我又开始上网冲浪,查阅资料
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
4 × 4
5 × 5
6 × 6
7 × 7
8 × 8
9 × 9
自评分
纠错
_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
8 × 8
来自大佬的自嘲,自称废物。 ↩︎