4.43: Why Bother With Readability?
- Page ID
- 14489
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)A lot of the suggestions in this chapter haven’t been about how to write programs that computers can run so much as how to write programs that programmers can read. You might not understand why this is important. After all, as long as the code works, who cares if it is hard or easy for human programmers to read?
However, the important thing to realize about software is that it is rarely ever left alone. When you are creating your own games, you will rarely be "done" with the program. You will always get new ideas for game features you want add, or find new bugs with the program. Because of this, it is important that your program is readable so that you can look at the code and understand it. And understanding the code is the first step to changing it to add more code or fix bugs.
As an example, here is an obfuscated version of the Memory Puzzle program that was made entirely unreadable. If you type it in (or download it from http://invpy.com/memorypuzzle_obfuscated.py) and run it you will find it runs exactly the same as the code at the beginning of this chapter. But if there was a bug with this code, it would be impossible to read the code and understand what’s going on, much less fix the bug.
The computer doesn’t mind code as unreadable as this. It’s all the same to it.
import random, pygame, sys from pygame.locals import * def hhh(): global a, b pygame.init() a = pygame.time.Clock() b = pygame.display.set_mode((640, 480)) j = 0 k = 0 pygame.display.set_caption('Memory Game') i = c() hh = d(False) h = None b.fill((60, 60, 100)) g(i) while True: e = False b.fill((60, 60, 100)) f(i, hh) for eee in pygame.event.get(): if eee.type == QUIT or (eee.type == KEYUP and eee.key == K_ESCAPE): pygame.quit() sys.exit() elif eee.type == MOUSEMOTION: j, k = eee.pos elif eee.type == MOUSEBUTTONUP: j, k = eee.pos e = True bb, ee = m(j, k) if bb != None and ee != None: if not hh[bb][ee]: n(bb, ee) if not hh[bb][ee] and e: o(i, [(bb, ee)]) hh[bb][ee] = True if h == None: h = (bb, ee) else: q, fff = s(i, h[0], h[1]) r, ggg = s(i, bb, ee) if q != r or fff != ggg: pygame.time.wait(1000) p(i, [(h[0], h[1]), (bb, ee)]) hh[h[0]][h[1]] = False hh[bb][ee] = False elif ii(hh): jj(i) pygame.time.wait(2000) i = c() hh = d(False) f(i, hh) pygame.display.update() pygame.time.wait(1000) g(i) h = None pygame.display.update() a.tick(30) def d(ccc): hh = [] for i in range(10): hh.append([ccc] * 7) return hh def c(): rr = [] for tt in ((255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0), (255, 128, 0), (255, 0, 255), (0, 255, 255)): for ss in ('a', 'b', 'c', 'd', 'e'): rr.append( (ss, tt) ) random.shuffle(rr) rr = rr[:35] * 2 random.shuffle(rr) bbb = [] for x in range(10): v = [] for y in range(7): v.append(rr[0]) del rr[0] bbb.append(v) return bbb def t(vv, uu): ww = [] for i in range(0, len(uu), vv): ww.append(uu[i:i + vv]) return ww def aa(bb, ee): return (bb * 50 + 70, ee * 50 + 65) def m(x, y): for bb in range(10): for ee in range(7): oo, ddd = aa(bb, ee) aaa = pygame.Rect(oo, ddd, 40, 40) if aaa.collidepoint(x, y): return (bb, ee) return (None, None) def w(ss, tt, bb, ee): oo, ddd = aa(bb, ee) if ss == 'a': pygame.draw.circle(b, tt, (oo + 20, ddd + 20), 15) pygame.draw.circle(b, (60, 60, 100), (oo + 20, ddd + 20), 5) elif ss == 'b': pygame.draw.rect(b, tt, (oo + 10, ddd + 10, 20, 20)) elif ss == 'c': pygame.draw.polygon(b, tt, ((oo + 20, ddd), (oo + 40 - 1, ddd + 20), (oo + 20, ddd + 40 - 1), (oo, ddd + 20))) elif ss == 'd': for i in range(0, 40, 4): pygame.draw.line(b, tt, (oo, ddd + i), (oo + i, ddd)) pygame.draw.line(b, tt, (oo + i, ddd + 39), (oo + 39, ddd + i)) elif ss == 'e': pygame.draw.ellipse(b, tt, (oo, ddd + 10, 40, 20)) def s(bbb, bb, ee): return bbb[bb][ee][0], bbb[bb][ee][1] def dd(bbb, boxes, gg): for box in boxes: oo, ddd = aa(box[0], box[1]) pygame.draw.rect(b, (60, 60, 100), (oo, ddd, 40, 40)) ss, tt = s(bbb, box[0], box[1]) w(ss, tt, box[0], box[1]) if gg > 0: pygame.draw.rect(b, (255, 255, 255), (oo, ddd, gg, 40)) pygame.display.update() a.tick(30) def o(bbb, cc): for gg in range(40, (-8) - 1, -8): dd(bbb, cc, gg) def p(bbb, ff): for gg in range(0, 48, 8): dd(bbb, ff, gg) def f(bbb, pp): for bb in range(10): for ee in range(7): oo, ddd = aa(bb, ee) if not pp[bb][ee]: pygame.draw.rect(b, (255, 255, 255), (oo, ddd, 40, 40)) else: ss, tt = s(bbb, bb, ee) w(ss, tt, bb, ee) def n(bb, ee): oo, ddd = aa(bb, ee) pygame.draw.rect(b, (0, 0, 255), (oo - 5, ddd - 5, 50, 50), 4) def g(bbb): mm = d(False) boxes = [] for x in range(10): for y in range(7): boxes.append( (x, y) ) random.shuffle(boxes) kk = t(8, boxes) f(bbb, mm) for nn in kk: o(bbb, nn) p(bbb, nn) def jj(bbb): mm = d(True) tt1 = (100, 100, 100) tt2 = (60, 60, 100) for i in range(13): tt1, tt2 = tt2, tt1 b.fill(tt1) f(bbb, mm) pygame.display.update() pygame.time.wait(300) def ii(hh): for i in hh: if False in i: return False return True if __name__ == '__main__': hhh()
Never write code like this. If you program like this while facing the mirror in a bathroom with the lights turned off, the ghost of Ada Lovelace will come out of the mirror and throw you into the jaws of a Jacquard loom.