Advertisement
Guest User

Untitled

a guest
Apr 19th, 2019
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.16 KB | None | 0 0
  1. import collections
  2. import math
  3. import itertools
  4. import time
  5. from PIL import ImageGrab
  6.  
  7. import win32api
  8. import win32con
  9.  
  10. INF = 1000000
  11.  
  12.  
  13. def PressKey(hexKeyCode):
  14. win32api.keybd_event(hexKeyCode, 0, 0, 0);
  15.  
  16. def ReleaseKey(hexKeyCode):
  17. win32api.keybd_event(hexKeyCode, 0, win32con.KEYEVENTF_KEYUP, 0)
  18.  
  19. # Actuals Functions
  20.  
  21.  
  22. # For each row define the shifts
  23. shiftLeft = [None for i in range(0xFFFF)]
  24. shiftRight = [None for i in range(0xFFFF)]
  25. shiftUp = {}
  26. shiftDown = {}
  27.  
  28. def genShiftResults():
  29. global shiftLeft, shiftRight, shiftUp, shiftDown
  30.  
  31. def row2Int(r, shift, reverse=False):
  32. if reverse:
  33. r = r[::-1]
  34. return (r[0] << (3*shift)) + (r[1] << (2*shift)) + (r[2] << shift) + r[3]
  35.  
  36. possible = list(range(0, 0xF))
  37. for a, b, c, d in itertools.product(possible, repeat=4):
  38. rowList = [a,b,c,d]
  39. newList = [0,0,0,0]
  40.  
  41. i = 0
  42. last = -1
  43. for j in range(4):
  44. if rowList[j] == last:
  45. newList[i-1] = rowList[j] + 1
  46. last = -1
  47. elif rowList[j] > 0:
  48. newList[i] = rowList[j]
  49. last = rowList[j]
  50. i += 1
  51.  
  52. shiftRight[row2Int(rowList, 4, False)] = row2Int(newList, 4, False)
  53. shiftLeft[row2Int(rowList, 4, True)] = row2Int(newList, 4, True)
  54.  
  55. shiftUp[row2Int(rowList, 16, True)] = row2Int(newList, 16, True)
  56. shiftDown[row2Int(rowList, 16, False)] = row2Int(newList, 16, False)
  57.  
  58.  
  59.  
  60. def getValue(state, x, y):
  61. t = (state >> (4 * (4 * y + x))) & 0xF
  62. assert 0 <= t <= 0xF
  63. return t
  64.  
  65. def modifiedState(state, x, y, val):
  66. assert 0 <= val <= 0xF
  67. maskB = 4 * (4 * y + x)
  68. state ^= (state & (0xF << maskB))
  69. state |= val << maskB
  70. return state
  71.  
  72. def printState(state):
  73. for y in range(4):
  74. for x in range(4):
  75. item = getValue(state, x, y)
  76. string = "{0:>4} ".format(2 ** item if item > 0 else "_")
  77. print(string, end="")
  78. print()
  79. print()
  80.  
  81. def children(state):
  82. # TODO: support 4's appearing and relative probability
  83. tempState = state
  84. for y in range(4):
  85. for x in range(4):
  86. if (tempState & 0xF) == 0:
  87. yield modifiedState(state, x, y, 2)
  88. tempState >>= 4
  89.  
  90. def shiftAbout(tempState, shiftArray, andMask, shift):
  91. new = 0
  92. for column in range(4):
  93. new |= shiftArray[tempState & andMask] << shift * column
  94. tempState >>= shift
  95. return new
  96.  
  97. def move(state, direction, gravity):
  98. global shiftLeft, shiftRight, shiftUp, shiftDown
  99. global columnMask
  100. # direction is 0,1
  101. # gravity is -1,1
  102.  
  103. if direction == 0 and gravity == 1:
  104. moved = shiftAbout(state, shiftLeft, 0xFFFF, 16)
  105.  
  106. elif direction == 0 and gravity == -1:
  107. moved = shiftAbout(state, shiftRight, 0xFFFF, 16)
  108.  
  109. elif direction == 1 and gravity == 1:
  110. moved = shiftAbout(state, shiftUp, 0xF000F000F000F, 4)
  111.  
  112. elif direction == 1 and gravity == -1:
  113. moved = shiftAbout(state, shiftDown, 0xF000F000F000F, 4)
  114.  
  115. return moved != state, moved
  116.  
  117.  
  118. # Aims to maximize heuristic
  119. #sqrtPieceHeuristic(state):
  120.  
  121.  
  122. # -150 to 0 range
  123. def heuristicSqrtPieces(state):
  124. heur = 0
  125. for y in range(4):
  126. for x in range(4):
  127. v = getValue(state, x, y)
  128. if v > 0:
  129. heur -= math.sqrt(1 << v)
  130. return heur
  131.  
  132.  
  133.  
  134. # -100 to 0 range
  135. def heuristicNotCentered(state):
  136. maxTile = max(getValue(state, x, y) for y in range(4) for x in range(4))
  137.  
  138. heur = 0
  139. for y in range(1,3):
  140. for x in range(1,3):
  141. v = getValue(state, x, y)
  142. # try to keep four largest on outside
  143. if v > (maxTile - 4):
  144. heur -= 10 * v
  145. return heur
  146.  
  147.  
  148. # 0 to 15 (higher is better)
  149. def heuristicBlanks(state):
  150. heur = 0
  151. for y in range(4):
  152. for x in range(4):
  153. piece = getValue(state, x, y)
  154. heur += piece == 0
  155. return heur
  156.  
  157.  
  158. calls = 0
  159. evaled = 0
  160. saved = {}
  161. def BeamAStarAlphaBeta(state, depth = 3):
  162. global calls, evaled, saved
  163.  
  164. calls += 1
  165.  
  166. key = (state, depth)
  167. temp = saved.get(key, None)
  168. if temp:
  169. return temp
  170.  
  171. evaled += 1
  172.  
  173. if depth == 0:
  174. heur = heuristicSqrtPieces(state)
  175. heur += heuristicNotCentered(state) / 2
  176. heur += 10 * heuristicBlanks(state)
  177. return (heur, state, "")
  178.  
  179. best = -INF
  180. bestAdvice = None
  181. bestResult = None
  182.  
  183. dirs = [("Left", 0, 1), ("Up", 1, 1), ("Right", 0, -1), ("Down", 1, -1)]
  184. for name, direction, gravity in dirs:
  185. legal, result = move(state, direction, gravity)
  186.  
  187. if legal:
  188. sumChildren = 0
  189. countChildren = 0
  190. for child in children(result):
  191. fitness, r, a = BeamAStarAlphaBeta(child, depth-1)
  192. sumChildren += fitness
  193. countChildren += 1
  194.  
  195. if countChildren > 0:
  196. avgChild = sumChildren / float(countChildren)
  197. else:
  198. avgChild = -INF
  199.  
  200. heuristic = avgChild
  201.  
  202. if heuristic > best:
  203. best = heuristic
  204. bestAdvice = name
  205. bestResult = result
  206.  
  207.  
  208. result = (best, bestResult, bestAdvice)
  209. saved[key] = result
  210. return result
  211.  
  212.  
  213. def main(activeTilesFromScreenCapture):
  214. global calls, evaled, saved
  215.  
  216. while True:
  217. time.sleep(0.40)
  218. state = activeTilesFromScreenCapture()
  219. printState(state)
  220.  
  221. tileToDepth = {512:4, 1024:5, 2048:5, 4096:5, 8192:6}
  222. maxTile = max(getValue(state, x, y) for x in range(4) for y in range(4))
  223. freeTiles = heuristicBlanks(state)
  224.  
  225. depth = tileToDepth.get(maxTile, 3) + (freeTiles < 5)
  226.  
  227. calls = 0
  228. evaled = 0
  229. saved = {}
  230. T0 = time.time()
  231. fitness, result, advice = BeamAStarAlphaBeta(state, depth)
  232. T1 = time.time() + 0.00001
  233.  
  234. print ("advice: {} : {:.3f} (depth: {} => {} calls {} evaled) ({:.1f} positons / s)".format(
  235. advice, fitness, depth, calls, evaled, evaled / (T1 - T0)))
  236. print ()
  237. print ()
  238.  
  239. keyMapping = {
  240. "Left" : 0x025,
  241. "Right" : 0x027,
  242. "Up" : 0x026,
  243. "Down" : 0x028
  244. }
  245.  
  246. key = keyMapping.get(advice)
  247. PressKey(key)
  248. time.sleep(0.05)
  249. ReleaseKey(key)
  250.  
  251.  
  252.  
  253. def calibrateScreen():
  254. # TODO: anything but this just please
  255.  
  256. # play with these numbers till you get the entire board
  257. cords = [225,352,720,852]
  258. img = ImageGrab.grab(cords)
  259.  
  260. width = cords[2] - cords[0]
  261. height = cords[3] - cords[1]
  262. #print (width, height)
  263.  
  264. # Squirrel math that hopefully works for you
  265. average = (width + height) // 2
  266. margins = int(average * 0.15)
  267. margin = margins // 4
  268. squareSize = (average - margins) // 4
  269. #print (squareSize)
  270.  
  271. squareOffset = margin + squareSize // 12
  272.  
  273. tileCords = [[None for i in range(4)] for j in range(4)]
  274.  
  275. for x in range(12):
  276. for y in range(10):
  277. purple = 255*255*255 + 255*255
  278. img.putpixel((squareSize+margin+x, squareSize+margin+y), purple)
  279.  
  280. for xSquare in range(4):
  281. for ySquare in range(4):
  282. xStart = squareOffset + (squareSize + margin) * xSquare
  283. yStart = squareOffset + (squareSize + margin) * ySquare
  284. tileCords[xSquare][ySquare] = (xStart,yStart)
  285.  
  286. # for i in range(10):
  287. # for j in range(10):
  288. # img.putpixel((xStart+i, yStart+j), 255 * 255)
  289.  
  290. # img.show()
  291.  
  292. def activeTilesFromScreenCapture():
  293. img = ImageGrab.grab(cords)
  294. state = 0
  295. for x in range(4):
  296. for y in range(4):
  297. tileType = {
  298. (238, 228, 218) : 1,
  299. (237, 224, 200) : 2,
  300. (242, 177, 121) : 3,
  301. (245, 149, 99) : 4,
  302. (246, 124, 95) : 5,
  303. (246, 94, 59) : 6,
  304. (237, 207, 114) : 7,
  305. (237, 204, 97) : 8,
  306. (237, 200, 80) : 9,
  307. (237, 197, 63) : 10,
  308. (237, 194, 46) : 11
  309. }
  310. pixel = img.getpixel((tileCords[x][y]))
  311. tType = tileType.get(pixel, -1)
  312. if (abs(pixel[0] - 204) +
  313. abs(pixel[1] - 192) +
  314. abs(pixel[2] - 179)) < 10:
  315. tType = 0
  316.  
  317. if tType < 0:
  318. print (pixel, tType, "??? Pausing for 5s")
  319. time.sleep(5)
  320. return activeTilesFromScreenCapture()
  321.  
  322. state = modifiedState(state, x, y, tType)
  323. return state
  324.  
  325. return activeTilesFromScreenCapture
  326.  
  327.  
  328. if __name__ == "__main__":
  329. genShiftResults()
  330.  
  331. activeTilesFromScreenCapture = calibrateScreen()
  332. start = activeTilesFromScreenCapture()
  333. print (start)
  334.  
  335. '''
  336. dirs = [("Left", 0, 1), ("Up", 1, 1), ("Right", 0, -1), ("Down", 1, -1)]
  337. for name, direction, gravity in dirs:
  338. legal, result = move(start, direction, gravity)
  339. print (name, legal)
  340. printState(result)
  341.  
  342. #'''
  343. main(activeTilesFromScreenCapture)
  344.  
  345.  
  346.  
  347. # v4 was 15000 evaled / second
  348. # v5 was 17000 evaled / second
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement