个人项目任务和要求
Github项目地址
https://github.com/richardevan/sudokugame
PSP 表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | ||
Estimate | 估计这个任务需要多少时间 | 40 | 50 |
Development | 开发 | ||
Analysis | 需求分析(包括学习新技术) | 70 | 70 |
Design Spec | 生成射进文档 | 60 | 60 |
Design Review | 设计复审(和同事审核设计文档) | 20 | 30 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 40 |
Design | 具体设计 | 70 | 80 |
Coding | 具体编码 | 1400 | 1500 |
Code Review | 代码复审 | 180 | 190 |
Test | 测试(自我测试,修改代码,提交修改) | 200 | 200 |
Reporting | 报告 | ||
Test Report | 测试报告 | 80 | 100 |
Size Measurement | 计算工作量 | 40 | 40 |
Postmortem & Process Improvement Plan | 事后总结,并提出过程进计划 | 40 | 40 |
合计 | 2220 | 2400 |
解题思路
数独横九竖九共八十一个格子,同时又分为9个九宫格。规则很简单——需要每一个格中的数字,都保证与其所在横排和竖排以及九宫格内无相同数字。所以我们的大概思路就是,从第一个空格开始试着填数,从 1 开始填,如果 1 不满足横排竖排九宫格无重复的话,就再填入 2 ,以此类推,直到填入一个暂时满足规则的数,中断此格,移动到下一个空格重复这个过程。如果到达某个空格发现已经无数可选了,说明前面某一格填错了,那就返回上一格,从上一格的中断处继续往 9 尝试,直到这样回朔到填错的那一格。
这样的话,我们就可以整理出重要的步骤了:
1. 画一个空白的屏幕格式
def canvas_click(self, event): print("Click! (%d,%d)" % (event.x, event.y)) self.canvas.focus_set() rsize = 512/9 (x, y) = (0, 0) if event.x > rsize: x = int(event.x/rsize) if event.y > rsize: y = int(event.y/rsize) print(x, y) if self.current: (tx, ty) = self.current # self.canvas.itemconfig(self.handles[ty][tx][0], # fill=rgb(128,128,128)) self.current = (x, y) def canvas_key(self, event): print("Clack! (%s)" % (event.char)) if event.char.isdigit() and int(event.char) > 0 and self.current: (x, y) = self.current # self.canvas.itemconfig(self.handles[y][x][0], # fill=rgb(128,128,128)) try: self.board.set(x, y, int(event.char)) self.sync_board_and_canvas() except ValueError: pass
2. 在屏幕上画一个网格
def make_grid(self): c = Canvas(self, bg=rgb(128, 128, 128), width='512', height='512') c.pack(side='top', fill='both', expand='1') self.rects = [[None for x in range(9)] for y in range(9)] self.handles = [[None for x in range(9)] for y in range(9)] rsize = 512/9 guidesize = 512/3 for y in range(9): for x in range(9): (xr, yr) = (x*guidesize, y*guidesize) self.rects[y][x] = c.create_rectangle(xr, yr, xr+guidesize, yr+guidesize, width=3) (xr, yr) = (x*rsize, y*rsize) r = c.create_rectangle(xr, yr, xr+rsize, yr+rsize) t = c.create_text(xr+rsize/2, yr+rsize/2, text="SUDO", font="System 15 bold") self.handles[y][x] = (r, t) self.canvas = c self.sync_board_and_canvas()
然后别忘了配合空白的屏幕和网格。
def sync_board_and_canvas(self): g = self.board.grid for y in range(9): for x in range(9): if g[y][x] != 0: self.canvas.itemconfig(self.handles[y][x][1], text=str(g[y][x])) else: self.canvas.itemconfig(self.handles[y][x][1],
text='')
还有做小的网格。
def clear(self): self.grid = [[0 for x in range(9)] for y in range(9)] self.locked = [] def get_row(self, row): return self.grid[row] def get_cols(self, col): return [y[col] for y in self.grid] def get_nearest_region(self, col, row): """Regions are 3x3 sections of the grid.""" def make_index(v): if v <= 2: return 0 elif v <= 5: return 3 else: return 6 return [y[make_index(col):make_index(col)+3] for y in self.grid[make_index(row):make_index(row)+3]] def set(self, col, row, v, lock=False): if v == self.grid[row][col] or (col, row) in self.locked: return for v2 in self.get_row(row): if v == v2: raise ValueError() for v2 in self.get_cols(col): if v == v2: raise ValueError() for y in self.get_nearest_region(col, row): for x in y: if v == x: raise ValueError() self.grid[row][col] = v if lock: self.locked.append((col, row)) def get(self, col, row): return self.grid[row][col]
3. 轮流填入格中数字 1 到 9,还有 递归判断填入数是否符合规则
def sudogen_1(board): """Algorithm: enter a random number between 1-9 to each
subgrid in the board, don't enter a duplicate random numbers.""" board.clear() added = [0] for y in range(0, 9, 3): for x in range(0, 9, 3): if len(added) == 10: return i = 0 while i in added: i = random.randint(1, 9) try: board.set(random.randint(x, x+2), random.randint(y, y+2), i, lock=True) except ValueError: print("Board rule violation, this shouldn't happen!") added.append(i)
对于不知道游戏或玩游戏的玩家,您可以先阅读游戏介绍。打开这个链接: https://en.wikipedia.org/wiki/Sudoku。
性能优化
1. 单元测试
2. 覆盖率测试
ncalls =为调用的数量。
tottime =花在给定函数的总时间(不包括时间在调用子函数)。
percall(1) =商tottime除以ncalls。
cumtime =累计时间花在这和所有子功能(从调用到出口)。这个数字即使是递归函数也是精确的。
percall(2) =商cumtime除以原始调用。
文件名:株(功能)=提供每个函数的相应数据。
小结
这次个人项目对我来说有点麻烦。因为用python的能力没那么厉害。本来,我想用C语言来完成作业。但是用C语言看起来很麻烦,很复杂,需要很长时间完成的,所以我换了一个语言就是python。用python完成作业后,我python的能力提高了。我也得到很多知识。希望这些知识能在以后帮助我。