-
Notifications
You must be signed in to change notification settings - Fork 0
/
game_logic.py
170 lines (129 loc) · 5.7 KB
/
game_logic.py
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import pygame
from tiles import *
import time
player, ai = "O", "X"
board = [".", ".", ".",
".", ".", ".",
".", ".", "."]
def generate_board(window, side):
# -- generate tiles --
tile_group = pygame.sprite.Group()
key = 0
for i in range(0, 3):
for j in range(0, 3):
tile_group.add(Tile([j, i], window, key, side, 0.3))
key += 1
return tile_group
def fill_board(tile_group):
# fill tiles
for i in range(len(tile_group.sprites())):
tile_group.sprites()[i].state = board[i]
def check_if_won(board):
winning = [[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]]
o_won = False
x_won = False
for line in winning:
if board[line[0]] == board[line[1]] and \
board[line[1]] == board[line[2]] and \
board[line[2]] == "O":
o_won = True
if board[line[0]] == board[line[1]] and \
board[line[1]] == board[line[2]] and \
board[line[2]] == "X":
x_won = True
# if there is no winnner
if not(o_won or x_won):
# if a blank space is found draw = False
draw = True
for tile in board:
if tile == ".":
draw = False
else:
draw = False
return o_won, x_won, draw
def static_evaluation(board, depth, number_of_boards_considered, list_of_boards_considered):
o_won, x_won, draw = check_if_won(board)
if draw:
return 0, number_of_boards_considered, list_of_boards_considered
if o_won:
return (20 - depth), number_of_boards_considered, list_of_boards_considered
if x_won:
return (-20 + depth), number_of_boards_considered, list_of_boards_considered
else:
# still moves left to play
return None
def minimax(board, depth, isMax, max_id, min_id, number_of_boards_considered, list_of_boards_considered, alpha, beta):
# if no moves are left to check
if static_evaluation(board, depth, number_of_boards_considered, list_of_boards_considered) != None:
return static_evaluation(board, depth, number_of_boards_considered, list_of_boards_considered)
list_of_boards_considered.append(board)
# if we are simulating what a player maximising the evaluation would do
if isMax:
# set a worst case for this player
currentMaxEval = -9999
# check all legal moves
for i in range(len(board)):
if board[i] == ".":
# analyse moves on a test board
analysis_board = board.copy()
analysis_board[i] = max_id
number_of_boards_considered += 1
list_of_boards_considered.append(analysis_board)
evaluation, number_of_boards_considered, list_of_boards_considered = minimax(analysis_board, depth+1, False, max_id, min_id, number_of_boards_considered, list_of_boards_considered, alpha, beta)
currentMaxEval = max(evaluation, currentMaxEval)
alpha = max(alpha, evaluation)
if beta <= alpha:
break
return currentMaxEval, number_of_boards_considered, list_of_boards_considered
# if we are simulating what a player minimising the evaluation would do
if not isMax:
# set a worst case for this player
currentMinEval = 9999
# check all legal moves
for i in range(len(board)):
if board[i] == ".":
# analyse moves on a test board
analysis_board = board.copy()
analysis_board[i] = min_id
number_of_boards_considered += 1
list_of_boards_considered.append(analysis_board)
evaluation, number_of_boards_considered, list_of_boards_considered = minimax(analysis_board, depth+1, True, max_id, min_id, number_of_boards_considered, list_of_boards_considered, alpha, beta)
currentMinEval = min(evaluation, currentMinEval)
beta = min(beta, evaluation)
if beta <= alpha:
break
return currentMinEval, number_of_boards_considered, list_of_boards_considered
def find_computer_move(board, ai, player, number_of_boards_considered, list_of_boards_considered):
# ai tries to minimise the evaluation
currentEval = 9999
tile_eval_for_display = []
# for every empty move
for i in range(len(board)):
if board[i] == ".":
# make a test move on an analysis board
analysis_board = board.copy()
analysis_board[i] = ai
number_of_boards_considered += 1
list_of_boards_considered.append(analysis_board)
alpha = -999999
beta = 9999999
# see if its good, check how the human (maximising player) may respond
evaluation, number_of_boards_considered, list_of_boards_considered = minimax(analysis_board, 0, True, player, ai, number_of_boards_considered, list_of_boards_considered, alpha, beta)
tile_eval_for_display.append(evaluation)
if evaluation < currentEval:
bestMove = i
currentEval = evaluation
else:
tile_eval_for_display.append("_")
return bestMove, number_of_boards_considered, list_of_boards_considered, tile_eval_for_display
def flash_tiles(board_list, group):
# set the state of the board
for i in range(len(board_list)):
group.sprites()[i].state = board_list[i]