Automating google hashcode's submission system with selenium

in #technology6 years ago

Last thursday it was the google hashcode, it's a huge competition around the world organized by google https://hashcode.withgoogle.com/ it's a fun hackathon that lasts 2 hours for the first round.

This year the subject was automated vehicule management :

You can find it in full here : https://drive.google.com/file/d/16brGfFeBPRYYVh1oD8ADgh333aGqEtAH/view

given a set of vehicules, a map (in the form of a grid) of and a set of rides (I want to go from position x;y to position x1;y1), you need to assign the vehicules to pickup the correct rides so that when they finish a ride, there is another one nearby. In order to finish everything as fast as possible. There are other parameters but we won't discuss them now are they are irrelevant.

So in the end you get several input files containing various scenarios, with a map bigger and bigger and more and more rides and vehicles.

Your job is to run your algorithm, allocate the correct rides and generate an output file which looks like this :

0 1 2
1 3

here we allocate the rides 1 and 2 to the vehicle 0 and the ride 3 to the vehicle 1.

Then submit the files to the juding system which will give us points depending on how well it went.

In this competition it's important to draw "first blood", aka having a result and fast and then build on it. So our first solution was to allocate all of the rides to one vehicle, which did poorly obviously, then the second dumb solution was to randomly allocate rides to the vehicules.

In terms of code it looks like this : (python)

vehicles_nb = data['vehicles'].__len__() # total number of vehicles

for ride in data['rides']: # iterate over the rides
    id = randint(0, vehicles_nb-1) # get a random vehicle 
    data['vehicles'][id]['rides'].append(ride['id']) # add the ride id to the vehicle rides

Pretty easy right ?

Note that if you submit it to the judging system, only the best score is kept, so after running it a few times we realized that our score was increasing (as we randomly do better than our best score). But submitting takes a lot of time because there is a lot of steps :

  • Click on the Authenticate button
  • Write username
  • Click next
  • Write password
  • Click login
  • click on "submit new submission"
  • click on upload
  • select the output file
  • click on send
  • repeat for the 5 files
  • click on submit to get the notation

So it takes a good 40-50 seconds to submit the output files once.

Then came a wild idea : What if I automated that whole process and along our efforts to come up with "real" algorithms, randomly try to get better results by chance ?

So I started automating it using https://www.seleniumhq.org/ I wrote a guide on it a few months ago (which has its formating broken but the information is here : https://steemit.com/programming/@howo/web-browser-automation-in-python-with-selenium)

I'll show you a gif of the result beforehand so you get some idea of what's happening in the code :

Peek 2018-03-01 21-12.gif

First we create the driver and open the hashcode page :

driver = webdriver.Chrome('./chromedriver')  
driver.get('https://hashcodejudge.withgoogle.com/#/rounds/4868850726207488/submissions/')

We are asked to login and as soon as we click on authenticate, a popup opens and they ask us to do so. Hence :

 driver.find_element_by_class_name("md-primary").click() # click on authenticate
 time.sleep(0.5) # wait for the window to appear
 driver.switch_to.window(driver.window_handles[1]) # switch the focus to the new windows 
 driver.find_element_by_id("identifierId").send_keys("username") # send the username
 driver.find_element_by_id("identifierNext").click() # click on the "next" button
 time.sleep(1) # wait for the window to proceed
 driver.find_element_by_name("password").send_keys("password") # send the password
 time.sleep(0.5) 
 driver.find_element_by_id("passwordNext").click() # confirms (this closes the popup)
 time.sleep(1)
 driver.switch_to.window(driver.window_handles[0]) # Switch back to the main page 

We have a lot of sleeps because if we go too fast the window won't fnd the next id or name. And this was coded during a hackathon so no time to write a clean "wait until you find this id/name"

We switch the focus of the driver on the new window because otherwise he won't be able to interact with the content of the popup.

Ok so now we are authenticated, we can submit the files

driver.find_element_by_class_name("md-primary").click() # Click on submit
time.sleep(0.5)

This creates a popup with 5 buttons,

the issue with them is that we don't have an unique id :

<button class="md-raised md-primary md-button md-ink-ripple" type="button" ng-transclude="" ng-click="ctrl.onUploadClick($event)" ng-disabled="!ctrl.ready || ctrl.fileName" aria-label="Upload">Upload file<div class="md-ripple-container" style=""></div></button>

Luckily all the buttons have this custom css :

aria-label="Upload"

So we can use selenium to get a list of all the "upload" buttons :

driver.find_elements_by_css_selector('[aria-label="Upload"]')

