The book's case study omits the checkrows function (and has some typos fixed below). The somewhat long program with all parts, and a test case, is given here. The length of the program (the example runs hundreds of steps) is such that stepper is not helpful to understanding how it works. One point of showing this, if you try stepping through part of it, is that generators hide the values and can make debugging more difficult.
An important lesson of the case study is that documentation is needed for this kind of program. Software should not be so complex, demanding that a user understand all the details in order to use the functions it has. It is quite difficult to understand or debug such code without an explanation of why it was done in this way, how to understand it, and how to use it.
def check3(seq): |
def grab3(k): |
return seq[k]+seq[k+1]+seq[k+2] |
m = len(seq) |
S = (grab3(i) for i in range(m-3)) |
A = (x in ("XXX","OOO") for x in S) |
return any(A) |
def checkrows(pos): |
n = len(pos) |
A = (check3(x) for x in pos) |
return any(A) |
def checkURdiags(pos): |
n = len(pos) |
def diag(k): |
return [ pos[i][i+k] for i in range(n-k)] |
D = (diag(k) for k in range(n-2)) |
A = (check3(e) for e in D) |
return any(A) |
def checkLLdiags(pos): |
n = len(pos) |
def diag(k): |
return [pos[i][i-k] for i in range(k,n)] |
D = (diag(k) for k in range(n-2)) |
A = (check3(e) for e in D) |
return any(A) |
def rotate(pos): |
n = len(pos) |
def row(k): |
return ''.join([pos[i][k] for i in range(n)]) |
newpos = [row(j) for j in range(n)] |
return newpos |
def winning(pos): |
rot = rotate(pos) |
R = [ f(pos) or f(rot) |
for f in (checkrows,checkURdiags,checkLLdiags) ] |
return any(R) |
CaseOne = ["XOOXO","OXOXX","XOXOX","OOXXX","OOOOO"] |
print winning(CaseOne) |