12
\$\begingroup\$

Background: I ran into numerous issues when presenting and running this King of the Hill challenge back in October: Write a bot to play Grid Game - I'm cooking up a new, similar challenge, but taking things a bit more slowly and preparing more thoroughly to try and pre-emptively solve the issues we hit then.


So this was the intended path for entries to the Grid Game competion:

  • Someone works on a bot, likes thier solution.
  • It's added to a Github Gist.
  • They past the gist and the code to an SO answer.
  • My code grabs the gist via the Github gist api.
  • The tournament is run with the latest version of the gists.

I also added a note that entrants could choose whether or not to consent to their entry becoming a part of the code base.

Here are some issues we found with that methodology:

  • The Gist API rate-limits get calls, so I had to cache the code to avoid being locked out.
  • Entries were in multiple places, causing confusion on whether the latest version was used:
    • SE answer
    • Gist
    • Cached in local memory
    • Cached in the code base

Long story short, this was a real headache when running the tournament to get results. A lot of in-line changes had to be made to try and correct it.

Proposed solution

What I'd like to do about this, is to make the entry a Pull Request in Github, making the repository a single, central source.

It would look like this:

  • The entry is a JS class, in a certain folder in the application.
  • There's a validator script which ensures it follows the rules of the challenge and doesn't break the applicaiton.
  • The result is submitted as a pull request.
  • If it passes the validator, it's accepted in to the repo and run as part of the tournament.
  • Updates to an entry would be made in the same way, modifiying the existing file.

Pros:

  • A 'single source of truth' for entries.
  • Everyone can train their entries on all current entries.
  • Less in-line problem solving.

Cons:

  • To enter the contest would make the entrant a contributor to an open-source repo.
  • The SE answer would probably be quite short, just a stub pointing to the pull request or file in the repo?

The questions

Is it acceptable to use Github Pull Requests as entries to a code challenge?

What other issues might this methodology introduce?

Is there a better, regularly used way to import a few mid-length entries (probably between 10 and 100 lines) into an application to run a KotH challenge which I haven't considered?

\$\endgroup\$
  • 1
    \$\begingroup\$ This solution excludes people that don't have a Github account. A better solution is to fetch the answers and render the code block in the browser, and identify the first <pre><code> block. You use that block as the code to be executed. All other blocks are ignored. \$\endgroup\$ – Ismael Miguel Feb 26 at 17:55
  • \$\begingroup\$ @IsmaelMiguel is there any guide available on how to do that? Or would I have to write a HTML scraper for the question? \$\endgroup\$ – AJFaraday Feb 26 at 23:04
  • 1
    \$\begingroup\$ I will post this as an answer \$\endgroup\$ – Ismael Miguel Feb 26 at 23:28
  • \$\begingroup\$ To enter the contest would make the entrant a contributor to an open-source repo. How is this a con? \$\endgroup\$ – S.S. Anne Feb 27 at 14:10
  • \$\begingroup\$ @S.S.Anne Only if some people don't want their code to become part of my project, really. \$\endgroup\$ – AJFaraday Feb 27 at 16:25
  • \$\begingroup\$ I see open-source as a pro, not a con. \$\endgroup\$ – S.S. Anne Feb 27 at 17:12
10
\$\begingroup\$

Instead of using Github, just fetch the contents of the answer.

To parse it, read this question: https://stackoverflow.com/questions/10585029/parse-an-html-string-with-js (remember the question id: 10585029)

Using the StackExchange API you can get the answers in the question, with a few calls to the API entry point /questions/{ids}/answers.

First, you will need a filter. Just add the "answer" > "body" option: "answer" > "body"

If you want, you can use this slightly more optimized filter: !FcbCBt3onoXUY8kGhT_Xh.df25

I strongly recommend using 100 for the page size.

You basically just use $.getJSON (or similar) on the following URL (as an example):
/2.2/questions/10585029/answers?pagesize=100&order=desc&sort=activity&site=stackoverflow&filter=!FcbCBt3onoXUY8kGhT_Xh.df25


If everything goes right, inside "items" you will have the answers, which will have the "body" key, which contains purely rendered HTML.

You can then do something similar to this, using the mockup of the answer I've liked:

