Advertisement
Guest User

Untitled

a guest
Feb 13th, 2016
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.76 KB | None | 0 0
  1. WIDTH, HEIGHT = 7, 6
  2. INFINITY = float('inf')
  3.  
  4. SEARCHDEPTH = 4
  5.  
  6. THREEWEIGHT = 1.0
  7. TWOWEIGHT = 0.1
  8. ONEWEIGHT = 0.01
  9. HEIGHTPENALTY = 0.2
  10.  
  11. N = (0, 1)
  12. S = (0, -1)
  13. W = (-1, 0)
  14. E = (1, 0)
  15.  
  16. SW = (-1, -1)
  17. NW = (-1, 1)
  18. SE = (1, -1)
  19. NE = (1, 1)
  20.  
  21.  
  22. def tuple_add(t1, t2):
  23. return (t1[0]+t2[0], t1[1]+t2[1])
  24.  
  25. def reverse_dir(direction):
  26. return (-direction[0], -direction[1])
  27.  
  28. class WallError(Exception):
  29. pass
  30.  
  31. class Pointer(object):
  32. def __init__(self, board_ins, x=0, y=0):
  33. self.x = x
  34. self.y = y
  35. self.brd = board_ins
  36.  
  37. @property
  38. def position(self):
  39. return (self.x, self.y)
  40.  
  41. @position.setter
  42. def position(self, pos):
  43. w=self.brd.width
  44. h=self.brd.height
  45.  
  46. if 0 <= pos[0] < w and 0 <= pos[1] < h:
  47. self.x, self.y = pos
  48. else:
  49. raise WallError, ('No such position:', pos)
  50.  
  51. def advance(self, direction):
  52. self.position = tuple_add(self.position, direction)
  53.  
  54. @property
  55. def contents(self):
  56. return self.brd.field(self.position)
  57.  
  58. @property
  59. def voids_beneath(self):
  60. return self.y-self.brd.chips[self.x]
  61.  
  62. def copy(self):
  63. return Pointer(self.brd, self.x, self.y)
  64.  
  65. def has_room(self, direction, n):
  66. x = self.x+direction[0]*n
  67. y = self.y+direction[1]*n
  68. w = self.brd.width
  69. h = self.brd.height
  70.  
  71. return 0 <= x < w and 0 <= y < h
  72.  
  73. def home(self):
  74. self.position=(0,0)
  75.  
  76. class Board(object):
  77. def __init__(self, w, h, turn=1, reps=None):
  78. self.array = [[0]*h for i in range(w)]
  79. self.turn = turn
  80. self.width = w
  81. self.height = h
  82. self.chips = [0]*w
  83. self.lastplayed = 0
  84.  
  85. self.optimcols = range(w/4, 3*w/4)+range(w/4)+range(3*w/4, w)
  86. self.eval_values = [0, ONEWEIGHT, TWOWEIGHT, THREEWEIGHT, INFINITY]
  87. self.height_coeff = 1-HEIGHTPENALTY
  88.  
  89. if reps is None:
  90. self.reps = {1:'X',
  91. -1:'O',
  92. 0:'_'}
  93. else:
  94. self.reps = reps
  95.  
  96. def field(self, x=0, y=0):
  97. if isinstance(x, tuple):
  98. x, y = x
  99. return self.array[x][y]
  100.  
  101. def play(self, col=None):
  102. if col is None:
  103. col = self.lastplayed
  104. if not 0 <= col < self.width:
  105. raise WallError, 'No such column'
  106. if self.chips[col] < self.height:
  107. self.chips[col] += 1
  108. self.array[col][self.chips[col]-1] = self.turn
  109. self.turn = -self.turn
  110. self.lastplayed = col
  111. else:
  112. raise WallError, 'Column full.'
  113.  
  114. def unplay(self, col=None):
  115. if col is None:
  116. col = self.lastplayed
  117. if not 0 <= col < self.width:
  118. raise WallError, 'No such column'
  119. if self.chips[col] > 0:
  120. self.turn = -self.turn
  121. self.array[col][self.chips[col]-1] = 0
  122. self.chips[col] -= 1
  123. else:
  124. raise WallError, 'Column empty.'
  125.  
  126. def empty_and_players(self, player=None):
  127. if player is None:
  128. player=self.turn
  129. for x in self.optimcols:
  130. for y in range(self.height):
  131. if self.array[x][y] in (player, 0):
  132. yield Pointer(self, x, y)
  133.  
  134. def possible_moves(self):
  135. for x in range(self.width):
  136. if self.chips[x] < self.height:
  137. yield x
  138.  
  139. def is_full(self):
  140. return sum(self.chips) == self.width*self.height
  141.  
  142. def evaluate(self, player=0):
  143. player = player or -self.turn
  144. dirs = [N, NW, W, SW, S, SE, E, NE]
  145. score = 0
  146. try:
  147. for i in [-1, 1]:
  148. self.evaluated_array = [[list() for k in range(self.height)]
  149. for j in range(self.width)]
  150. for field in self.empty_and_players(player*i):
  151. x, y = field.position
  152. for direction in dirs:
  153. if ((1 or direction not in self.evaluated_array[x][y]) and
  154. field.has_room(direction, 3)):
  155. assert field.contents!=-player*i
  156. score+=self._evaluate_seq(field, direction, player*i)*i
  157. field.position = (x,y)
  158. if score == INFINITY or score == -INFINITY:
  159. raise StopIteration
  160. except StopIteration:
  161. pass
  162. return score
  163.  
  164. def _evaluate_seq(self, pointer, direction, player):
  165. filled = 0
  166. first_zero_h = None
  167. last_zero_h = None
  168. assert pointer.contents in (player, 0)
  169. for i in range(4):
  170. if pointer.contents == -player:
  171. return 0
  172. elif pointer.contents == 0:
  173. last_zero_h = pointer.voids_beneath
  174. if first_zero_h is None:
  175. first_zero_h = last_zero_h
  176. elif pointer.contents == player:
  177. filled += 1
  178. if i < 3:
  179. pointer.advance(direction)
  180.  
  181. score = self.eval_values[filled]
  182. x, y = pointer.position
  183. self.evaluated_array[x][y].append(reverse_dir(direction))
  184.  
  185. if score == INFINITY:
  186. return score
  187. elif not score:
  188. return score
  189.  
  190. heightw = self.height_coeff ** min(first_zero_h, last_zero_h)
  191. return score * heightw
  192.  
  193. def get_best_move(self, search_depth, fp=None, alpha=-INFINITY, beta=INFINITY):
  194. if fp is None:
  195. fp = self.turn
  196. max_ = (-INFINITY, 0)
  197. player = -self.turn
  198. if search_depth == 0:
  199. max_ = (self.evaluate(fp), 0)
  200. else:
  201. for col in self.possible_moves():
  202. self.play(col)
  203. cur = -self.get_best_move(search_depth-1, -fp, -beta, -alpha)[0]
  204. self.unplay(col)
  205. max_ = max((cur, col), max_)
  206. alpha = max(alpha, cur)
  207. if alpha >= beta:
  208. break
  209. return max_
  210.  
  211. def __str__(self):
  212. out = ''
  213. for row in range(self.height-1, -1, -1):
  214. out += '\n|'
  215. for col in range(self.width):
  216. out += self.reps[self.array[col][row]]+'|'
  217. out += '\n ' + ' '.join([str(i) for i in range(self.width)])
  218. return out
  219.  
  220.  
  221.  
  222. m = Board(WIDTH, HEIGHT,-1)
  223. while not (abs(m.evaluate()) == INFINITY or m.is_full()):
  224. if m.turn==-1:
  225. where=int(raw_input('Your turn: '))
  226. m.play(where)
  227. print m
  228. else:
  229. print 'My turn...'
  230. m.play(m.get_best_move(SEARCHDEPTH)[1])
  231. print m
  232.  
  233. b = m.evaluate(1)
  234. if b == -INFINITY:
  235. print 'You won.'
  236. elif b == INFINITY:
  237. print 'You lost.'
  238. else:
  239. print 'A tie.'
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement