AI/Unit 3/Umaretiya_r_U3_L3.py

237 lines
6.9 KiB
Python

# Name: Rushil Umaretiya
# Date: 1/8/2021
import random
class RandomBot:
def __init__(self):
self.white = "O"
self.black = "@"
self.directions = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]
self.opposite_color = {self.black: self.white, self.white: self.black}
self.x_max = None
self.y_max = None
def best_strategy(self, board, color):
# returns best move
self.x_max = len(board)
self.y_max = len(board[0])
if color == "#000000":
color = "@"
else:
color = "O"
random_move, flipped_stones = random.choice(list(self.find_moves(board, color).items()))
return (random_move // self.x_max, random_move % self.y_max), len(flipped_stones)
def stones_left(self, board):
left = 0
for i in range(board):
for j in range(board[i]):
if board[i][j] == '.': left += 1
return left
def find_moves(self, board, color):
moves_found = {}
for i in range(len(board)):
for j in range(len(board[i])):
flipped_stones = self.find_flipped(board, i, j, color)
if len(flipped_stones) > 0:
moves_found.update({i * self.y_max + j: flipped_stones})
return moves_found
def find_flipped(self, board, x, y, color):
if board[x][y] != ".":
return []
if color == self.black:
color = "@"
else:
color = "O"
flipped_stones = []
for incr in self.directions:
temp_flip = []
x_pos = x + incr[0]
y_pos = y + incr[1]
while 0 <= x_pos < self.x_max and 0 <= y_pos < self.y_max:
if board[x_pos][y_pos] == ".":
break
if board[x_pos][y_pos] == color:
flipped_stones += temp_flip
break
temp_flip.append([x_pos, y_pos])
x_pos += incr[0]
y_pos += incr[1]
return flipped_stones
class Best_AI_bot:
def __init__(self):
self.logging = True
self.white = "#ffffff" # "O"
self.black = "#000000" # "@"
self.directions = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]
self.opposite_color = {self.black: self.white, self.white: self.black}
self.x_max = None
self.y_max = None
self.color = None
self.heuristic_table = [
[999,-3,2,2,2,2,-3,999],
[-3,-4,-1,-1,-1,-1,-4,-3],
[2,-1,1,0,0,1,-1,2],
[2,-1,0,1,1,0,-1,2],
[2,-1,0,1,1,0,-1,2],
[2,-1,1,0,0,1,-1,2],
[-3,-4,-1,-1,-1,-1,-4,-3],
[999, -3, 2, 2, 2, 2, -3, 999],
]
def best_strategy(self, board, color):
self.x_max = len(board)
self.y_max = len(board[0])
self.color = color
stones_left = self.stones_left(board)
if stones_left > 32:
sd = 4
elif stones_left > 10:
sd = 6
else:
sd = 8
v, best_move = self.alphabeta(board, color, search_depth=sd, alpha=-9999999999, beta=9999999999) # returns state
return (best_move // self.x_max, best_move % self.y_max), 0
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 alphabeta(self, board, color, search_depth, alpha, beta, last_move=-1):
terminal_test = self.terminal_test(board)
if search_depth <= 0 or terminal_test:
if terminal_test:
return self.evaluate(board, self.color, last_move) * 1000000, last_move
return self.evaluate(board, self.color, last_move), 0
if search_depth % 2 == 0:
v = -9999999999
result = 0
for move, flipped in self.find_moves(board, color).items():
max_val, max_state = self.alphabeta(self.make_move(board, color, move, flipped), self.opposite_color[color], search_depth - 1, alpha, beta, move)
if v < max_val:
v = max_val
result = move
if v > beta:
return v, result
alpha = max(alpha, v)
return v, result
else:
v = 9999999999
result = 0
for move, flipped in self.find_moves(board, color).items():
min_val, min_state = self.alphabeta(self.make_move(board, color, move, flipped), self.opposite_color[color], search_depth - 1, alpha, beta, move)
if v > min_val:
v = min_val
result = move
if v < alpha:
return v, result
beta = min(beta, v)
return v, result
def terminal_test(self, board):
return self.stones_left(board) == 0
def stones_left(self, board):
left = 0
for i in range(len(board)):
for j in range(len(board[i])):
if board[i][j] == '.': left += 1
return left
def make_move(self, board, color, move, flipped):
my_board = [row[:] for row in board]
if color == self.black:
color = "@"
else:
color = "O"
my_board[move // self.x_max][move % self.y_max] = color
for flip in flipped:
my_board[flip[0]][flip[1]] = color
return my_board
def evaluate(self, board, color, last_move):
score = self.score(board, color)
if last_move != -1:
heuristic = self.heuristic_table[last_move // self.x_max][last_move % self.y_max]
return score * heuristic
else:
return score
def score(self, board, color):
if color == self.black:
color = "@"
else:
color = "O"
score = 0
for i in range(len(board)):
for j in range(len(board[i])):
if board[i][j] == color:
score += 1
elif board[i][j] != '.':
score -= 1
return score
def find_moves(self, board, color):
moves_found = {}
for i in range(len(board)):
for j in range(len(board[i])):
flipped_stones = self.find_flipped(board, i, j, color)
if len(flipped_stones) > 0:
moves_found.update({i * self.y_max + j: flipped_stones})
return moves_found
def find_flipped(self, board, x, y, color):
if board[x][y] != ".":
return []
if color == self.black:
color = "@"
else:
color = "O"
flipped_stones = []
for incr in self.directions:
temp_flip = []
x_pos = x + incr[0]
y_pos = y + incr[1]
while 0 <= x_pos < self.x_max and 0 <= y_pos < self.y_max:
if board[x_pos][y_pos] == ".":
break
if board[x_pos][y_pos] == color:
flipped_stones += temp_flip
break
temp_flip.append([x_pos, y_pos])
x_pos += incr[0]
y_pos += incr[1]
return flipped_stones