Created
December 18, 2014 07:39
-
-
Save amitn/470909939c950f3fb99a to your computer and use it in GitHub Desktop.
Threes solver using OpenCV and Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import cv2 | |
import numpy as np | |
import glob | |
SAMPLES_SIZE = 2001 | |
SAMPLES = np.empty((0, SAMPLES_SIZE)) | |
RESPONSES = [] | |
def learnCard(I, num): | |
global SAMPLES | |
global RESPONSES | |
sample = I.reshape((1, SAMPLES_SIZE)) | |
SAMPLES = np.append(SAMPLES, sample, 0) | |
RESPONSES.append(int(num)) | |
def readDir(num): | |
for fileName in glob.glob("./cards/" + str(num) + "/*.png"): | |
print fileName | |
I = cv2.imread(fileName) | |
learnCard(I, num) | |
if __name__ == "__main__": | |
global SAMPLES | |
global RESPONSES | |
for num in (0, 1, 2, 3, 6, 12, 24, 48, 96, 192, 384, 768): | |
readDir(num) | |
RESPONSES = np.array(RESPONSES, np.int32) | |
RESPONSES = RESPONSES.reshape((RESPONSES.size, 1)) | |
np.savetxt("train_samples.data", SAMPLES) | |
np.savetxt("train_responses.data", RESPONSES) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import cv2 | |
import numpy as np | |
import glob | |
SAMPLES_SIZE = 288 | |
SAMPLES = np.empty((0, SAMPLES_SIZE)) | |
RESPONSES = [] | |
def learnCard(I, num): | |
global SAMPLES | |
global RESPONSES | |
sample = I.reshape((1, SAMPLES_SIZE)) | |
SAMPLES = np.append(SAMPLES, sample, 0) | |
RESPONSES.append(int(num)) | |
def readDir(num): | |
for fileName in glob.glob("./next_card/" + str(num) + "/*.png"): | |
print fileName | |
I = cv2.imread(fileName) | |
learnCard(I, num) | |
if __name__ == "__main__": | |
global SAMPLES | |
global RESPONSES | |
for num in (1, 2, 3, 6): | |
readDir(num) | |
RESPONSES = np.array(RESPONSES, np.int32) | |
RESPONSES = RESPONSES.reshape((RESPONSES.size, 1)) | |
np.savetxt("train_samples_next.data", SAMPLES) | |
np.savetxt("train_responses_next.data", RESPONSES) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import cv2 | |
import numpy as np | |
import random | |
import socket | |
import time | |
import ThreesSolver | |
CARD_H = 185 | |
CARD_W = 135 | |
CARD_H_SUB = 40 | |
CARD_W_SUB = 20 | |
CARD_NUM = 0 | |
NUM = 0 | |
SCALE = 0.2 | |
SAMPLES_SIZE_CARD = 2001 | |
SAMPLES_SIZE_NEXT = 288 | |
MODEL = None | |
MODEL_NEXT = None | |
DEBUG = False | |
#DEBUG = True | |
def doModel(name): | |
SAMPLES = np.loadtxt("train_samples%s.data" % (name), np.float32) | |
RESPONSES = np.loadtxt("train_responses%s.data" % (name), np.int32) | |
RESPONSES = RESPONSES.reshape((RESPONSES.size, 1)) | |
MODEL = cv2.KNearest() | |
MODEL.train(SAMPLES, RESPONSES) | |
return MODEL | |
def iview(I): | |
global NUM | |
s = "NUM%03d" % (NUM) | |
cv2.imshow(s, I) | |
NUM += 1 | |
return s | |
class GameCard(object): | |
def __init__(self, I, debug=False): | |
global CARD_NUM | |
global SCALE | |
self.I = I[20:-20, 10:-10] | |
#self.G = cv2.cvtColor(self.I, cv2.COLOR_BGR2GRAY) | |
self.s = cv2.resize(self.I, None, fx=SCALE, fy=SCALE) | |
self.num = 0 | |
if debug: | |
cv2.imwrite("cards/card_%03d.png" % (CARD_NUM), self.s) | |
CARD_NUM += 1 | |
else: | |
self.findNum() | |
def findNum(self): | |
global MODEL | |
sample = self.s.reshape((1, SAMPLES_SIZE_CARD)) | |
sample = np.float32(sample) | |
retval, results, neigh_resp, dists = MODEL.find_nearest(sample, k=1) | |
self.num = int(results[0][0]) | |
def onMouseEvent(event, x, y, flags, param): | |
if (cv2.EVENT_LBUTTONDBLCLK == event): | |
print "(%d, %d)" % (x, y) | |
def cutCards(I, nCard): | |
global DEBUG | |
H = CARD_H | |
W = CARD_W | |
b = ThreesSolver.Board() | |
for i in range(4): | |
for j in range(4): | |
iT = I[i * H:(i + 1) * H, j * W:(j + 1) * W] | |
c = GameCard(iT, DEBUG) | |
b.board[i, j] = c.num | |
if DEBUG: | |
MOVES = ("LEFT", "RIGHT", "DOWN", "UP") | |
return "SCREEN" | |
return random.choice(MOVES) | |
return b.checkAllMoves(nCard) | |
class NextCard(object): | |
def __init__(self, I, debug): | |
global SCALE | |
self.I = I[125:185, 340:380] | |
self.s = cv2.resize(self.I, None, fx=SCALE, fy=SCALE) | |
self.num = 0 | |
if debug: | |
self.saveImage() | |
else: | |
self.getNum() | |
def saveImage(self): | |
global CARD_NUM | |
cv2.imwrite("next_card/card_%03d.png" % (CARD_NUM), self.s) | |
CARD_NUM += 1 | |
def getNum(self): | |
global MODEL_NEXT | |
sample = self.s.reshape((1, SAMPLES_SIZE_NEXT)) | |
sample = np.float32(sample) | |
retval, results, neigh_resp, dists = MODEL_NEXT.find_nearest(sample, k=1) | |
self.num = int(results[0][0]) | |
def cutBoard(I): | |
B = I[340:1080, 90:630] | |
return B | |
def ProssesGame(): | |
global DEBUG | |
iSCR = cv2.imread("shot1.png") | |
cv2.imshow('Screen', iSCR) | |
nCard = NextCard(iSCR, DEBUG) | |
iBRD = cutBoard(iSCR) | |
#cv2.imshow('Board', iBRD) | |
#cv2.setMouseCallback('Screen', onMouseEvent) | |
nextMove = cutCards(iBRD, nCard.num) | |
cv2.destroyAllWindows() | |
return nextMove | |
def getScreen(s): | |
time.sleep(1) | |
s.send("SCREEN") | |
time.sleep(0.3) | |
s.recv(64) | |
def randomMove(s): | |
s.send("MOVE") | |
time.sleep(0.3) | |
s.recv(64) | |
def sendMove(s, m): | |
s.send(m) | |
s.recv(64) | |
if __name__ == "__main__": | |
global MODEL | |
global MODEL_NEXT | |
cSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
cSocket.connect(("localhost", 4456)) | |
MODEL = doModel("") | |
MODEL_NEXT = doModel("_next") | |
while True: | |
getScreen(cSocket) | |
nextMove = ProssesGame() | |
sendMove(cSocket, nextMove) | |
#randomMove(cSocket) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env monkeyrunner | |
from com.android.monkeyrunner import MonkeyRunner | |
import random | |
import time | |
import socket | |
MOVES = ("LEFT", "RIGHT", "DOWN", "UP") | |
def doMove(device, c, move): | |
if move in "LEFT": | |
device.drag(c, (c[0] - 100, c[1]), 0.3, 15) | |
elif move in "RIGHT": | |
device.drag(c, (c[0] + 100, c[1]), 0.3, 15) | |
elif move in "DOWN": | |
device.drag(c, (c[0], c[1] + 100), 0.3, 15) | |
elif move in "UP": | |
device.drag(c, (c[0], c[1] - 100), 0.3, 15) | |
time.sleep(0.3) | |
def randomMove(device, c): | |
i = random.randint(0,3) | |
doMove(device, c, MOVES[i]) | |
def takeSnapshot(device): | |
result = device.takeSnapshot() | |
## Writes the screenshot to a file | |
result.writeToFile('shot1.png', 'png') | |
if __name__ == "__main__": | |
device = MonkeyRunner.waitForConnection() | |
W = device.getProperty('display.width') | |
H = device.getProperty('display.height') | |
c = (int(W) / 2, int(H) / 2) | |
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | |
server.bind(('localhost', 4456)) | |
server.listen(5) | |
while True: | |
cn, addr = server.accept() | |
while True: | |
buf = cn.recv(64) | |
if not buf: | |
break | |
if len(buf) > 0: | |
print buf | |
if "MOVE" in buf: | |
randomMove(device, c) | |
elif "SCREEN" in buf: | |
takeSnapshot(device) | |
elif buf in MOVES: | |
doMove(device, c, buf) | |
cn.send("OK") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import numpy | |
import copy | |
import random | |
import sys | |
import string | |
BOARD_SIZE = 4 | |
MOVE_UP = (-1, 0) | |
MOVE_DOWN = (1, 0) | |
MOVE_LEFT = (0, -1) | |
MOVE_RIGHT = (0, 1) | |
MOVES = (MOVE_UP, MOVE_DOWN, MOVE_LEFT, MOVE_RIGHT) | |
MOVES_STRING = ("UP", "DOWN", "LEFT", "RIGHT") | |
UP_DOWN_LEFT_RIGHT = ((MOVE_UP, MOVE_DOWN), (MOVE_LEFT, MOVE_RIGHT)) | |
def isValidLocation(s): | |
if (s[0] < 0 or s[1] < 0 or s[0] >= BOARD_SIZE or s[1] >= BOARD_SIZE): | |
return False | |
return True | |
def addPoints(s, d): | |
return (s[0] + d[0], s[1] + d[1]) | |
def mergeScore(v1, v2): | |
if v1 > 2 and v2 > 2 and v1 == v2: | |
return 2 | |
if v1 != 0 and v2 != 0 and v1 + v2 == 3: | |
return 2 | |
return 0 | |
def canMerge(v1, v2): | |
if v1 > 2 and v2 > 2 and v1 == v2: | |
return True | |
if v1 != 0 and v2 != 0 and v1 + v2 == 3: | |
return True | |
return False | |
class Board(object): | |
def __init__(self): | |
self.board = numpy.zeros((BOARD_SIZE, BOARD_SIZE), dtype=numpy.uint16) | |
self.wasMoved = False | |
self.depth = 0 | |
def getScore(self): | |
score = 0.0 | |
for i in range(BOARD_SIZE): | |
for j in range(BOARD_SIZE): | |
s = (i, j) | |
if (self.board[s] == 0): | |
score += 4 | |
score += self.checkAllMerges(s) | |
score += self.checkLock(s) | |
#score += self.checkNextMerges(s) | |
return score | |
def checkAllMerges(self, s): | |
score = 0 | |
for m in (MOVE_DOWN, MOVE_RIGHT): | |
d = addPoints(s, m) | |
if isValidLocation(d): | |
score += mergeScore(self.board[s], self.board[d]) | |
return score | |
def checkNextMerges(self, s): | |
score = 0 | |
return 0 | |
for m in (MOVE_DOWN, MOVE_RIGHT): | |
d = addPoints(s, m) | |
if isValidLocation(d) and self.board[s] > 0: | |
if self.board[s] * 2 == self.board[d]: | |
score += 1 | |
if self.board[s] == self.board[d] * 2: | |
score += 1 | |
return score | |
def checkLock(self, s): | |
return 0 | |
score = 0 | |
for (t1, t2) in UP_DOWN_LEFT_RIGHT: | |
d1 = addPoints(s, t1) | |
d2 = addPoints(s, t2) | |
if isValidLocation(d1) and isValidLocation(d2): | |
c = self.board[s] | |
v1 = self.board[d1] | |
v2 = self.board[d2] | |
if (c + v1 != 3 and c + v2 != 3 and c < v1 and c < v2): | |
score += -1 | |
return score | |
def doMove(self, m): | |
self.wasMoved = False | |
movedLocation = [] | |
for outer in range(BOARD_SIZE): | |
wasMoved = False | |
for inner in range(1, BOARD_SIZE): | |
if (m == MOVE_UP or m == MOVE_DOWN): | |
j = outer | |
if m == MOVE_UP: | |
i = inner | |
else: | |
i = BOARD_SIZE - 1 - inner | |
else: | |
i = outer | |
if m == MOVE_LEFT: | |
j = inner | |
else: | |
j = BOARD_SIZE - 1 - inner | |
s = (i, j) | |
d = addPoints(s, m) | |
if (self.board[d] == 0 and self.board[s] > 0): | |
self.board[d] = self.board[s] | |
self.board[s] = 0 | |
wasMoved = True | |
elif canMerge(self.board[s], self.board[d]): | |
self.board[d] += self.board[s] | |
self.board[s] = 0 | |
wasMoved = True | |
movedLocation.append(wasMoved) | |
nextIndex = -1 | |
t = [] | |
for nextIndex in range(4): | |
if (movedLocation[nextIndex]): | |
self.wasMoved = True | |
ml = (-1, -1) | |
if (m == MOVE_LEFT): | |
ml = (nextIndex, BOARD_SIZE - 1) | |
elif (m == MOVE_RIGHT): | |
ml = (nextIndex, 0) | |
elif (m == MOVE_DOWN): | |
ml = (0, nextIndex) | |
elif (m == MOVE_UP): | |
ml = (BOARD_SIZE - 1, nextIndex) | |
t.append(ml) | |
return t | |
def checkAllMoves(self, nV): | |
allScores = [] | |
allBoards = [] | |
allDir = [] | |
mi = 0 | |
for m in MOVES: | |
newBoard = copy.deepcopy(self) | |
nextCardLocations = newBoard.doMove(m) | |
if (newBoard.wasMoved): | |
score = 0 | |
nscore = 0 | |
for ncl in nextCardLocations: | |
newBoard.board[ncl] = nV | |
score += newBoard.getScore() | |
nscore += 1 | |
for mm in MOVES: | |
newBoardNew = copy.deepcopy(newBoard) | |
newBoardNew.doMove(mm) | |
if (newBoardNew.wasMoved): | |
score += newBoardNew.getScore() | |
nscore += 1 | |
newBoard.board[ncl] = 0 | |
score = score / nscore | |
allScores.append(score) | |
allBoards.append(newBoard) | |
allDir.append(MOVES_STRING[mi]) | |
mi += 1 | |
#print allScores | |
#for b in allBoards: | |
print nV | |
print self.board | |
print allScores | |
i = allScores.index(max(allScores)) | |
return allDir[i] | |
#return allBoards[i] | |
def ReadBoard(B): | |
for i in range(BOARD_SIZE): | |
print "Enter Line %d" % (i) | |
line = sys.stdin.readline() | |
sline = string.split(line, " ") | |
for j in range(BOARD_SIZE): | |
B.board[(i, j)] = int(sline[j]) | |
if __name__ == "__main__": | |
B = Board() | |
ReadBoard(B) | |
while (True): | |
print B.getScore() | |
print "Enter next:" | |
line = sys.stdin.readline() | |
nV = int(line) | |
B = B.checkAllMoves(nV) | |
print B.board | |
for xx in range(2): | |
print "Fix Board i j v:" | |
line = sys.stdin.readline() | |
sline = string.split(line, " ") | |
i = int(sline[0]) | |
j = int(sline[1]) | |
v = int(sline[2]) | |
B.board[(i, j)] = v |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment