board board or self board for row in boardif empty in rowreturn return none emptydraw or win def checkwin(selfmarkboard=none)board board or self board for row in boardif row count(mark=self degreereturn for col in range(self degree)for row in boardif row[col!markbreak elsereturn for row in range(self degree)col row if board[row][col!markbreak elsereturn for row in range(self degree)col (self degree- row if board[row][col!markbreak elsereturn check across check down check diag row =col check diag row+col degree- def checkfinish(self)if self checkwin(self usermark)outcome "you've won!elif self checkwin(self machinemark)outcome ' win again :-)elif self checkdraw()outcome 'looks like drawother move-selection code mostly just performs other kinds of analysis on the board data structure or generates new board states to search tree of moves and countermoves you'll also find relatives of these files in the same directory that implements alternative search and move-scoring schemesdifferent board representationsand so on for additional background on game scoring and searches in generalconsult an ai text it' fun stuffbut it' too specialized to cover well in this book where to go from here this concludes the gui section of this bookbut this is not an end to the book' gui coverage if you want to learn more about guisbe sure to see the tkinter examples that appear later in this book and are described at the start of this pymailguipycalcand the mostly external pyform and pytree provide additional gui case complete gui programs