mirror of
https://github.com/Rushilwiz/AI.git
synced 2025-04-16 09:00:18 -04:00
197 lines
6.0 KiB
Python
197 lines
6.0 KiB
Python
# Name: Rushil Umaretiya
|
|
# Date: 1/18/21
|
|
|
|
import random
|
|
|
|
class RandomBot:
|
|
def __init__(self):
|
|
self.yellow = "O"
|
|
self.red = "X"
|
|
self.directions = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]
|
|
self.opposite_color = {self.red: self.yellow, self.yellow: self.red}
|
|
self.x_max = None
|
|
self.y_max = None
|
|
|
|
def __str__(self):
|
|
return "Random Bot"
|
|
|
|
def best_strategy(self, board, color):
|
|
# returns best move
|
|
self.x_max = len(board)
|
|
self.y_max = len(board[0])
|
|
if color == "#ffff00":
|
|
color = "O"
|
|
else:
|
|
color = "X"
|
|
|
|
best_move = random.choice(self.find_moves(board, color))
|
|
|
|
return best_move, 0
|
|
|
|
def find_moves(self, board, color):
|
|
moves_found = []
|
|
for col in range(self.x_max):
|
|
for row in reversed(range(self.y_max)):
|
|
if board[col][row] == '.':
|
|
moves_found.append([col, row])
|
|
break
|
|
return moves_found
|
|
|
|
class SmartBot:
|
|
|
|
def __init__(self):
|
|
self.yellow = "O"
|
|
self.red = "X"
|
|
self.directions = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]
|
|
self.opposite_color = {self.red: self.yellow, self.yellow: self.red}
|
|
self.x_max = None
|
|
self.y_max = None
|
|
self.color = None
|
|
|
|
def __str__(self):
|
|
return "Smart Bot"
|
|
|
|
def best_strategy(self, board, color):
|
|
# returns best move
|
|
self.x_max = len(board)
|
|
self.y_max = len(board[0])
|
|
|
|
if color == "#ffff00":
|
|
color = "O"
|
|
else:
|
|
color = "X"
|
|
self.color = color
|
|
|
|
sd = 4
|
|
v, best_move = self.alphabeta(board, color, sd, -9999999999, 9999999999) # returns state
|
|
|
|
return best_move, v
|
|
|
|
def alphabeta(self, board, color, search_depth, alpha, beta, last_move = -1):
|
|
terminal_test = self.terminal_test(board, color)
|
|
if search_depth <= 0 or terminal_test:
|
|
if terminal_test:
|
|
if color == self.color:
|
|
return 99999999, last_move
|
|
else:
|
|
return -99999999, last_move
|
|
heuristic = self.evaluate(board, color)
|
|
return heuristic, 0
|
|
|
|
if search_depth % 2 == 0:
|
|
v = -9999999999
|
|
result = None
|
|
for move in self.find_moves(board, color):
|
|
max_val, max_state = self.alphabeta(self.make_move(board, color, move), self.opposite_color[color], search_depth - 1, alpha, beta, move)
|
|
if max_val > v:
|
|
v = max_val
|
|
result = move
|
|
if v > beta:
|
|
return v, result
|
|
alpha = max(alpha, v)
|
|
return v, result
|
|
else:
|
|
v = 9999999999
|
|
result = None
|
|
for move in self.find_moves(board, color):
|
|
min_val, min_state = self.alphabeta(self.make_move(board, color, move), self.opposite_color[color], search_depth - 1, alpha, beta, move)
|
|
if min_val < v:
|
|
v = min_val
|
|
result = move
|
|
if v < alpha:
|
|
return v, result
|
|
beta = min(beta, v)
|
|
return v, result
|
|
|
|
def minimax(self, board, color, search_depth):
|
|
# returns best "value"
|
|
return 1
|
|
|
|
def negamax(self, board, color, search_depth):
|
|
# returns best "value"
|
|
return 1
|
|
|
|
def make_move(self, board, color, move):
|
|
my_board = [row[:] for row in board]
|
|
|
|
my_board[move[0]][move[1]] = color
|
|
|
|
return my_board
|
|
|
|
def terminal_test(self, board, color):
|
|
for col in range(len(board)):
|
|
for row in range(len(board[col])):
|
|
if board[col][row] == color:
|
|
for direction in self.directions:
|
|
x_pos = col
|
|
y_pos = row
|
|
row_count = 0
|
|
while 0 <= x_pos < self.x_max and 0 <= y_pos < self.y_max:
|
|
if board[x_pos][y_pos] == color:
|
|
row_count += 1
|
|
if row_count == 4: return True
|
|
else:
|
|
break
|
|
x_pos += direction[0]
|
|
y_pos += direction[1]
|
|
return False
|
|
|
|
def evaluate(self, board, color):
|
|
heuristic = 0
|
|
|
|
# Center Column
|
|
center_array = [i for i in board[self.x_max // 2]]
|
|
center_heuristic = center_array.count(color)
|
|
heuristic += center_heuristic * 3
|
|
|
|
# Columns
|
|
for col in range(self.x_max):
|
|
col_array = [i for i in board[col]]
|
|
for row in range(self.y_max - 3):
|
|
array = col_array[row : row + 4]
|
|
heuristic += self.evaluate_array(array, color)
|
|
|
|
# Rows
|
|
for row in range(self.y_max):
|
|
row_array = [i[row] for i in board]
|
|
for col in range(self.x_max - 3):
|
|
array = row_array[col : col + 4]
|
|
heuristic += self.evaluate_array(array, color)
|
|
|
|
# Diagonals
|
|
for col in range(self.x_max - 3):
|
|
for row in range(self.y_max - 3):
|
|
array = [board[col + i][row + 1] for i in range(4)]
|
|
heuristic += self.evaluate_array(array, color)
|
|
|
|
for col in range(self.x_max - 3):
|
|
for row in range(self.y_max - 3):
|
|
array = [board[col + 3 - i][row + i] for i in range(4)]
|
|
heuristic += self.evaluate_array(array, color)
|
|
|
|
return heuristic
|
|
|
|
def evaluate_array(self, array, color):
|
|
heuristic = 0
|
|
opposite_color = self.opposite_color[color]
|
|
|
|
if array.count(color) == 4:
|
|
heuristic += 999
|
|
elif array.count(color) == 3 and array.count('.') == 1:
|
|
heuristic += 5
|
|
elif array.count(color) == 2 and array.count('.') == 2:
|
|
heuristic += 2
|
|
|
|
if array.count(opposite_color) == 3 and array.count('.') == 1:
|
|
heuristic -= 100
|
|
|
|
return heuristic
|
|
|
|
def find_moves(self, board, color):
|
|
moves_found = []
|
|
for col in range(self.x_max):
|
|
for row in reversed(range(self.y_max)):
|
|
if board[col][row] == '.':
|
|
moves_found.append([col, row])
|
|
break
|
|
return moves_found |