Você está na página 1de 4

# tools for minimax

import game_tree
import copy

def _switch_rate(r):
'''Return opposing players rating corresponding to r.'''

return r * -1 # one's loss is the other's gain

class GameState:

"""State of a two-person game, including player about to play.

Assumptions:
Two-person, zero-sum game, with exactly three outcomes:
player one can win, lose, or draw, whereas player two
can (respectively) lose, win, or draw.
Each ply toggles player_1 <-> player_2.
"""
'''Class constants.'''
WIN = 1
LOSE = -1
DRAW = 0
INF = float('inf')

def __init__(self, start_state):


"""Create a new Game in starting state.

Arguments
start_state: Tuple (layout, starting player).
"""

self._state = start_state

def terminal_eval(self):
"""Return current player's score at end of game.

Assumptions:
The game is in a state reachable from the initial position by a
sequence of plies, with a current player to play, but no further
plies allowed.

Returns:
Return whether the current player wins, loses, or ties.
"""
if self.winner(self.player()):
return self.WIN
elif self.winner(self.opponent()):
return self.LOSE
else:
return self.DRAW

def heuristic_eval(self):
"""Return estimate of current player's score at end of game.

Assumptions:
Game is in a state reachable from initial position by sequence
of plies, current player to play, possibly further moves allowed.

Returns:
Confidence that current player wins (0,1], loses [-1,0), or
draws (0).
"""

raise NotImplementedError('Implemented in GameState subclass')

def _comp_layouts(self, s1, s2):


'''Given two states, s1 and s2, return the different element (r, c)
when comparing s1 and s2'''

l1 = list(copy.deepcopy(s1._state[0]))
l2 = list(copy.deepcopy(s2._state[0]))

for i in range(len(s1._state[0])):
for j in range(len(s1._state[0])):
if l1[i][j] != l2[i][j]:
return (i, j) # the different spot

def minimax(self, foresight, pred_max=-1, layout=None):


"""Return best move and score for current GameState.

Arguments:
foresight: Number of plies we may look ahead.
pred_max: Best score so far of predecessor GameState.
layout: Dictionary containing best score and move
for each layout

Assumptions:
Current player has at least one legal move available.
foresight is positive.
Returns (m, s)
s: Highest score that current player can guarantee.
m: Next move that allows current player to guarantee s.
"""

root = game_tree.GameStateNode(self)
root.grow()

if len(root.children) == 0: # if there are no further moves.


if pred_max > 0:
return (0, _switch_rate(self.terminal_eval())) # switch
else:
return (0, self.terminal_eval())

elif foresight <= 0: # no more foresight


if pred_max > 0:
return (0, _switch_rate(self.heuristic_eval()))
else:
return (0, self.heuristic_eval())
else: # forsight and move available.
new_children = []
children = root.children
# sort children by heurestic_eval value.
children.sort(key=lambda children: children.value.heuristic_eval())
best_score = children[0].value.heuristic_eval() # lowest value
# go through children, if it's the best score, append new_children.
for c in children:
if c.value.heuristic_eval() == best_score:
new_children.append(c)
max_mm = -2
for c in new_children:
# recursion ------
r = c.value.minimax(foresight, _switch_rate(pred_max))
minimax = r[1]
if minimax > max_mm:
max_mm = minimax
best_child = c

return (self._comp_layouts(self, best_child.value), max_mm)

def player(self):
"""Return current player --- the one with option of moving.

Assumptions
Player returned is one of 'p1' or 'p2'.
Player returned might have no legal moves available.
"""
return self._state[1] # state is a 2-tuple

def opponent(self):
"""Return opponent of current player."""
if self.player() == 'p1':
return 'p2'
else:
return 'p1'

def next_move(self):
"""Return a sequence of all legal moves."""
raise NotImplementedError('Implement next_move in GameState subclass')

def winner(self, player):


"""Return whether this player has won."""
raise NotImplementedError('Implement winner in GameState subclass')

def make_move(self, move):


"""Return new GameState by applying move."""
raise NotImplementedError('Implement make_move in GameState subclass')

Você também pode gostar