Download
""" Tic Tac Toe game on Python for Series 60 platform (needs version 1.1.3) Jean-Claude Rimbault (pynokio.org, 2005) """ import random import appuifw, e32 from key_codes import * # constants # row evaluation constants depending on neighbours colors # XO 4 0 # X. 1 3 # .. 0 10 # O. 3 30 # XX 2 100 # OO 6 300 rates = (10, 3, 100, 30, 0, 0, 300) # neighbours squares for each position on the grid neighbours = [ [('23','59','47'),('13','58'),('12','57','69')], [('17','56'),('19','28','37','46'),('45','39')], [('14','53','89'),('79','52'),('78','51','36')] ] # variables grid = [ ['1','2','3'], ['4','5','6'], ['7','8','9'], ] player = ['X', 'O'] # X = human, O = computer input = -1 cx = cy = 0 aborted = '' # subroutines def setup(): """ Symbian Series 60 UI setup """ global canvas, old_body, old_screen old_body = appuifw.app.body old_screen = appuifw.app.screen appuifw.app.screen = 'full' canvas = appuifw.Canvas() appuifw.app.body = canvas appuifw.app.exit_key_handler = quit canvas.draw = display canvas.bind(EKeyRightArrow, lambda: cursor(1,0)) canvas.bind(EKeyUpArrow, lambda: cursor(0,-1)) canvas.bind(EKeyLeftArrow, lambda: cursor(-1,0)) canvas.bind(EKeyDownArrow, lambda: cursor(0,1)) canvas.bind(EKeySelect, enter) def cleanup(): """ restore saved objects """ appuifw.app.body = old_body appuifw.app.screen = old_screen def quit(): """ abort game loop """ global aborted aborted = '*' def enter(): """ select square under cursor """ global input input = cx+cy*3+1 def cursor(dx, dy): """ cursor movement """ global cx, cy cx += dx cy += dy if cx < 0: cx = 0 elif cx > 2: cx = 2 if cy < 0: cy = 0 elif cy > 2: cy = 2 def display(): """ game board display """ canvas.line((12,77,162,77), 0x000000, width=4) canvas.line((12,127,162,127), 0x000000, width=4) canvas.line((62,27,62,177), 0x000000, width=4) canvas.line((112,27,112,177), 0x000000, width=4) for line in range(3): for column in range(3): x1 = column * 50 + 18 y1 = line * 50 + 33 x2 = x1 + 40 y2 = y1 + 40 canvas.rectangle((x1,y1,x2,y2), fill=0xffffff) piece = grid[line][column] if piece == 'X': canvas.line((x1,y1,x2,y2), 0x00ff00, width=4) canvas.line((x2,y1,x1,y2), 0x00ff00, width=4) elif piece == 'O': canvas.ellipse((x1,y1,x2,y2), 0xff0000, width=4) if cx == column and cy == line: canvas.rectangle((x1,y1,x2,y2), 0x0000ff) def best(possible): """ use a static evaluation function to choose a move (not perfect) """ bestrate = 0 bestmove = 0 for move in possible: line, column = divmod(move-1, 3) rate = 0 for row in neighbours[line][column]: total = 0 for square in row: line, column = divmod(int(square)-1, 3) color = grid[line][column] if color == 'X': total += 1 elif color == 'O': total += 3 rate += rates[total] if rate > bestrate: bestmove = move bestrate = rate return bestmove def play(): """ choose and play one move """ global input move = 0 if player[0] == 'X': # human if input: move = input input = 0 else: # computer possible = [] # list all possible moves for move in range(1, 10): line, column = divmod(move-1, 3) if grid[line][column] not in player: possible.append(move) if not possible: # grid is full quit() return else: #move = random.choice(possible) # random play move = best(possible) # choose the best move if 1 <= move <= 9: line, column = divmod(move-1, 3) if grid[line][column] in player: # square already occupied? appuifw.note(u"Invalid move!'", 'info') else: grid[line][column] = player[0] player[0], player[1] = player[1], player[0] # swap players def finished(): """ check for game end """ if grid[0][0] == grid[0][1] == grid[0][2]: return grid[0][0] if grid[1][0] == grid[1][1] == grid[1][2]: return grid[1][0] if grid[2][0] == grid[2][1] == grid[2][2]: return grid[2][0] if grid[0][0] == grid[1][0] == grid[2][0]: return grid[0][0] if grid[0][1] == grid[1][1] == grid[2][1]: return grid[0][1] if grid[0][2] == grid[1][2] == grid[2][2]: return grid[0][2] if grid[0][0] == grid[1][1] == grid[2][2]: return grid[0][0] if grid[2][0] == grid[1][1] == grid[0][2]: return grid[2][0] return aborted def game(): """ game """ for square in range(1, 10): row, col = divmod(square-1, 3) grid[row][col] = str(square) while not finished(): display() play() e32.ao_sleep(0.08) display() winner = finished() if winner == '*': appuifw.note(u"Draw!", 'info') else: appuifw.note(u"%s wins!'" % winner, 'info') # main program setup() playing = 1 while playing: game() playing = appuifw.query(u'Play again?','query') cleanup()