# This is for Windows to play Piano Tiles 2 on BlueStacks. # Install Python 3, then install pywin32 via PowerShell # pip3 install pywin32 # Then run this code via PowerShell # python3 pianoTiles2win.py # You will likely have to change y and tileWidth in this code. # This code will stop on its own after you lose. # To prematurely stop Piano Tiles 2, you can press "esc" during run. # I mostly want to use this on the Master hall, # which means that I don't have to worry about programming long clicks for long tiles # because time (not score) is important, and I don't have to worry about things # like slider tiles! # For Pianist Challenge... # Orange slidey tiles, starburst tiles, and huge multi-click tiles cause problems. # Songs that produce sparkly graphics for every tap can cause problems. # These are from the pywin32 module... import win32gui import win32ui import win32con import win32api # I used the following as guides: # https://stackoverflow.com/questions/3586046/fastest-way-to-take-a-screenshot-with-python-on-windows # https://stackoverflow.com/questions/1181464/controlling-mouse-with-python # I did not use pyautogui (used pywin32 instead) because pyautogui is very slow. # tap mindlessly (True) or intelligently (False) # mindless tapping should allow the rare combo (tap-many-times) tiles to be completed mindlessTaps = False # start with Piano Tiles 2 (in BlueStacks) on upper-left of screen # x increases left to right from 0 to width-1 (measured in pixels) # y increases top to bottom from 0 to height-1 (measured in pixels) y = 450 + 60 #y = 800 tileWidth = 90 x1 = 15 # don't start at center of tile else long tiles can give problems x2 = x1 + tileWidth x3 = x1 + 2*tileWidth x4 = x1 + 3*tileWidth w = 3*tileWidth+1 h = 1 # since rgb aren't exactly 0 on tiles (partly due to BlueStacks and also due to long tiles), # set a tolerance that is an integer less than 256 cap = 20 # After how many cycles to stop? # Set this high if game in BlueStacks often pauses for a few moments. # I usually don't have to wait for this since the code can stop in other ways. # Having this is VERY important else you can stuck not being able to use your computer! stopCounter = 1000 # my tap/click function def clickk(xx,yy): win32api.SetCursorPos((xx,yy)) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,xx,yy,0,0) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,xx,yy,0,0) print("It may be wise to fully restart the Piano Tiles 2 app or BlueStacks!") print("Put Piano Tiles 2 in BlueStacks on upper-left of screen!") response = int(input("Where is the start tile (1, 2, 3, or 4)?: ")) if response == 1: xs = x1; elif response == 2: xs = x2; elif response == 3: xs = x3; elif response == 4: xs = x4; else: print("script terminating") quit() # tap the start tile! clickk(xs,y) # A cute function using bitwise operators. # Seems that pywin32 actually gives a BGR integer (RGB is reversed), # so the following function has been changed to work with pywin32. def rgbint2rgbtuple(RGBint): red = RGBint & 255 green = (RGBint >> 8) & 255 blue = (RGBint >> 16) & 255 return (red, green, blue) # setup for taking screenshots #hwnd = win32gui.FindWindow(None, "BlueStacks") wDC = win32gui.GetWindowDC(0) # using 0 seems to select the entire screen dcObj=win32ui.CreateDCFromHandle(wDC) cDC=dcObj.CreateCompatibleDC() im = win32ui.CreateBitmap() im.CreateCompatibleBitmap(dcObj, w, h) # use the same w and h when taking screenshot in loop cDC.SelectObject(im) state = [0,0,0,0] counter = 0 while counter < stopCounter: counter += 1 # capture screen cDC.BitBlt((0,0),(w,h) , dcObj, (x1,y), win32con.SRCCOPY) #im.SaveBitmapFile(cDC, "temp.bmp") # grab pixel info r1, g1, b1 = rgbint2rgbtuple(cDC.GetPixel(0, 0)) r2, g2, b2 = rgbint2rgbtuple(cDC.GetPixel(tileWidth, 0)) r3, g3, b3 = rgbint2rgbtuple(cDC.GetPixel(2*tileWidth, 0)) r4, g4, b4 = rgbint2rgbtuple(cDC.GetPixel(3*tileWidth, 0)) #print((r1, g1, b1), (r2, g2, b2), (r3, g3, b3), (r4,g4,b4)) stateNow = [0,0,0,0] if (r1+g1+b1)/3 < cap: stateNow[0]=1; if mindlessTaps: clickk(x1,y) if (r2+g2+b2)/3 < cap: stateNow[1]=1; if mindlessTaps: clickk(x2,y) if (r3+g3+b3)/3 < cap: stateNow[2]=1; if mindlessTaps: clickk(x3,y) if (r4+g4+b4)/3 < cap: stateNow[3]=1; if mindlessTaps: clickk(x4,y) # quit right away if things look weird (because waiting for counter is annoying) if sum(stateNow)>2: print("More than 2 tiles were found, so quitting!") print("This is likely due to the screen going black for a moment at end of game.") quit() # A minor fix to deal with slow screen update when tapping double tiles. if (state==[0,1,0,1] and stateNow==[0,0,0,1]) or (state==[1,0,1,0] and stateNow==[0,0,1,0]): stateNow = state if (stateNow != state and stateNow != [0,0,0,0]): print(stateNow, counter) counter = 0 if not mindlessTaps: if stateNow[0]: clickk(x1,y) if stateNow[1]: clickk(x2,y) if stateNow[2]: clickk(x3,y) if stateNow[3]: clickk(x4,y) state = stateNow print("Timed out!")