# Text-based Tic Tac Toe with DRY and PEP-8

This is a basic Tic-Tac-Toe game with a minimal interface. The only concessions to ease of use are input validation (7 lines) and 1-indexed rows and columns (a few bytes). I've been trying to tighten it up while still maintaining readability and PEP-8 style.

I'm pretty happy with most of it, except for printing the board: I'd like to do it at the beginning, between each move, and at the end, but I don't see how to manage that without either repeating the formatted print() call or turning it into a function and calling it twice. As you can see, my current compromise omits the empty starting board in favor of the more interesting ending board.

This printing issue is my focus at the moment, but I'm also interested in any other suggestions for improvement.

board = [['*' for i in range(3)] for j in range(3)]

while True:
try:
x,y = map(int, input('\n> '))
if board[x-1][y-1] == '*':
board[x-1][y-1] = piece
else:
continue
except (ValueError, IndexError):
pass
else:
break
print('', *(' '.join(row) for row in board), sep='\n')
if ([piece] * 3 in board or
(piece,) * 3 in zip(*board) or
all(board[i][i] == piece for i in range(3)) or
all(board[i][2-i] == piece for i in range(3))):
print(piece, 'wins.')
return True
elif all(p!='*' for row in board for p in row):
print('Tie.')
return True

while True:
break


Input validation

Input validation is not really related to Tic-Tac-Toe, but is shared among all console programs.

The code to get the correct coordinates should be moved into a function in its own file to reuse it in the future and make the tic-tac-toe script even shorter.

Names

askmove does a complete turn, so I would call it: make_turn

Refactor

The check for the winning position is very much isolated from the rest of the program. I think the program would gain a lot of readibility if you wrote a is_won function.

I stared at it some more, and found a one-line DRY improvement:

if ([piece] * 3 in board or
(piece,) * 3 in zip(*board) or
all(board[i][i] == piece for i in range(3)) or
all(board[i][2-i] == piece for i in range(3))):
print(piece, 'wins.') # return removed
elif all(p!='*' for row in board for p in row):
print('Tie.') # return removed
else:
return True # invert condition; game now continues on True


Which led to a one-line LoC improvement:

while askmove('X') and askmove('O'):
pass


I had been trying for something like this:

    win condition:
return piece + ' wins'
tie condition:
return 'Tie.'


However, I couldn't figure out how to do it without spending a few lines on a wrapper function to give print() an exit code, and then import sys would need two lines too, so the above was the best I could manage.