-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtic-tac-ai.py
199 lines (160 loc) · 5.19 KB
/
tic-tac-ai.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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# A tic-tac-toe game by Mark Edward Murray
#
# One player version with AI
def ask_to_play(human):
answer = raw_input("Shall we play a game? (y/n) ")
ai = ""
if human == "X":
human = "O"
ai = "X"
elif human == "O":
human = "X"
ai = "O"
if answer == "y":
new_game(human, ai)
def new_game(human, ai):
board = [ ["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"] ]
turn = "X"
print_board(board)
for counter in range(9):
if turn == human:
play_turn(turn, board)
elif turn == ai:
ai_turn(turn, board)
if check_for_win(turn, board) == True:
break
turn = switch_turns(turn)
print "The game is over."
ask_to_play(human)
def print_board(board):
for row in board:
print " ".join(row)
def switch_turns(turn):
if turn == "X":
turn = "O"
elif turn == "O":
turn = "X"
return turn
def get_valid_selection(turn, board):
valid_moves = set_valid_moves(board)
selection = raw_input("Turn: %s -- Select a tile to claim by entering 1 - 9: " % turn)
if selection in valid_moves:
return selection
else:
return get_valid_selection(turn, board)
def set_valid_moves(board):
valid_moves = []
for row in board:
for tile in row:
if tile != "X" and tile != "O":
valid_moves.append(tile)
return valid_moves
def play_turn(turn, board):
selection = get_valid_selection(turn, board)
for row in board:
if selection in row:
index = row.index(selection)
row[index] = turn
break
print_board(board)
def collect_victory_lines(board):
row1 = board[0]
row2 = board[1]
row3 = board[2]
col1 = [ board[0][0], board[1][0], board[2][0] ]
col2 = [ board[0][1], board[1][1], board[2][1] ]
col3 = [ board[0][2], board[1][2], board[2][2] ]
diag1 = [ board[0][0], board[1][1], board[2][2] ]
diag2 = [ board[0][2], board[1][1], board[2][0] ]
return [row1, row2, row3, col1, col2, col3, diag1, diag2]
def check_for_win(turn, board):
victory = [turn, turn, turn] # for everything, there is a season
victory_lines = collect_victory_lines(board)
for line in victory_lines:
if line == victory:
print "%s wins the game!" % turn
return True
# ai player functions
def ai_turn(turn, board):
selection = calculate_best_selection(turn, board)
valid_moves = set_valid_moves(board)
if selection not in valid_moves:
selection = valid_moves[0]
for row in board:
if selection in row:
index = row.index(selection)
row[index] = turn
break
print_board(board)
def determine_enemy(turn):
if turn == "X":
return "O"
elif turn == "O":
return "X"
def analyze_offense(turn, board):
enemy = determine_enemy(turn)
offense_values = { "1":0.0, "2":0.0, "3":0.0, "4":0.0, "5":0.0, "6":0.0, "7":0.0, "8":0.0, "9":0.0 }
victory_lines = collect_victory_lines(board)
for key in offense_values:
for line in victory_lines:
if key in line:
enemy_count = line.count(enemy)
self_count = line.count(turn)
if enemy in line:
offense_values[key] += 0.0
elif turn in line:
if enemy in line:
offense_values[key] += 0.0
elif self_count > 1:
offense_values[key] += 2.0
else:
offense_values[key] += 0.49
else:
offense_values[key] += 0.33
return offense_values
def analyze_defence(turn, board):
enemy = determine_enemy(turn)
defense_values = { "1":0.0, "2":0.0, "3":0.0, "4":0.0, "5":0.0, "6":0.0, "7":0.0, "8":0.0, "9":0.0 }
victory_lines = collect_victory_lines(board)
for key in defense_values:
for line in victory_lines:
if key in line:
enemy_count = line.count(enemy)
self_count = line.count(turn)
if enemy in line:
if turn in line:
defense_values[key] += 0.0
elif enemy_count == 2:
defense_values[key] += 0.99
elif enemy_count == 1:
defense_values[key] += 0.33
return defense_values
def print_analysis(offense, defense):
print " OFFENSE"
print " ".join("%.2f" % x for x in [offense["1"], offense["2"], offense["3"]])
print " ".join("%.2f" % x for x in [offense["4"], offense["5"], offense["6"]])
print " ".join("%.2f" % x for x in [offense["7"], offense["8"], offense["9"]])
print " DEFENSE"
print " ".join("%.2f" % x for x in [defense["1"], defense["2"], defense["3"]])
print " ".join("%.2f" % x for x in [defense["4"], defense["5"], defense["6"]])
print " ".join("%.2f" % x for x in [defense["7"], defense["8"], defense["9"]])
def calculate_best_selection(turn, board):
offense_values = analyze_offense(turn, board)
defense_values = analyze_defence(turn, board)
print_analysis(offense_values, defense_values)
best_selection = ""
best_selection_value = 0.0
for key in offense_values:
if offense_values[key] >= best_selection_value:
best_selection = key
best_selection_value = offense_values[key]
for key in defense_values:
if defense_values[key] >= best_selection_value:
best_selection = key
best_selection_value = defense_values[key]
print "selection: %s" % best_selection
print "value: %.2f" % best_selection_value
return best_selection
# main function call
human = "O"
ask_to_play(human)