mirror of
https://github.com/Rushilwiz/AI.git
synced 2025-04-17 17:40:17 -04:00
finished unit 3 lab 2
This commit is contained in:
parent
9487a1d65d
commit
c4d3363f16
189
Unit 3/Umaretiya_r_U3_L2.py
Normal file
189
Unit 3/Umaretiya_r_U3_L2.py
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
# Name: Rushil Umaretiya
|
||||||
|
# Date: 12/16/2020
|
||||||
|
import random
|
||||||
|
|
||||||
|
class RandomPlayer:
|
||||||
|
def __init__(self):
|
||||||
|
self.white = "#ffffff" #"O"
|
||||||
|
self.black = "#000000" #"X"
|
||||||
|
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.first_turn = True
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Random Player"
|
||||||
|
|
||||||
|
def best_strategy(self, board, color):
|
||||||
|
# returns best move
|
||||||
|
# (column num, row num), 0
|
||||||
|
try:
|
||||||
|
best_move = random.choice(list(self.find_moves(board, color)))
|
||||||
|
except IndexError:
|
||||||
|
return (-1,-1), 0
|
||||||
|
|
||||||
|
return (best_move // 5, best_move % 5), 0
|
||||||
|
|
||||||
|
|
||||||
|
def find_moves(self, board, color):
|
||||||
|
# finds all possible moves
|
||||||
|
# returns a set, e.g., {0, 1, 2, 3, ...., 24}
|
||||||
|
# 0 5 10 15 20
|
||||||
|
# 1 6 11 16 21
|
||||||
|
# 2 7 12 17 22
|
||||||
|
# 3 8 13 18 23
|
||||||
|
# 4 9 14 19 24
|
||||||
|
|
||||||
|
possible_moves = set()
|
||||||
|
|
||||||
|
for x in range(len(board)):
|
||||||
|
for y in range(len(board[x])):
|
||||||
|
if self.first_turn and board[x][y] == '.': possible_moves.add(x*5+y)
|
||||||
|
elif (color == self.black and board[x][y] == 'X') or (color == self.white and board[x][y] == 'O'):
|
||||||
|
for direction in self.directions:
|
||||||
|
curr_x = x + direction[0]
|
||||||
|
curr_y = y + direction[1]
|
||||||
|
stop = False
|
||||||
|
while 0 <= curr_x < 5 and 0 <= curr_y < 5:
|
||||||
|
if board[curr_x][curr_y] != '.':
|
||||||
|
stop = True
|
||||||
|
if not stop:
|
||||||
|
possible_moves.add(curr_x*5+curr_y)
|
||||||
|
curr_x += direction[0]
|
||||||
|
curr_y += direction[1]
|
||||||
|
|
||||||
|
self.first_turn = False
|
||||||
|
return possible_moves
|
||||||
|
|
||||||
|
class CustomPlayer:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.white = "#ffffff" #"O"
|
||||||
|
self.black = "#000000" #"X"
|
||||||
|
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.first_turn = True
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Custom Player"
|
||||||
|
|
||||||
|
def utility (self, board, color):
|
||||||
|
my_moves = len(self.find_moves(board, color))
|
||||||
|
opponent_moves = len(self.find_moves(board, self.opposite_color[color]))
|
||||||
|
if my_moves == 0 and opponent_moves == 0:
|
||||||
|
return 0
|
||||||
|
elif my_moves == 0:
|
||||||
|
return -1000
|
||||||
|
elif opponent_moves == 0:
|
||||||
|
return 1000
|
||||||
|
else:
|
||||||
|
return my_moves - opponent_moves
|
||||||
|
|
||||||
|
def terminal_test (self, board, color):
|
||||||
|
my_moves = self.find_moves(board, color)
|
||||||
|
opponent_moves = self.find_moves(board, self.opposite_color[color])
|
||||||
|
if len(my_moves) == 0 or len(opponent_moves) == 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def best_strategy(self, board, color):
|
||||||
|
# returns best move
|
||||||
|
best_move = self.minimax(board, color, 2)
|
||||||
|
return best_move
|
||||||
|
|
||||||
|
def minimax(self, board, color, search_depth):
|
||||||
|
max_val = self.max_value(board, color, search_depth) # returns state
|
||||||
|
move = self.current_position(max_val[1], color)
|
||||||
|
return (move // 5, move % 5), max_val[0]
|
||||||
|
|
||||||
|
def current_position(self, board, color):
|
||||||
|
for i in range(len(board)):
|
||||||
|
for j in range(len(board[i])):
|
||||||
|
if (color == self.black and board[i][j] == 'X') or (color == self.white and board[i][j] == 'O'):
|
||||||
|
return i*5+j
|
||||||
|
return -1
|
||||||
|
|
||||||
|
def successors(self, board, color):
|
||||||
|
successors = []
|
||||||
|
moves = self.find_moves(board, color)
|
||||||
|
current_position = self.current_position(board, color)
|
||||||
|
for move in moves:
|
||||||
|
successor = [x[:] for x in board]
|
||||||
|
if current_position != -1:
|
||||||
|
successor[current_position // 5][current_position % 5] = "W"
|
||||||
|
successor[move // 5][move % 5] = 'X' if color == self.black else 'O'
|
||||||
|
successors.append(successor)
|
||||||
|
return successors
|
||||||
|
|
||||||
|
def max_value(self, board, color, search_depth):
|
||||||
|
# return value and state: (val, state)
|
||||||
|
if search_depth <= 0 or self.terminal_test(board, color):
|
||||||
|
return self.utility(board, color), board
|
||||||
|
v = -99999
|
||||||
|
result = board
|
||||||
|
for successor in self.successors(board, color):
|
||||||
|
min_val, min_state = self.min_value(successor, self.opposite_color[color], search_depth - 1)
|
||||||
|
if v < min_val:
|
||||||
|
v = min_val
|
||||||
|
result = successor
|
||||||
|
|
||||||
|
return v, result
|
||||||
|
|
||||||
|
def min_value(self, board, color, search_depth):
|
||||||
|
# return value and state: (val, state)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if search_depth <= 0 or self.terminal_test(board, color):
|
||||||
|
return self.utility(board, self.opposite_color[color]), board
|
||||||
|
|
||||||
|
v = 99999
|
||||||
|
result = board
|
||||||
|
for successor in self.successors(board, color):
|
||||||
|
max_val, max_state = self.max_value(successor, self.opposite_color[color], search_depth - 1)
|
||||||
|
if v > max_val:
|
||||||
|
v = max_val
|
||||||
|
result = successor
|
||||||
|
|
||||||
|
return v, result
|
||||||
|
|
||||||
|
def negamax(self, board, color, search_depth):
|
||||||
|
# returns best "value"
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def alphabeta(self, board, color, search_depth, alpha, beta):
|
||||||
|
# returns best "value" while also pruning
|
||||||
|
pass
|
||||||
|
|
||||||
|
def make_move(self, board, color, move):
|
||||||
|
# returns board that has been updated
|
||||||
|
return board
|
||||||
|
|
||||||
|
def evaluate(self, board, color, possible_moves):
|
||||||
|
# returns the utility value
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def find_moves(self, board, color):
|
||||||
|
# finds all possible moves
|
||||||
|
possible_moves = set()
|
||||||
|
for x in range(len(board)):
|
||||||
|
for y in range(len(board[x])):
|
||||||
|
if len([y for x in board for y in x if y != '.']) < 2 and board[x][y] == '.': possible_moves.add(x*5+y)
|
||||||
|
elif (color == self.black and board[x][y] == 'X') or (color == self.white and board[x][y] == 'O'):
|
||||||
|
for direction in self.directions:
|
||||||
|
curr_x = x + direction[0]
|
||||||
|
curr_y = y + direction[1]
|
||||||
|
stop = False
|
||||||
|
while 0 <= curr_x < 5 and 0 <= curr_y < 5:
|
||||||
|
if board[curr_x][curr_y] != '.':
|
||||||
|
stop = True
|
||||||
|
if not stop:
|
||||||
|
possible_moves.add(curr_x*5+curr_y)
|
||||||
|
curr_x += direction[0]
|
||||||
|
curr_y += direction[1]
|
||||||
|
|
||||||
|
return possible_moves
|
240
Unit 3/isolation_runner.py
Normal file
240
Unit 3/isolation_runner.py
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
# Original idea from Richard Zhan (class of 2020)
|
||||||
|
# Modified by N. Kim on Dec 2019
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import tkinter as tk
|
||||||
|
from Umaretiya_r_U3_L2 import CustomPlayer, RandomPlayer
|
||||||
|
|
||||||
|
# constants
|
||||||
|
delay_time = 0.15
|
||||||
|
turn_off_printing = False
|
||||||
|
tile_size = 50
|
||||||
|
padding = 5
|
||||||
|
x_max = 5
|
||||||
|
y_max = 5
|
||||||
|
board_x = x_max*tile_size+(x_max+1)*padding-2
|
||||||
|
board_y = y_max*tile_size+(y_max+1)*padding-2
|
||||||
|
white = "#ffffff"
|
||||||
|
black = "#000000"
|
||||||
|
grey = "#505050"
|
||||||
|
green = "#00ff00"
|
||||||
|
yellow = "#ffff00"
|
||||||
|
brown = "#654321"
|
||||||
|
blue = "#0000ff"
|
||||||
|
cyan = "#00ffff"
|
||||||
|
red = "#ff0000"
|
||||||
|
asterisk = " "+u'\u2217'
|
||||||
|
directions = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]
|
||||||
|
opposite_color = {black: white, white: black}
|
||||||
|
|
||||||
|
# variables
|
||||||
|
player_types = {0: "Player", 1: "Random", 2: "Custom"}
|
||||||
|
players = {black: None, white: None, None: None}
|
||||||
|
player_max_times = {black: 0, white: 0}
|
||||||
|
player_total_times = {black: 0, white: 0}
|
||||||
|
p1_name = ""
|
||||||
|
p2_name = ""
|
||||||
|
root = None
|
||||||
|
canvas = None
|
||||||
|
turn = white
|
||||||
|
board = []
|
||||||
|
possible_moves = {i for i in range(x_max * y_max)}
|
||||||
|
first_turn = 0
|
||||||
|
# commands
|
||||||
|
|
||||||
|
|
||||||
|
def whose_turn(my_board, prev_turn):
|
||||||
|
global possible_moves, first_turn
|
||||||
|
cur_turn = opposite_color[prev_turn]
|
||||||
|
possible_moves = find_moves(my_board, cur_turn)
|
||||||
|
first_turn += 1
|
||||||
|
if len(possible_moves) > 0:
|
||||||
|
return cur_turn
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def find_moves(my_board, my_color):
|
||||||
|
global first_turn
|
||||||
|
moves_found = set()
|
||||||
|
for i in range(len(my_board)):
|
||||||
|
for j in range(len(my_board[i])):
|
||||||
|
if first_turn < 2 and my_board[i][j] == '.':
|
||||||
|
moves_found.add(i*y_max+j)
|
||||||
|
elif (my_color == black and my_board[i][j] == 'X') or (my_color == white and my_board[i][j] == 'O'):
|
||||||
|
for incr in directions:
|
||||||
|
x_pos = i + incr[0]
|
||||||
|
y_pos = j + incr[1]
|
||||||
|
stop = False
|
||||||
|
while 0 <= x_pos < x_max and 0 <= y_pos < y_max:
|
||||||
|
if my_board[x_pos][y_pos] != '.':
|
||||||
|
stop = True
|
||||||
|
if not stop:
|
||||||
|
moves_found.add(x_pos*y_max+y_pos)
|
||||||
|
x_pos += incr[0]
|
||||||
|
y_pos += incr[1]
|
||||||
|
return moves_found
|
||||||
|
|
||||||
|
|
||||||
|
def print_board(my_board):
|
||||||
|
# return # comment to print board each time
|
||||||
|
print("\t", end="")
|
||||||
|
for i in range(x_max):
|
||||||
|
print(chr(ord("a")+i), end=" ")
|
||||||
|
print()
|
||||||
|
for i in range(y_max):
|
||||||
|
print(i+1, end="\t")
|
||||||
|
for j in range(x_max):
|
||||||
|
print(my_board[j][i], end=" ")
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def draw_rect(x_pos, y_pos, possible=False, wall = False):
|
||||||
|
coord = [x_pos*(padding+tile_size)+padding+1, y_pos*(padding+tile_size)+padding+1,
|
||||||
|
(x_pos+1)*(padding+tile_size), (y_pos+1)*(padding+tile_size)]
|
||||||
|
if possible:
|
||||||
|
canvas.create_rectangle(coord, fill=cyan, activefill=yellow)
|
||||||
|
elif wall:
|
||||||
|
canvas.create_rectangle(coord, fill=red)
|
||||||
|
else:
|
||||||
|
canvas.create_rectangle(coord, fill=green)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_circle(x_pos, y_pos, fill_color):
|
||||||
|
coord = [x_pos*(padding+tile_size)+2*padding+1, y_pos*(padding+tile_size)+2*padding+1,
|
||||||
|
(x_pos+1)*(padding+tile_size)-padding, (y_pos+1)*(padding+tile_size)-padding]
|
||||||
|
canvas.create_oval(coord, fill=fill_color)
|
||||||
|
|
||||||
|
|
||||||
|
def make_move(x, y):
|
||||||
|
if x*y_max+y not in possible_moves:
|
||||||
|
return False
|
||||||
|
next_turn(x, y)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def click(event=None):
|
||||||
|
x = int((event.x-padding)/(padding+tile_size))
|
||||||
|
y = int((event.y-padding)/(padding+tile_size))
|
||||||
|
if x*y_max+y not in possible_moves:
|
||||||
|
return
|
||||||
|
next_turn(x, y)
|
||||||
|
|
||||||
|
|
||||||
|
def next_turn(x_pos, y_pos):
|
||||||
|
global turn, possible_moves
|
||||||
|
for pos in possible_moves:
|
||||||
|
draw_rect(int(pos/y_max), pos % y_max)
|
||||||
|
if turn == black:
|
||||||
|
color_symbol = "X"
|
||||||
|
else:
|
||||||
|
color_symbol = "O"
|
||||||
|
board[x_pos][y_pos] = color_symbol
|
||||||
|
draw_circle(x_pos, y_pos, turn)
|
||||||
|
possible_moves -= {x_pos*x_max + y_pos}
|
||||||
|
for i in range(len(board)):
|
||||||
|
for j in range(len(board[i])):
|
||||||
|
if board[i][j] == color_symbol and (i != x_pos or j != y_pos):
|
||||||
|
board[i][j] = 'W'
|
||||||
|
if board[i][j] == 'X':
|
||||||
|
draw_circle(i, j, black)
|
||||||
|
elif board[i][j] == 'O':
|
||||||
|
draw_circle(i, j, white)
|
||||||
|
elif board[i][j] == 'W':
|
||||||
|
draw_rect(i, j, wall = True)
|
||||||
|
winner_candidate = color_symbol
|
||||||
|
turn = whose_turn(board, turn)
|
||||||
|
if turn is None:
|
||||||
|
print_board(board)
|
||||||
|
print ("{} win".format(winner_candidate))
|
||||||
|
|
||||||
|
return
|
||||||
|
for pos in possible_moves:
|
||||||
|
draw_rect(int(pos/y_max), pos % y_max, True)
|
||||||
|
print_board(board)
|
||||||
|
if players[turn] != "Player":
|
||||||
|
root.update()
|
||||||
|
'''you may change the code below'''
|
||||||
|
time.sleep(delay_time)
|
||||||
|
start = time.time()
|
||||||
|
move, val = players[turn].best_strategy(board, turn)
|
||||||
|
time_used = round(time.time()-start, 3)
|
||||||
|
player_max_times[turn] = max(player_max_times[turn], time_used)
|
||||||
|
player_total_times[turn] = player_total_times[turn]+time_used
|
||||||
|
next_turn(move[0], move[1])
|
||||||
|
|
||||||
|
|
||||||
|
def init(choice_menu, e1, e2, v1, v2):
|
||||||
|
global turn_off_printing, turn, root, canvas, p1_name, p2_name, players, player_types
|
||||||
|
if turn_off_printing:
|
||||||
|
sys.stdout = open(os.devnull, 'w')
|
||||||
|
p1_name = e1.get()
|
||||||
|
p2_name = e2.get()
|
||||||
|
players[black] = player_types[v1.get()]
|
||||||
|
players[white] = player_types[v2.get()]
|
||||||
|
p1_name = players[black]
|
||||||
|
p2_name = players[white]
|
||||||
|
if players[black] == "Random":
|
||||||
|
players[black] = RandomPlayer()
|
||||||
|
elif players[black] == "Custom":
|
||||||
|
players[black] = CustomPlayer()
|
||||||
|
if players[white] == "Random":
|
||||||
|
players[white] = RandomPlayer()
|
||||||
|
elif players[white] == "Custom":
|
||||||
|
players[white] = CustomPlayer()
|
||||||
|
choice_menu.destroy()
|
||||||
|
root = tk.Tk()
|
||||||
|
root.title("Isolation Game")
|
||||||
|
root.resizable(width=False, height=False)
|
||||||
|
canvas = tk.Canvas(root, width=board_x, height=board_y, bg=brown)
|
||||||
|
canvas.bind("<Button-1>", click)
|
||||||
|
canvas.grid(row=0, column=0, columnspan=2)
|
||||||
|
for i in range(x_max):
|
||||||
|
board.append([])
|
||||||
|
for j in range(y_max):
|
||||||
|
draw_rect(i, j)
|
||||||
|
board[i].append(".")
|
||||||
|
turn = whose_turn(board, turn)
|
||||||
|
for pos in possible_moves:
|
||||||
|
draw_rect(int(pos/y_max), pos % y_max, True)
|
||||||
|
print_board(board)
|
||||||
|
print ("whose turn", players[turn])
|
||||||
|
if players[turn] != "Player":
|
||||||
|
root.update()
|
||||||
|
'''you may change the code below'''
|
||||||
|
time.sleep(delay_time)
|
||||||
|
move, idc = players[turn].best_strategy(board, turn)
|
||||||
|
next_turn(move[0], move[1])
|
||||||
|
root.mainloop()
|
||||||
|
|
||||||
|
|
||||||
|
def menu():
|
||||||
|
global p1_name, p2_name, radio_on, radio_off
|
||||||
|
choice_menu = tk.Tk()
|
||||||
|
choice_menu.title("Menu")
|
||||||
|
choice_menu.resizable(width=False, height=False)
|
||||||
|
tk.Label(text="Black", font=("Arial", 30), bg=black, fg=grey).grid(row=0, column=0, sticky=tk.W+tk.E+tk.N+tk.S)
|
||||||
|
tk.Label(text="White", font=("Arial", 30), bg=white, fg=black).grid(row=0, column=1, sticky=tk.W+tk.E+tk.N+tk.S)
|
||||||
|
v1 = tk.IntVar()
|
||||||
|
v2 = tk.IntVar()
|
||||||
|
v1.set(0)
|
||||||
|
v2.set(0)
|
||||||
|
tk.Radiobutton(text="Player", compound=tk.LEFT, font=("Arial", 20), bg=black, fg=grey, anchor=tk.W, variable=v1, value=0).grid(row=1, column=0, sticky=tk.W + tk.E + tk.N + tk.S)
|
||||||
|
tk.Radiobutton(text="Player", font=("Arial", 20), bg=white, fg=black, anchor=tk.W, variable=v2, value=0).grid(row=1, column=1, sticky=tk.W + tk.E + tk.N + tk.S)
|
||||||
|
tk.Radiobutton(text="Random", font=("Arial", 20), bg=black, fg=grey, anchor=tk.W, variable=v1, value=1).grid(row=2, column=0, sticky=tk.W + tk.E + tk.N + tk.S)
|
||||||
|
tk.Radiobutton(text="Random", font=("Arial", 20), bg=white, fg=black, anchor=tk.W, variable=v2, value=1).grid(row=2, column=1, sticky=tk.W + tk.E + tk.N + tk.S)
|
||||||
|
tk.Radiobutton(text="Custom", font=("Arial", 20), bg=black, fg=grey, anchor=tk.W, variable=v1, value=2).grid(row=3, column=0, sticky=tk.W + tk.E + tk.N + tk.S)
|
||||||
|
tk.Radiobutton(text="Custom", font=("Arial", 20), bg=white, fg=black, anchor=tk.W, variable=v2, value=2).grid(row=3, column=1, sticky=tk.W + tk.E + tk.N + tk.S)
|
||||||
|
e1 = tk.Entry(font=("Arial", 15), bg=black, fg=grey, width=12)
|
||||||
|
e2 = tk.Entry(font=("Arial", 15), bg=white, fg=black, width=12)
|
||||||
|
e1.insert(0, "Player 1 Name")
|
||||||
|
e2.insert(0, "Player 2 Name")
|
||||||
|
e1.grid(row=99, column=0, sticky=tk.W+tk.E+tk.N+tk.S)
|
||||||
|
e2.grid(row=99, column=1, sticky=tk.W + tk.E + tk.N + tk.S)
|
||||||
|
tk.Button(text="Begin", font=("Arial", 15), bg=white, fg=black, command=lambda: init(choice_menu, e1, e2, v1, v2)).grid(row=100, column=0, columnspan=2, sticky=tk.W+tk.E+tk.N+tk.S)
|
||||||
|
choice_menu.mainloop()
|
||||||
|
|
||||||
|
|
||||||
|
menu()
|
193
Unit 3/isolation_shell.py
Normal file
193
Unit 3/isolation_shell.py
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
# Name: Rushil Umaretiya
|
||||||
|
# Date: 12/16/2020
|
||||||
|
import random
|
||||||
|
|
||||||
|
class RandomPlayer:
|
||||||
|
def __init__(self):
|
||||||
|
self.white = "#ffffff" #"O"
|
||||||
|
self.black = "#000000" #"X"
|
||||||
|
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.first_turn = True
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Random Player"
|
||||||
|
|
||||||
|
def best_strategy(self, board, color):
|
||||||
|
# returns best move
|
||||||
|
# (column num, row num), 0
|
||||||
|
try:
|
||||||
|
best_move = random.choice(list(self.find_moves(board, color)))
|
||||||
|
except IndexError:
|
||||||
|
return (-1,-1), 0
|
||||||
|
|
||||||
|
return (best_move // 5, best_move % 5), 0
|
||||||
|
|
||||||
|
|
||||||
|
def find_moves(self, board, color):
|
||||||
|
# finds all possible moves
|
||||||
|
# returns a set, e.g., {0, 1, 2, 3, ...., 24}
|
||||||
|
# 0 5 10 15 20
|
||||||
|
# 1 6 11 16 21
|
||||||
|
# 2 7 12 17 22
|
||||||
|
# 3 8 13 18 23
|
||||||
|
# 4 9 14 19 24
|
||||||
|
|
||||||
|
possible_moves = set()
|
||||||
|
|
||||||
|
for x in range(len(board)):
|
||||||
|
for y in range(len(board[x])):
|
||||||
|
if self.first_turn and board[x][y] == '.': possible_moves.add(x*5+y)
|
||||||
|
elif (color == self.black and board[x][y] == 'X') or (color == self.white and board[x][y] == 'O'):
|
||||||
|
for direction in self.directions:
|
||||||
|
curr_x = x + direction[0]
|
||||||
|
curr_y = y + direction[1]
|
||||||
|
stop = False
|
||||||
|
while 0 <= curr_x < 5 and 0 <= curr_y < 5:
|
||||||
|
if board[curr_x][curr_y] != '.':
|
||||||
|
stop = True
|
||||||
|
if not stop:
|
||||||
|
possible_moves.add(curr_x*5+curr_y)
|
||||||
|
curr_x += direction[0]
|
||||||
|
curr_y += direction[1]
|
||||||
|
|
||||||
|
self.first_turn = False
|
||||||
|
return possible_moves
|
||||||
|
|
||||||
|
class CustomPlayer:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.white = "#ffffff" #"O"
|
||||||
|
self.black = "#000000" #"X"
|
||||||
|
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.first_turn = True
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Custom Player"
|
||||||
|
|
||||||
|
def utility (self, board, color):
|
||||||
|
my_moves = len(self.find_moves(board, color))
|
||||||
|
opponent_moves = len(self.find_moves(board, self.opposite_color[color]))
|
||||||
|
if my_moves == 0 and opponent_moves == 0:
|
||||||
|
return 0
|
||||||
|
elif my_moves == 0:
|
||||||
|
return -1000
|
||||||
|
elif opponent_moves == 0:
|
||||||
|
return 1000
|
||||||
|
else:
|
||||||
|
return my_moves - opponent_moves
|
||||||
|
|
||||||
|
def terminal_test (self, board, color):
|
||||||
|
my_moves = self.find_moves(board, color)
|
||||||
|
opponent_moves = self.find_moves(board, self.opposite_color[color])
|
||||||
|
if len(my_moves) == 0 or len(opponent_moves) == 0:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def best_strategy(self, board, color):
|
||||||
|
# returns best move
|
||||||
|
best_move = self.minimax(board, color, 4)
|
||||||
|
print('MY MOVE: ' + str(best_move[0]))
|
||||||
|
print("CONFIDENCE: " + str(best_move[1]))
|
||||||
|
return best_move
|
||||||
|
|
||||||
|
def minimax(self, board, color, search_depth):
|
||||||
|
max_val = self.max_value(board, color, search_depth) # returns state
|
||||||
|
move = self.current_position(max_val[1], color)
|
||||||
|
return (move // 5, move % 5), max_val[0]
|
||||||
|
|
||||||
|
def current_position(self, board, color):
|
||||||
|
for i in range(len(board)):
|
||||||
|
for j in range(len(board[i])):
|
||||||
|
if (color == self.black and board[i][j] == 'X') or (color == self.white and board[i][j] == 'O'):
|
||||||
|
return i*5+j
|
||||||
|
return -1
|
||||||
|
|
||||||
|
def successors(self, board, color):
|
||||||
|
successors = []
|
||||||
|
moves = self.find_moves(board, color)
|
||||||
|
current_position = self.current_position(board, color)
|
||||||
|
for move in moves:
|
||||||
|
successor = [x[:] for x in board]
|
||||||
|
if current_position != -1:
|
||||||
|
successor[current_position // 5][current_position % 5] = "W"
|
||||||
|
successor[move // 5][move % 5] = 'X' if color == self.black else 'O'
|
||||||
|
successors.append(successor)
|
||||||
|
return successors
|
||||||
|
|
||||||
|
def max_value(self, board, color, search_depth):
|
||||||
|
# return value and state: (val, state)
|
||||||
|
if search_depth <= 0 or self.terminal_test(board, color):
|
||||||
|
return self.utility(board, color), board
|
||||||
|
v = -99999
|
||||||
|
result = board
|
||||||
|
for successor in self.successors(board, color):
|
||||||
|
min_val, min_state = self.min_value(successor, self.opposite_color[color], search_depth - 1)
|
||||||
|
if v < min_val:
|
||||||
|
v = min_val
|
||||||
|
result = successor
|
||||||
|
|
||||||
|
return v, result
|
||||||
|
|
||||||
|
def min_value(self, board, color, search_depth):
|
||||||
|
# return value and state: (val, state)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if search_depth <= 0 or self.terminal_test(board, color):
|
||||||
|
return self.utility(board, self.opposite_color[color]), board
|
||||||
|
|
||||||
|
v = 99999
|
||||||
|
result = board
|
||||||
|
for successor in self.successors(board, color):
|
||||||
|
max_val, max_state = self.max_value(successor, self.opposite_color[color], search_depth - 1)
|
||||||
|
if v > max_val:
|
||||||
|
v = max_val
|
||||||
|
result = successor
|
||||||
|
|
||||||
|
return v, result
|
||||||
|
|
||||||
|
def negamax(self, board, color, search_depth):
|
||||||
|
# returns best "value"
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def alphabeta(self, board, color, search_depth, alpha, beta):
|
||||||
|
# returns best "value" while also pruning
|
||||||
|
pass
|
||||||
|
|
||||||
|
def make_move(self, board, color, move):
|
||||||
|
# returns board that has been updated
|
||||||
|
return board
|
||||||
|
|
||||||
|
def evaluate(self, board, color, possible_moves):
|
||||||
|
# returns the utility value
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def find_moves(self, board, color):
|
||||||
|
# finds all possible moves
|
||||||
|
possible_moves = set()
|
||||||
|
for x in range(len(board)):
|
||||||
|
for y in range(len(board[x])):
|
||||||
|
if len([y for x in board for y in x if y != '.']) < 2 and board[x][y] == '.': possible_moves.add(x*5+y)
|
||||||
|
elif (color == self.black and board[x][y] == 'X') or (color == self.white and board[x][y] == 'O'):
|
||||||
|
for direction in self.directions:
|
||||||
|
curr_x = x + direction[0]
|
||||||
|
curr_y = y + direction[1]
|
||||||
|
stop = False
|
||||||
|
while 0 <= curr_x < 5 and 0 <= curr_y < 5:
|
||||||
|
if board[curr_x][curr_y] != '.':
|
||||||
|
stop = True
|
||||||
|
if not stop:
|
||||||
|
possible_moves.add(curr_x*5+curr_y)
|
||||||
|
curr_x += direction[0]
|
||||||
|
curr_y += direction[1]
|
||||||
|
|
||||||
|
self.first_turn = False
|
||||||
|
return possible_moves
|
||||||
|
|
Loading…
Reference in New Issue
Block a user