#!/bin/sh
# A (bad) Bejeweled 2 solver
# by Phillip Berndt, 2010
#
import gtk
import struct
import time
import os
from numpy import *

# Take a screenshot
wnd = gtk.gdk.get_default_root_window()
width, height = wnd.get_size()
pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, width, height)
pixbuf.get_from_drawable(wnd, wnd.get_colormap(), 0, 0, 0, 0, width, height)
data = pixbuf.get_pixels_array()

# Search for upper-left side of field
# Generated using C-Sourcecode output mode of The GIMP
search = array(struct.unpack("144B", 
  "\252\251\312\377nl\260\377FC\210\377^W\237\377YT\241\377;7\224\377jh\253"
  "\377JF\211\377JE\222\377=7{\377:3S\37781-\377FC\210\377D@\221\377@:\202\377"
  "92-\37792-\3776/+\377XR\236\377D=\204\377?5B\377;3/\37770,\377:2/\377OJ\235"
  "\377@6K\377;1.\377;3/\37792.\37770,\377JE\232\377@6C\377<2/\377;2.\377;4"
  "0\37781,\377")).reshape(6, 6, 4)

foundAt = False
for x in arange(width):
	print "Searching ", x, "\r", 
	if foundAt: break
	for y in arange(height):
		if all(data[y:(y+6), x:(x+6)] == search):
			foundAt = x, y
			break

if not foundAt:
	print "Did not find field"

while True:
	# Take another screenshot
	pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, width, height)
	pixbuf.get_from_drawable(wnd, wnd.get_colormap(), 0, 0, 0, 0, width, height)
	data = pixbuf.get_pixels_array()

	# Read the whole field
	gems = zeros((8, 8))
	for x in arange(8):
		for y in arange(8):
			# Go to a point somewhere inside a slot
			point = data[foundAt[1] + 37 * y + 20, foundAt[0] + 39 * x + 22]

			# These values are guesses. Could be improved. (Does not detect everything atm, but
			# abound 90%)
			if point[0] > 235 and point[1] > 120 and point[0] - 30 > point[1] and point[2] < 110:
				# Orange
				gems[y, x] = 1
			elif point[0] > 250 and point[1] < 110 and point[2] < 110:
				# Red
				gems[y, x] = 2
			elif point[0] < 120 and point[1] > 190 and point[2] < 120:
				# Green
				gems[y, x] = 3
			elif point[0] < 70 and ((point[1] < 200 and point[2] > 240) or (point[1] < 95 and point[2] > 170)):
				# Blue
				gems[y, x] = 4
			elif point[0] > 200 and point[1] > 200 and point[2] < 90:
				# Yellow
				gems[y, x] = 5
			elif (point[0] > 200 and point[1] < 110 and point[2] > 200) or (point[0] > 30 and point[1] < 10 and point[2] > 30):
				# Violett
				gems[y, x] = 6
			elif point[0] > 200 and point[1] > 200 and point[2] > 200:
				# White
				gems[y, x] = 7
			print "%d,%d:" % (x,y), str(point) + " detected as " + str(gems[y, x])

	# Determine if a move is valid
	def is_valid(field, debug=0):
		for x in arange(8):
			for y in arange(8 - 2):
				if all(field[y:y+3, x] == field[y, x]) and field[y, x] != 0:
					print "Valid because of ", field[y:y+3, x]
					return True
		for y in arange(8):
			for x in arange(8 - 2):
				if all(field[y, x:x+3] == field[y, x]) and field[y, x] != 0:
					print "Valid because of ", field[y, x:x+3]
					return True
		return False
	lastTry = False
	def dtry():
		# Try to find a valid mode
		# Just try everything and check with is_valid
		global lastTry
		for x in arange(7):
			for y in arange(8):
				cpy = gems.copy()

				tmp = cpy[y,x+1]
				cpy[y,x+1] = cpy[y,x]
				cpy[y,x] = tmp

				if is_valid(cpy):
					if lastTry != False and lastTry == (y, x, y, x+1):
						continue
					print "Valid one: "
					print cpy
					lastTry = y, x, y, x+1
					return y, x, y, x+1
		for x in arange(8):
			for y in arange(7):
				cpy = gems.copy()
				
				tmp = cpy[y+1,x]
				cpy[y+1,x] = cpy[y,x]
				cpy[y,x] = tmp

				if x == 7 and y == 3:
					is_valid(cpy, 1)
				if is_valid(cpy):
					if lastTry != False and lastTry == (y, x, y, x+1):
						continue
					print "Valid one: "
					print cpy
					lastTry = y, x, y, x+1
					return y, x, y+1, x
		return False
	# Choose a move to make
	res = dtry()
	print "Found at", foundAt
	print lastTry
	print gems
	print res
	if not res:
		print "Argh"
	else:
		y, x, ny, nx = res
		# Use xdotool to simulate a mouse click
		os.system("xdotool mousemove %d %d" % ( (foundAt[0] + 39 * x + 22) * 1, (foundAt[1] + 37 * y + 20) * 1 ))
		os.system("xdotool click 1")
		os.system("xdotool mousemove %d %d" % ( (foundAt[0] + 39 * nx + 22) * 1, (foundAt[1] + 37 * ny + 20) * 1 ))
		os.system("xdotool click 1")

	if res == False or res == (0, 0, 0, 1):
		# Click (possible) dialogs
		os.system("xdotool mousemove %d %d" % ( (foundAt[0] + 200) * 1, (foundAt[1] + 287) ))
		os.system("xdotool click 1")
		os.system("xdotool mousemove %d %d" % ( (foundAt[0] + 82) * 1, (foundAt[1] + 166) ))
		os.system("xdotool click 1")
		os.system("xdotool mousemove %d %d" % ( (foundAt[0] + 200) * 1, (foundAt[1] + 113) ))
		os.system("xdotool click 1")

	os.system("xdotool mousemove %d %d" % ( foundAt[0] - 10, foundAt[1]))
	time.sleep(1)
