/code/blog

Code, code and code

Functionally Programming Tic Tac Toe

I am a novice functional programmer. So if you find any areas of suggested improvement on my FP skills, do add a comment below. Below is a sample Tic Tac Toe written using Functional Programming constructs (or at least whatever I understood about them). Right now, I’ve implemented only a simple player who basically marks off a cell randomly. It should be possible to define more intelligent players similarly. Hopefully all the comments in the code should be sufficiently self explanatory.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import random
import functools
import itertools
import copy

def row_gen(board):
    """ 
    Generator which returns tuples of tuples. 
    The outer tuple represents a row.
    The inner tuple represents each cell with 
    its coordinates and data 
    """
    return (
        tuple((row,col,board[row][col])
              for col in range(3))
        for row in range(3))

def col_gen(board):
    """ 
    Generator which returns tuples of tuples. 
    The outer tuple represents a column.
    The inner tuple represents each cell with 
    its coordinates and data 
    """
    return (
        tuple((row,col,board[row][col])
              for row in range(3))
        for col in range(3))

def dia_gen(board):
    """ 
    Generator which returns two tuples of tuples. 
    The outer tuple represents a diagonal.
    The inner tuple represents each cell with 
    its coordinates and data 
    """
    return (
        tuple((i,i,board[i][i]) for i in range(3)),
        tuple((i,2-i,board[i][2-i]) for i in range(3)))

def empty(board):
    """ Gets a list of all empty cells on the board """
    return (
        (row,col)
        for row in range(3)
            for col in range(3)
                if board[row][col] == None)

def is_empty(board):
    """ checks if any cell on the board is still empty """
    for row in range(3) :
        for col in range(3) :
            if board[row][col] is None :
                return False
    return True

def random_player(chr,board):
    """Represents a player who randomly marks his next move """
    empty_cells = list(empty(board))
    play = empty_cells[random.randint(0,len(empty_cells)-1)]
    board = copy.copy(board)
    board[play[0]][play[1]] = chr
    return board

def show(board):
    """ Shows the current representation of the board """
    print '+-+-+-+'
    for row in range(3) :
        print '|%s|' % '|'.join(
            board[row][col]if board[row][col] is not None else ' '
            for col in range(3))
        print '+-+-+-+'

if __name__ == '__main__' :
    # Initialise the board with all values set to None       
    board = list(list(None for i in range(3)) for j in range(3))
    show(board)

    # Initialise the two players. Each is given a separate char
    player1 = functools.partial(random_player,'X')
    player2 = functools.partial(random_player,'O')

    # Setup an iterator to continuously cycle through both players
    players = itertools.cycle((player1,player2))

    # Play game
    over = False
    while not over and not is_empty(board) :
        # Ask the next player to make his move
        board = players.next()(board)
        show(board)

        # Note a cell bag set is all rows, 
        # all cols and all diagonals
        for cell_bag_set in (
                row_gen(board),
                col_gen(board),
                dia_gen(board)) :

            # Note a cell_bag can be a row, column or a dia
            for cell_bag in cell_bag_set :
                vals = set(val[2] for val in cell_bag)
                if len(vals) == 1 and  \
                        vals.__iter__().next() is not None :
                    over = True
                    print 'Over'
                    break

Comments