summaryrefslogtreecommitdiff
path: root/tictactoe.py
blob: f6b2c7032ba66cd58e90e0245aad007d1fc37f58 (plain)
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
import random

board = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
wincombs = ((0, 1, 2), (3, 4, 5), (6, 7, 8), (0, 3, 6), (1, 4, 7), (2, 5, 8), (0, 4, 8), (2, 4, 6))
player1 = 'x'
player2 = 'o'

def render(board):
    print(f'''
 {board[0]} │ {board[1]} │ {board[2]} 
───┼───┼───
 {board[3]} │ {board[4]} │ {board[5]} 
───┼───┼───
 {board[6]} │ {board[7]} │ {board[8]}''')

def evaluate(board):
    for wincomb in wincombs:
        if board[wincomb[0]] == board[wincomb[1]] == board[wincomb[2]] == player1:
            return 1
        if board[wincomb[0]] == board[wincomb[1]] == board[wincomb[2]] == player2:
            return -1
    if all(cell in {player1, player2} for cell in board):
        return 0

def askmove(board):
    for _ in range(3):      # 3 attempts
        userinput = input('\nWhere do you want to place your x? > ')
        if userinput in {'1', '2', '3', '4', '5', '6', '7', '8', '9'}:
            idx = int(userinput) - 1
            if board[idx] not in {player1, player2}:
                return idx
        print('\nInvalid input')
        return askmove(board)
    exit(0)

def emptycells(board):
    for cell in board:
        if cell not in {player1, player2}:
            yield cell

def checkposition(board):
    eval = evaluate(board)
    if eval is not None:
        render(board)
        if eval == 0:
            print('\nDRAW\n')
        if eval == 1:
            print(f'\n{player1} won the game!\n')
        if eval == -1:
            print(f'\n{player2} won the game!\n')
        exit(0)

def minimax(board, ismax, alpha = -float('inf'), beta = float('inf')):

    eval = evaluate(board)
    if eval is not None:
        return eval
    
    if ismax:
        bestvalue = -float('inf')
        for cell in emptycells(board):
            idx = int(cell) - 1
            board[idx] = player1
            minimaxvalue = minimax(board, False, alpha, beta)
            board[idx] = cell
            if minimaxvalue > bestvalue:
                bestvalue = minimaxvalue
                alpha = max(alpha, bestvalue)
                if alpha >= beta:
                    break
    else:
        bestvalue = float('inf')
        for cell in emptycells(board):
            idx = int(cell) - 1
            board[idx] = player2
            minimaxvalue = minimax(board, True, alpha, beta)
            board[idx] = cell
            if minimaxvalue < bestvalue:
                bestvalue = minimaxvalue
                beta = min(beta, bestvalue)
                if alpha >= beta:
                    break
    return bestvalue

def bestmoves(board, ismax):
    bestmovelist = []
    if ismax:
        bestvalue = -float('inf')
        for cell in emptycells(board):
            idx = int(cell) - 1
            board[idx] = player1
            minimaxvalue = minimax(board, False)
            board[idx] = cell
            if minimaxvalue == bestvalue:
                bestmovelist.append(cell)
            elif minimaxvalue > bestvalue:
                bestvalue = minimaxvalue
                bestmovelist = [cell]
    else:
        bestvalue = float('inf')
        for cell in emptycells(board):
            idx = int(cell) - 1
            board[idx] = player2
            minimaxvalue = minimax(board, True)
            board[idx] = cell
            if minimaxvalue == bestvalue:
                bestmovelist.append(cell)
            elif minimaxvalue < bestvalue:
                bestvalue = minimaxvalue
                bestmovelist = [cell]
    return bestmovelist
    
import time

if __name__ == '__main__':
    while True:
        starttime = time.time()
        bestmoves_list = bestmoves(board, False)
        computermove = random.choice(bestmoves_list)
        exectime = time.time() - starttime
        print('exectime >', exectime)
        input()
        render(board)
        usermove = askmove(board)
        board[usermove] = player1
        checkposition(board)
        bestmoves_list = bestmoves(board, False)
        computermove = random.choice(bestmoves_list)
        idx = int(computermove) - 1
        board[idx] = player2
        checkposition(board)