var json = '{"owner":{"profile_image":"https://i.stack.imgur.com/E0rsP.jpg?s=128&g=1","display_name":"Cilan","link":"https://stackoverflow.com/users/2876565/cilan"},"is_accepted":false,"score":213,"last_activity_date":1582619200,"last_edit_date":1582619200,"creation_date":1392780526,"answer_id":21870431,"question_id":10585029,"link":"https://stackoverflow.com/questions/10585029/parse-an-html-string-with-js/21870431#21870431","body":"<p>It\'s quite simple:</p>\\n\\n<pre><code>var parser = new DOMParser();\\nvar htmlDoc = parser.parseFromString(txt, \'text/html\');\\n// do whatever you want with htmlDoc.getElementsByTagName(\'a\');\\n</code></pre>\\n\\n<p><a href=\\"https://developer.mozilla.org/en-US/docs/Web/API/DOMParser#Browser_compatibility\\" rel=\\"nofollow noreferrer\\">According to MDN</a>, to do this in chrome you need to parse as XML like so:</p>\\n\\n<pre><code>var parser = new DOMParser();\\nvar htmlDoc = parser.parseFromString(txt, \'text/xml\');\\n// do whatever you want with htmlDoc.getElementsByTagName(\'a\');\\n</code></pre>\\n\\n<p><s>It is currently unsupported by webkit and you\'d have to follow Florian\'s answer, and it is unknown to work in most cases on mobile browsers.</s></p>\\n\\n<p>Edit: Now widely supported</p>\\n"}';

var json_obj = JSON.parse(json);

var parser = new DOMParser();
var doc = parser.parseFromString(json_obj.body, 'text/html');

var pre = doc.getElementsByTagName('pre')[0];

if(pre)
{
  document.body.appendChild(pre);

  var text = pre.innerText || pre.textContent;
  var p = document.createElement(p);
  
  p.innerText = p.textContent = 'Text content:\n\n' + text;
  document.body.appendChild(p);
}


If you aren't afraid of jQuery, your job is a lot simplified (REAL EXAMPLE):

var URL = 'https://api.stackexchange.com/2.2/questions/10585029/answers?pagesize=100&order=desc&sort=activity&site=stackoverflow&filter=!FcbCBt3onoXUY8kGhT_Xh.df25';

$.getJSON(URL, function(data){
  // example to fetch the first answer and the first <pre>
  var $pre = $(data.items[0].body).filter('pre').first();

  if(!$pre.length)
  {
    return;
  }

  $pre.appendTo(document.body);
  
  // .replace(/\r?\n/g, '<br>') only needed for this demonstration
  $('<p></p>').html(('Text content:\n\n' + $pre.text()).replace(/\r?\n/g, '<br>')).appendTo(document.body);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


What I have as "text content" is what you can use to just do a simple eval() or a new Function(<string code>) or something else.

I strongly recommend that you read the whole documentation about the API parameters and their accepted values.
With this, you can do quite a lot!
Pay attention to the quota limits and the "has_more" key.

Any questions, just ask below.

\$\endgroup\$
  • \$\begingroup\$ Thanks! This was suggested for my earlier challenge, but I couldn’t find guidelines for it, and didn’t want to change the answer mechanism in-line. I’ll give this a go. \$\endgroup\$ – AJFaraday Feb 27 at 6:59
  • \$\begingroup\$ This should be really easy to implement. Remember to change the site before using the endpoints. All my examples were written using the question that explains how to use the DomParser() on stackoverflow. I've added a jQuery example, using the real API entrypoint and shows the real content from the API, because it was easier. \$\endgroup\$ – Ismael Miguel Feb 27 at 9:43
  • \$\begingroup\$ I'm currently trying to write without a framework like jquery, ember, etc. (to improve my JS knowledge), but I won't rule out using it by the end of the project :p \$\endgroup\$ – AJFaraday Feb 27 at 11:47
  • 1
    \$\begingroup\$ Well, I wrote an example without jQuery, and a shorter example with jQuery. You can convert the jQuery into non-jQuery, but it will be a lot more complex, as it is a cross-origin request. I believe you need something in the lines of hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors. Using jQuery simplifies all the AJAX and HTML handling, so, why not use it? I know some people don't like it, and prefer other libraries, but well. It works. \$\endgroup\$ – Ismael Miguel Feb 27 at 12:33
7
\$\begingroup\$

No

This creates link-only answers, which are not permitted per general Stack Exchange policy.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .