我有问题。我正在尝试建立一个人工智能游戏,我遇到了一个问题。我复制了一个播放器并继承了前一个播放器(类Player(SelectiveAlphaBeta.Player))。现在,我正在制作的游戏树中的搜索是相同的(它只打印每个级别的最高和最低分数 - 只是为了帮助我选择正确的阈值)。然而它崩溃了:
class Player(SelectiveAlphaBeta.Player):
def __init__(self, setup_time, player_color, time_per_k_turns, k):
SelectiveAlphaBeta.Player.__init__(self, setup_time, player_color, time_per_k_turns, k, 0.25) # TODO: w
def get_move(self, board_state, possible_moves):
self.clock = time.process_time()
self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round - 0.05
if len(possible_moves) == 1:
return possible_moves[0]
current_depth = 1
prev_alpha = -INFINITY
# Choosing an arbitrary move:
best_move = possible_moves[0]
if (self.w < 1):
minimax = MiniMaxWithAlphaBetaPruningWithWDeepeningUntilRestfulness
(self.utility, self.color, self.no_more_time, self.w)
else: # self.w == 1
minimax = MiniMaxWithAlphaBetaPruning(self.utility, self.color, self.no_more_time)
time_last_move = 0;
print('debugger - line 1')
# Iterative deepening until the time runs out.
while True:
print('{} going to depth: {}, remaining time: {}, prev_alpha: {}, best_move: {}'.format(
self.__repr__(), current_depth, self.time_for_current_move - (time.process_time() - self.clock),
prev_alpha, best_move))
time_before = time.process_time()
time_left = self.time_for_current_move - (time.process_time() - self.clock);
# if (time_last_move <= time_left):
try:
print('debugger - line 2')
(alpha, move), run_time = run_with_limited_time(
minimax.search, (board_state, current_depth, -INFINITY, INFINITY, True), {},
time_left)
print('debugger - line 3')
except (ExceededTimeError):
print('no more time')
break
except (MemoryError):
print('no more memory')
break
# else:
# print('{} has no enough time ({}) left to go deeper'.format(self.__repr__(), time_left))
# break;
time_after = time.process_time()
time_last_move = time_after - time_before
if self.no_more_time():
print('no more time')
break
prev_alpha = alpha
best_move = move
if alpha == INFINITY:
print('the move: {} will guarantee victory.'.format(best_move))
break
if alpha == -INFINITY:
print('all is lost')
break
current_depth += 1
if self.turns_remaining_in_round == 1:
self.turns_remaining_in_round = self.k
self.time_remaining_in_round = self.time_per_k_turns
else:
self.turns_remaining_in_round -= 1
self.time_remaining_in_round -= (time.process_time() - self.clock)
return best_move
def utility(self, state):
return SelectiveAlphaBeta.Player.utility(self, state)
def no_more_time(self):
return SelectiveAlphaBeta.Player.no_more_time(self)
def __repr__(self):
return '{} {}'.format(abstract.AbstractPlayer.__repr__(self), 'SelectiveAlphaBetaWithRestfulness{}'.format(str(self.w)))
没有什么遗漏,因为这是函数的签名:
class MiniMaxWithAlphaBetaPruningWithW(MiniMaxWithAlphaBetaPruning):
def __init__(self, utility, my_color, no_more_time, w):
MiniMaxWithAlphaBetaPruning.__init__(self, utility, my_color, no_more_time)
self.w = w
def search(self, state, depth, alpha, beta, maximizing_player):
"""Start the MiniMax algorithm.
:param state: The state to start from.
:param depth: The maximum allowed depth for the algorithm.
:param alpha: The alpha of the alpha-beta pruning.
:param alpha: The beta of the alpha-beta pruning.
:param maximizing_player: Whether this is a max node (True) or a min node (False).
:return: A tuple: (The alpha-beta algorithm value, The move in case of max node or None in min mode)
"""
if depth == 0 or self.no_more_time():
return self.utility(state), None
next_moves = state.legalMoves()
if not next_moves:
# This player has no moves. So the previous player is the winner.
return INFINITY if state.currPlayer != self.my_color else -INFINITY, None
list = []
for next_move in next_moves:
if (self.no_more_time()):
del list[:]
return self.utility(state), None
new_state = copy.deepcopy(state)
new_state.doMove(next_move)
list.append((new_state, next_move, self.utility(new_state)))
list.sort(key=itemgetter(2))
if (self.no_more_time()):
del list[:]
return self.utility(state), None
if maximizing_player:
selected_move = next_moves[0]
best_move_utility = -INFINITY
for i in range(int(len(list)) - 1, int(len(list)) - int(len(list) * self.w) - 1, -1):
minimax_value, _ = self.search(list[i][0], depth - 1, alpha, beta, False)
alpha = max(alpha, minimax_value)
if minimax_value > best_move_utility:
best_move_utility = minimax_value
selected_move = list[i][1]
if beta <= alpha or self.no_more_time():
break
del list[:]
return alpha, selected_move
else:
for i in range(0, int(len(list) * self.w)):
beta = min(beta, self.search(list[i][0], depth - 1, alpha, beta, True)[0])
if beta <= alpha or self.no_more_time():
break
del list[:]
return beta, None
class MiniMaxWithAlphaBetaPruningWithWDeepeningUntilRestfulness(MiniMaxWithAlphaBetaPruning):
def __init__(self, utility, my_color, no_more_time, w):
MiniMaxWithAlphaBetaPruningWithW.__init__(self, utility, my_color, no_more_time, w)
# self.treshold_restfulness = TODO
def search(self, state, depth, alpha, beta, maximizing_player):
"""Start the MiniMax algorithm.
:param state: The state to start from.
:param depth: The maximum allowed depth for the algorithm.
:param alpha: The alpha of the alpha-beta pruning.
:param alpha: The beta of the alpha-beta pruning.
:param maximizing_player: Whether this is a max node (True) or a min node (False).
:return: A tuple: (The alpha-beta algorithm value, The move in case of max node or None in min mode)
"""
print('debugger - line 4')
if depth == 0 or self.no_more_time():
return self.utility(state), None
next_moves = state.legalMoves()
if not next_moves:
# This player has no moves. So the previous player is the winner.
return INFINITY if state.currPlayer != self.my_color else -INFINITY, None
list = []
for next_move in next_moves:
if (self.no_more_time()):
del list[:]
return self.utility(state), None
new_state = copy.deepcopy(state)
new_state.doMove(next_move)
list.append((new_state, next_move, self.utility(new_state)))
list.sort(key=itemgetter(2))
if (self.no_more_time()):
del list[:]
return self.utility(state), None
if maximizing_player:
selected_move = next_moves[0]
best_move_utility = -INFINITY
for i in range(int(len(list)) - 1, int(len(list)) - int(len(list) * self.w) - 1, -1):
minimax_value, _ = self.search(list[i][0], depth - 1, alpha, beta, False)
alpha = max(alpha, minimax_value)
if minimax_value > best_move_utility:
best_move_utility = minimax_value
selected_move = list[i][1]
if beta <= alpha or self.no_more_time():
break
print('Utility of best Move in deepening in depth of {} is {}'.format(depth, minimax_value))
del list[:]
return alpha, selected_move
else:
for i in range(0, int(len(list) * self.w)):
beta = min(beta, self.search(list[i][0], depth - 1, alpha, beta, True)[0])
if beta <= alpha or self.no_more_time():
break
del list[:]
return beta, None
错误消息是:
Exception in thread Thread-6:
Traceback (most recent call last):
File "C:\Python34\lib\threading.py", line 921, in _bootstrap_inner
self.run()
File "C:\Python34\lib\threading.py", line 869, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\Eli\workspace\HW2\amazons\utils.py", line 36, in function_wrapper
result = func(*args, **kwargs)
TypeError: search() missing 1 required positional argument: 'maximizing_player'
为方便原始玩家:
class Player(players.simple_player.Player):
def __init__(self, setup_time, player_color, time_per_k_turns, k, w):
players.simple_player.Player.__init__(self, setup_time, player_color, time_per_k_turns, k)
self.w = w;
def get_move(self, board_state, possible_moves):
self.clock = time.process_time()
self.time_for_current_move = self.time_remaining_in_round / self.turns_remaining_in_round - 0.05
if len(possible_moves) == 1:
return possible_moves[0]
current_depth = 1
prev_alpha = -INFINITY
# Choosing an arbitrary move:
best_move = possible_moves[0]
if (self.w < 1):
minimax = MiniMaxWithAlphaBetaPruningWithW(self.utility, self.color, self.no_more_time, self.w)
else: # self.w == 1
minimax = MiniMaxWithAlphaBetaPruning(self.utility, self.color, self.no_more_time)
time_last_move = 0;
# Iterative deepening until the time runs out.
while True:
print('{} going to depth: {}, remaining time: {}, prev_alpha: {}, best_move: {}'.format(
self.__repr__(), current_depth, self.time_for_current_move - (time.process_time() - self.clock),
prev_alpha, best_move))
time_before = time.process_time()
time_left = self.time_for_current_move - (time.process_time() - self.clock);
# if (time_last_move <= time_left):
try:
(alpha, move), run_time = run_with_limited_time(
minimax.search, (board_state, current_depth, -INFINITY, INFINITY, True), {},
time_left)
except (ExceededTimeError):
print('no more time')
break
except (MemoryError):
print('no more memory')
break
# else:
# print('{} has no enough time ({}) left to go deeper'.format(self.__repr__(), time_left))
# break;
time_after = time.process_time()
time_last_move = time_after - time_before
if self.no_more_time():
print('no more time')
break
prev_alpha = alpha
best_move = move
if alpha == INFINITY:
print('the move: {} will guarantee victory.'.format(best_move))
break
if alpha == -INFINITY:
print('all is lost')
break
current_depth += 1
if self.turns_remaining_in_round == 1:
self.turns_remaining_in_round = self.k
self.time_remaining_in_round = self.time_per_k_turns
else:
self.turns_remaining_in_round -= 1
self.time_remaining_in_round -= (time.process_time() - self.clock)
return best_move
为方便起见 - run_with_limited_time:
def run_with_limited_time(func, args, kwargs, time_limit):
"""Runs a function with time limit
:param func: The function to run.
:param args: The functions args, given as tuple.
:param kwargs: The functions keywords, given as dict.
:param time_limit: The time limit in seconds (can be float).
:return: A tuple: The function's return value unchanged, and the running time for the function.
:raises PlayerExceededTimeError: If player exceeded its given time.
"""
q = Queue()
t = Thread(target=function_wrapper, args=(func, args, kwargs, q))
t.start()
# This is just for limiting the runtime of the other thread, so we stop eventually.
# It doesn't really measure the runtime.
t.join(time_limit)
if t.is_alive():
raise ExceededTimeError
q_get = q.get()
if isinstance(q_get, MemoryError):
raise q_get
return q_get
当然没有提及对象仅运行它的游戏的功能。我不知道为什么会这样。它一定是非常愚蠢但我不知道......我只做了一个简单的代码副本,我没有改变这一行......
提前致谢, 利
答案 0 :(得分:2)
你的问题在这里:
minimax = MiniMaxWithAlphaBetaPruningWithWDeepeningUntilRestfulness
(self.utility, self.color, self.no_more_time, self.w)
这些实际上是两个单独的行,第二行没有任何作用,而你打算将它作为单个表达式。它会将minimax
指定为类本身而不是实例,这会在以后调用类上的方法时导致问题。
您可以将所有内容放在一行上,或者只是将左括号移到第一行(因为当括号打开时,Python允许表达式在下一行继续):
minimax = MiniMaxWithAlphaBetaPruningWithWDeepeningUntilRestfulness(
self.utility, self.color, self.no_more_time, self.w)