-
Notifications
You must be signed in to change notification settings - Fork 5
/
ai.py
130 lines (106 loc) · 3.72 KB
/
ai.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# -*- coding: utf-8 -*-
import numpy as np
from othello import Board
from value import ScorerWrapper, CountScorer
import sys
class AlphaBeta(object):
MAX_VAL = float("inf")
MIN_VAL = float("-inf")
def __init__(self, evaluator, depth):
"""https://en.wikipedia.org/wiki/Alpha-beta_pruning
http://web.cs.ucla.edu/~rosen/161/notes/alphabeta.html
"""
self._evaluator = evaluator
self._depth = depth
@property
def depth(self):
return self._depth
@depth.setter
def depth(self, val):
self._depth = val
def search(self, board, player):
alpha = AlphaBeta.MIN_VAL
beta = AlphaBeta.MAX_VAL
return self._alpha_beta_search(board, player,
alpha, beta,
self._depth, True)
def _alpha_beta_search(self, board, player, alpha, beta, depth, is_maximizing_player):
if board.is_terminal_state() or depth == 0:
return self._evaluator(board), None
act = None
if is_maximizing_player:
r = AlphaBeta.MIN_VAL
else:
r = AlphaBeta.MAX_VAL
actions = board.feasible_pos(player)
opponent = Board.opponent(player)
if len(actions) > 0:
for i,j in actions:
with board.flip2(i, j, player):
v, _ = self._alpha_beta_search(board, opponent,
alpha, beta,
depth-1, not is_maximizing_player)
if is_maximizing_player:
if r < v:
act = (i, j)
alpha = max(v, alpha)
r = max(r, v)
else:
if r > v:
act = (i, j)
beta = min(v, beta)
r = min(r, v)
if alpha >= beta:
break
else:
r, _ = self._alpha_beta_search(board, opponent,
alpha, beta,
depth, not is_maximizing_player)
return r, act
class Agent(object):
def __init__(self, role):
self._role = role
def play(self, board):
pass
def begin_of_game(self, board):
pass
def end_of_game(self, board):
pass
@property
def role(self):
return self._role
@role.setter
def role(self, value):
self._role = value
class Bot(Agent):
def __init__(self, evaluator, depth, final_depth, role):
super(Bot, self).__init__(role)
self._default_searcher = AlphaBeta(ScorerWrapper(role, evaluator),
depth)
self._final_searcher = AlphaBeta(ScorerWrapper(role, CountScorer()),
final_depth)
self._final_depth = final_depth
def _play(self, board):
if board.blanks <= self._final_depth:
r, action = self._final_searcher.search(board, self.role)
else:
r, action = self._default_searcher.search(board, self.role)
return r, action
def play(self, board):
return self._play(board)[1]
class HumanPlayer(Agent):
def __init__(self, role):
super(HumanPlayer, self).__init__(role)
def play(self, board):
pos = board.feasible_pos(self.role)
p = None
while True:
try:
l = raw_input("Enter your choise: ").strip().lower()
if l == "exit":
break
p = pos[ord(l.lower()) - ord("a")]
break
except:
pass
return p