With that list and we can iterate over the 5 buttons :

 for id, elem in enumerate(driver.find_elements_by_css_selector('[aria-label="Upload"]')) : # We iterate over the 5 upload buttons
 ​  elem.click()
 ​  time.sleep(0.5)

Then there is a file selection dialog, which is outside of the driver as it's an os window. We can't control it via selenium. We'll use pyautogui to the rescue ! (I also wrote an article about it : https://steemit.com/python/@howo/how-to-control-the-mouse-and-keyboard-with-python-for-automation)

The upload windows pops in focus so we just have to hit a few good keys to select the right files.

    \# I know the ifs are ugly but this is hackathon code, no time for pretty
    if (id == 0): # First time the dialog opens, we select the "output" folder
        pyautogui.press('down')
        pyautogui.press('enter')
        time.sleep(0.5)
    if (id == 2): # select the file b
        pyautogui.press('down')
        time.sleep(0.5)
    elif (id == 3):  # select the file c
        pyautogui.press('down')
        pyautogui.press('down')
        time.sleep(0.2)
    elif (id == 4):  # select the file d
        pyautogui.press('down')
        pyautogui.press('down')
        pyautogui.press('down')
    elif (id == 5):  # select the file e
        pyautogui.press('down')
        pyautogui.press('down')
        pyautogui.press('down')
        pyautogui.press('down')

 pyautogui.press('enter')
 

 \# click on the submit button
 driver.find_element_by_css_selector('[ng-click="submissionsCtrl.createSubmission()"]').click() 

And bam ! it worked.

I let it run for the duration of the hackathon that was left flooding our team with random results and infuriating my teammates who could not see the results of their own submissions.

At some point the randomness converged to a "maximum" and we did not manage to get past 12M points with that method (the winners of the hackathon got 45M points).

You can find the complete source file for this on my github : https://github.com/drov0/hashcode-auto-submit

Sort:  

Thank you for this work! u deserve more Upvotes! I know @inertia will like to know about your work since you created Steempress also @theoccultcorner and other people who are into Data and Creation and Development on steem

ahh who else @neoxian should know you are behind Steem.press the Steem Wordpress plugin, and I think we need ore people focused on advertising Steempress

I mean there are 7-0 MILLION wordpress Blogs AlREADY out there LETS get THEM on steem and GARUNTEE us a 70 Million Blog Content BASE and Bring the Reward Pool into paying for the QUALITY Blogs I know exist in that pool of Content from Wordpress!

Wow even if we got just 10-% of wordpress to join stem and got 7 million Blogs on Steem that would increase our Value so much I think that could push Steem price to $20 easily because of MetaCalfs Law bout the Value of a tele comunication network being proportional to the amount of users Square! So actually if we go from 700K users to 7 million that is 10X so I see us going from $2 Steem price we are at now to $20 Easily happening! Bu actually metacalfs law would say that a 10X in users would exponentially grow our steem value to hah I don't know $200? $2000? It would be SPECTACULAR that is for sure! And if Ethereum can be $1000 I believe Steem can easily get up there, oh yeah, oh hell yeah... Especially with $19,000 Bitcoin, $40,000 Bitcoin o yeah $100 $200 $50 and $1000 even $2000 Steem price is VERy easy to Imagine, just imagine the BIG media players nbaord paying their own people with steem to produce content and hving legt autoted systems in pace that scoop up a users steem.SBD autoamtcialy c onvert it to pendable Fit mney on their Bank accounts or debit crds, so that sort of system makes iut EASY to imagine people getting paid off teem inmss, like youtube, with just a fiat gateway to cash in their pay, or even a PAYCJHECK system, I can even setup a system tha takes someones SBD rewards or STEEM, and lets them send it to me and I vas it outa nd snd them a fucking PAYcheck! THAT would eb Simple so yteah we have many ways to pay peope the question is mostly technical we do need engineers to solve these problems and business people WILl come , this is the BEST environet for making money Steemis a Dre come true when it comes to mking money creatingand developing :D

Thanks for your support ! Yeah we definitely want to emboard all these bloggers to make steem the greatest blogging platform :D

It's a knowledgeable post. thanks for sharing.keep it up.people will be benefits on this post thanks for sharing.go ahead.

To listen to the audio version of this article click on the play image.

Brought to you by @tts. If you find it useful please consider upvote this reply.

You have to be pretty smart and tech savvy to participate. Very good. Go Steemer! Great work!
Joy

Coin Marketplace

STEEM 0.31
TRX 0.11
JST 0.034
BTC 64140.77
ETH 3133.36
USDT 1.00
SBD 4.15