15
\$\begingroup\$

Write a program that outputs the contents of the first HTML <code>...</code> block of the answer to this question that is just above yours when the answers are sorted by votes. Output Top! if you are the top answer.

Ignore answers that have negative votes or no <code>...</code> tags. The source of your program must appear in the first <code>...</code> block in your post. These blocks are created automatically when you use backticks or

indent things with 4 spaces.

This is code-golf, the answer with the fewest characters wins.

Additional Rules (Updated)

  • Answer in any programming language you want but if you answer multiple times use different languages.
  • You may not hard code your output. Your program's ability to run correctly should not depend on it's vote count or on what the answer above is. If the vote distribution changed drastically your program should still correctly output the code of the answer above it.
  • You may hard code your program to search for itself on this page (so as to find the next highest) via some unique property of your answer, such as your username (if you only have one answer) or the answer's direct link.
  • If two answers have equal votes you should still use the one just above yours (which I believe will be the newest one).
  • You may have multiple <code>...</code> blocks in your answer but the first one must contain your program's source.
\$\endgroup\$
  • 1
    \$\begingroup\$ Do I have to account for multiple pages? \$\endgroup\$ – Οurous Jul 18 '14 at 3:02
  • 1
    \$\begingroup\$ Yes you should account for multiple pages \$\endgroup\$ – Calvin's Hobbies Jul 18 '14 at 3:04
  • 4
    \$\begingroup\$ Note that inline code spans are just <code></code>, but proper code blocks are <pre><code>stuff</code></pre>. \$\endgroup\$ – Doorknob Jul 18 '14 at 4:03
  • 3
    \$\begingroup\$ @Calvin'sHobbies I think the order of tied answers (by votes) is random. At least on SO, I don't know about here. \$\endgroup\$ – Martin Ender Jul 18 '14 at 11:51
  • 4
    \$\begingroup\$ I would argue that caring about multiple pages is unnecessary - if you aren't on the first page, you aren't WINNING anyway :) \$\endgroup\$ – lrn Jul 18 '14 at 16:21

11 Answers 11

5
\$\begingroup\$

Javascript + jQuery (92 86 64 char)

To test, open Dev Tools on this page (usually F12), and run my code!

This Javscript needs to be run using the console from this page (and only this page).

alert($("code",$("#answer-34767").prev().prev()).html()||"Top!")

So short, it doesn't even need a scrollbar!

Basically, it finds my answer by ID, and then gets two nodes ahead (skipping the anchor link). If that does not exist, I must be on top. Then it digs down to the first code element and gets it's .innerHTML.

The nice thing is that SE uses jQuery by default, so I get that advantage without even trying.

\$\endgroup\$
  • 2
    \$\begingroup\$ I personally don't like your answer as it's a bit like cheating... Anyway, it could be as short as alert($("code",$("#answer-34767").prev().prev()).html()||"Top!"). \$\endgroup\$ – core1024 Jul 19 '14 at 8:18
  • \$\begingroup\$ @core1024: Thanks for the improvment! I hadn't thought of doing it one-statement. I agree that I do have a huge advantage. Maybe I have to count Firefox's code for >78MB? The rules say "Answer in any programming language you want". \$\endgroup\$ – Robbie Wxyz Jul 19 '14 at 15:19
  • \$\begingroup\$ You don't need to count the Firefox's code :) Your advantage is in the current environment and not in the interpreter. It's as if everybody had the source of the page already loaded in an "object"/"variable". +1 for the exploit ;) \$\endgroup\$ – core1024 Jul 19 '14 at 18:45
  • 4
    \$\begingroup\$ This is gonna alert "top" if it's top of the second page, is this the correct behavior? \$\endgroup\$ – William Barbosa Jul 21 '14 at 1:29
  • \$\begingroup\$ @WilliamBarbosa: I'm with "lrn" on that one. (see his comment on OP's question). \$\endgroup\$ – Robbie Wxyz Jul 21 '14 at 14:50
6
\$\begingroup\$

PHP 666 611 593 588 580 Characters

Edit: Used even smaller url than previously from tinyurl.

Edit: Following comment on other answer I used int rather than boolean. Also needed to correct an error that became apparent but fixed now.

Here is my code

<?
$a=34727;$b=new DOMDocument();$b->loadHTMLFile("http://turl.no/t2u");$c=$b->saveHTML();$d=$e=1;$f='data-answerid="';$g=strpos($c,$f);$h=substr($c,0,$g);$c=substr($c,($g+15));while($d==1){$g=strpos($c,'"');$i=substr($c,0,$g);if($i==$a){$j=$h;$k=$e;}$g=strpos($c,'vote-count-post ">');$c=substr($c,($g+18));$g=strpos($c,'<');$l=substr($c,0,$g);$g=strpos($c,'data-answerid="');if($g){++$e;++$e;$h=substr($c,0,$g);$c=substr($c,($g+15));}else{$d=2;}}if($k==1){echo 'Top!';}else{$g=strpos($j,'><code>');$m=strpos($j,'</code></pre>');$n=$m-$g-7;$o=substr($j,($g+7),$n);echo nl2br($o);}

I am sure this can be improved using DOMXPath and nodes. However am quite pleased with it. I could not decide what to do in the case of mine is the only answer but with -ve points so ignored. However another answer was posted so not a problem any more.

I also used tinyurl to shorten the url, saving lots of characters.

I hope you like it,

Paul.

PS This will not run in codepad so can't show a fiddle.

Edit: saved 5 more with the php tags being altered

You can see it working here on a domain I do not currently use (so am not just trying a sneaky link). This is not a permanent link though but is currently available.

\$\endgroup\$
  • \$\begingroup\$ You could shorten it even more by using an even shorter urlshortener=) for example ➡.ws/.v \$\endgroup\$ – flawr Jul 18 '14 at 16:24
  • \$\begingroup\$ I tried it with the tinyarrows.com link but the delay in connecting times out the server. They are genuinely tiny urls though. \$\endgroup\$ – Paul Drewett Jul 18 '14 at 20:49
  • 1
    \$\begingroup\$ On this site, it is acceptable to use a shortened opening tag (I believe it's <? instead of <?php) and leave off the closing tag. That should leave you a few more chars. \$\endgroup\$ – Justin Jul 18 '14 at 23:40
  • 1
    \$\begingroup\$ turl.no makes some pretty short links, and because it's a Norwegian link shortener, few people have noticed it internationally. Here's a link for you: turl.no/t2u points to the same page as your tinyurl.com link, and saves 8 characters. \$\endgroup\$ – bilde2910 Jul 20 '14 at 22:39
  • \$\begingroup\$ @bilde2910 Thankyou, that worked and it is indeed another very tiny url. Much appreciated and Turl.ca is interesting. He loves his .ca domains doesn't he :-) \$\endgroup\$ – Paul Drewett Jul 20 '14 at 23:24
4
\$\begingroup\$

Dart 412 403

import"dart:io";import"dart:convert";main(){new HttpClient().get("pi.vu",0,"BYga").then((v)=>v.close()).then((r)=>r.transform(UTF8.decoder).join()).then((s,[i,c="Top!"])=>new RegExp(r'<div id="answer-(\d+)[^]*?vote-count-post ">(\d+)[^]*?<table class="fw"').allMatches(s).forEach((m)=>m[1]=="34735"?print(c):m[2][0]!='-'&&(i=(s=m[0]).indexOf("<code>"))>0?c=s.substring(i+6,s.indexOf("</code>",i)):0));}

Ungolfed (well, with newlines and leading whitespace)

import"dart:io";
import"dart:convert";
main(){
  new HttpClient().get("pi.vu",0,"BYga")
  .then((v)=>v.close())
  .then((r)=>r.transform(UTF8.decoder).join())
  .then((s,[i,c="Top!"])=>
      new RegExp(r'<div id="answer-(\d+)[^]*?vote-count-post ">(\d+)[^]*?<table class="fw"')
      .allMatches(s)
      .forEach((m)=>
          m[1]=="34735"?print(c)
                       :m[2][0]!='-'&&(i=(s=m[0]).indexOf("<code>"))>0
                           ?c=s.substring(i+6,s.indexOf("</code>",i)):0
  ));
}
\$\endgroup\$
4
\$\begingroup\$

Delphi (688 873 859 848 840)

I will still try to shave off some characters but it will do the job :)

Edit: instead of getting it shorter I made it longer :P
I forgot to add in the ignoring of answers when it has a negative votecount or no code blocks.

I'm just updating the un-golfed version while editing.
Thanks to @manatwork for the suggested edits that took off 8 characters.

Golfed version:

uses IdHTTP,Classes,MSHTML;const u='http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours/34718#34718';var g:TIdHTTP;m:TMemoryStream;l:TStringList;p,t,r,o:OleVariant;s,i,j:int32;c:boolean;begin L:=TStringList.Create;g:=TIdHTTP.Create(nil);m:=TMemoryStream.Create;g.Get(u,m);m.Position:=0;L.LoadFromStream(m);p:=coHTMLDocument.Create as IHTMLDocument2;p.write(l.Text);for I:=0to p.body.all.length-1do begin c:=0>1;t:=p.body.all.item(i);if(t.classname='answer')and(t.id='answer-34718')then if s=0 then writeln('Top!') else for j:=0to o.all.length-1do begin t:=o.all.item(j);if t.tagname='CODE'then writeln(t.innertext);end else if t.classname='answer'then begin for j:=0to t.all.length-1do begin r:=t.all.item(j);if r.tagname='CODE'then c:=1>0 else if c and(r.class='vote-count-post')and(r.innertext[1]<>'-')then begin o:=t;s:=1;end;end;end;end;end.

Ungolfed version:

uses
  IdHTTP,Classes,MSHTML;
const
  u='http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours/34718';
  a='answer';b='CODE';
var
  g:TIdHTTP;
  m:TMemoryStream;
  l:TStrings;
  p,t,r,o,z:OleVariant;
  s,i,j:int32;
  c:byte;
begin
  L:=TStringList.Create;
  g:=TIdHTTP.Create(nil);
  m:=TMemoryStream.Create;
  g.Get(u,m);
  m.Position:=0;
  L.LoadFromStream(m);
  p:=coHTMLDocument.Create as IHTMLDocument2;
  p.write(l.Text);
  z:=p.body.all;
  for I:=0to z.length-1do
  begin
    c:=0;
    t:=z.item(i);
    if(t.classname=a)and(t.id='answer-34718')then
      if s=0 then
        write('Top!')
      else
        for j:=0to o.all.length-1do
        begin
          t:=o.all.item(j);
          if t.tagname=b then
            write(t.innertext)
        end
    else if t.classname=a then
      for j:=0to t.all.length-1do
      begin
        r:=t.all.item(j);
        if r.tagname=b then
          c:=1
        else if(c=1)and(r.class='vote-count-post')and(r.innertext[1]<>'-')then
        begin
          o:=t;
          s:=1;
        end;
      end;
  end;
end.
\$\endgroup\$
  • \$\begingroup\$ http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours/34718#34718 can be changed to http://codegolf.stackexchange.com/q/34718, which would save quite a bit of characters. \$\endgroup\$ – Doorknob Jul 18 '14 at 10:46
  • \$\begingroup\$ Thanks, sadly I also had to add some since I forgot the part where you have to ignore answers with a negative votecount or no code blocks :/.. doesnt work :( I get a 301 permanently moved \$\endgroup\$ – Teun Pronk Jul 18 '14 at 10:51
  • \$\begingroup\$ As suggested before, you can declare l as TStrings instead. (But keep the instantiation with TStringList.) \$\endgroup\$ – manatwork Jul 18 '14 at 11:26
  • \$\begingroup\$ I would try to make c byte instead of boolean. \$\endgroup\$ – manatwork Jul 18 '14 at 11:29
3
\$\begingroup\$

Python - 280

import os, sys, cgi
os.system('wget http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours.html -q -O a')
b=[ x[:-2] for x in open('a').read().split('code>') if x[-1]=='/']
for i, m in enumerate(b):
    if m == cgi.escape(open(sys.argv[0]).read()):
        print b[i-1]

This is my first codegolf, so I hope this is golf-y enough!

Edit: Thanks for the tips! It's looking a bit golfier now.

\$\endgroup\$
  • \$\begingroup\$ Doesn't look bad for a first try! Though you could use an URL shortener for the link and get rid of a few spaces in there (for i,m, m==open,etc). \$\endgroup\$ – Christoph Böhmwalder Jul 18 '14 at 21:38
  • \$\begingroup\$ @HackerCow I think URL shorteners are generally frowned on, but http://codegolf.stackexchange.com/q/34705/14509 would definitely work. \$\endgroup\$ – undergroundmonorail Jul 19 '14 at 1:19
  • \$\begingroup\$ @KidElephant I removed a bunch of whitespace from your code. I didn't test it or anything but unless I screwed up it should be (logically) the same program. Note that I removed the shebang, those aren't required here. ix.io/dsz Taking out whitespace can save quite a few bytes :) \$\endgroup\$ – undergroundmonorail Jul 19 '14 at 1:23
  • \$\begingroup\$ Also, for code golf challenges you are supposed to include a byte count. I'd edit one in for you here but your answer is probably going to change if you use any suggestions so I won't bother. You can find the byte count by running wc -c $filename. If your editor appends a trailing newline to files (it probably does) you can subtract one from that to get your final score. \$\endgroup\$ – undergroundmonorail Jul 19 '14 at 1:26
2
\$\begingroup\$

Mathematica - 159

First time doing parsing in Mathematica

FirstCase[
 Cases[Import["http://bit.do/JGta1","XMLObject"],
 {__,a_,_,_,_,XMLElement[_, {_, "id""answer-34780",__},_],__}a,∞], 
 XMLElement["code",_,{c_}]c,"Top!",∞]
\$\endgroup\$
2
\$\begingroup\$

Ruby 283+17 = 300

This succeeds regardless how few votes this answer gets and no matter if there's a second (or fifteenth) page of answers or not. It uses the data API.

d=34849
JSON.parse(Net::HTTP.get(URI("http://api.stackexchange.com/2.2/questions/34705/answers?site=codegolf&filter=8G3Ng9T*")))['items'].map{|a|abort$1.gsub(/&.+?;/){|g|g[?a]??&:g[?g]??>:?<}if !d&&a['score']>=0&&/<code>(.*?)<\/code>/m=~a['body']
d=p if a['answer_id']==d}
$><<'Top!'

must be run with ruby -rnet/http -rjson (hence the +17)

ungolfed:

d = 34849 # this answer id
i = JSON.parse(Net::HTTP.get(URI("http://api.stackexchange.com/2.2/questions/34705/answers?site=codegolf&filter=8G3Ng9T*")))['items'] # stackexchange api answers for this question
i.map{ |a|
  # if we've already hit this answer, the score's above 0 and there's code...
  if !d && a['score']>=0 && /<code>(.*?)<\/code>/m=~a['body'] then
    # abort with html-unescaped code
    abort $1.gsub(/&.+?;/){ |g|
      # this turns &amp;, &gt; and &lt; into &, > and <, respectively
      g[?a] ? ?& : g[?g] ? ?> : ?<       
    }
  end
  # if we are at our answer, set d = nil
  if a['answer_id']==d then 
    d = p 
  end
}
# no abort. puts 'Top!'
$><<'Top!'

Changelog

300 removed parens in symbol regex

302 initial commit

\$\endgroup\$
  • \$\begingroup\$ You can save some bytes by making your filter unsafe \$\endgroup\$ – pppery Jun 16 '16 at 15:14
  • \$\begingroup\$ @ppperry please explain? \$\endgroup\$ – Not that Charles Jun 16 '16 at 15:16
  • \$\begingroup\$ Using unsafe filters means you want have to manually HTML unescape. See the filter docs \$\endgroup\$ – pppery Jun 16 '16 at 15:19
1
\$\begingroup\$

PHP 135

<?
preg_match_all('@(\d+?)"></a.*de>(.*)</c@Us',join('
',file('http://pi.vu/BYga')),$m);echo$m[2][array_search(34786,$m[1])-1]?:'Top!';

Edit: lrn's URL shortener produces the shortest URL :)

The RegEx matches the anchor before each answer (together with the answer ID) and the contents inside the first <code> tag. The U flag triggers the Ungreedy mode and the s flag make . matches new lines (very handful). I'm not worried if this matches something else as the answers are escaped, so nobody can insert the < literal in the page's source.

After I get all the answers in $m[2] and their IDs in $m[1], I just use echo to print the answer above mine, as it's in $m[2][array_search(34786,$m[1])-1], or "Top!", if my answer eventually gets first :)

I like the fact that in PHP the ternary operator can be used as a short-circuit operator ?:

\$\endgroup\$
  • \$\begingroup\$ That is amazing. I just tested it but it is showing the code from the one below. I am sure this will be a quick fix but thought I would mention it. Amazing job though, 135 in PHP, I still cannot quite believe it... \$\endgroup\$ – Paul Drewett Jul 20 '14 at 23:36
  • 1
    \$\begingroup\$ @PaulDrewett Please look at the order when you open this page in private browsing. It's different from the order when you're logged in. \$\endgroup\$ – core1024 Jul 21 '14 at 5:49
  • \$\begingroup\$ Oh, that is suprising. I wonder why? Sorry to point out an error in error. My bad. I did upvote you though as a useful answer. I still think it is amazing... \$\endgroup\$ – Paul Drewett Jul 21 '14 at 9:40
1
\$\begingroup\$

Delphi, 461 bytes, 553 bytes

Now handles multiple pages too!

Golfed:

uses IdHTTP,RegularExpressions;var T,S,O:String;K,V,C:Int32;begin repeat Inc(C);Str(C,S);S:=TIdHTTP.Create.Get('http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours?page='+S);T:=T+S;until Pos('<span class="page-numbers next',S)=0;O:='Top!';for T in TRegEx.Split(T,'<a name="') do begin S:=T;Val(Copy(S,1,Pos('"',S)-1),K,C);if C=1then Continue;Delete(S,1,Pos('post ">',S)+6);Val(Copy(S,1,Pos('<',S)-1),V,C);C:=Pos('<code>',S);if(C=0)or(V<0)then Continue;if K=34844then Break;O:=Copy(S,C+6,Pos('</code>',S)-C-6);end;Write(O)end.

(slightly) Ungolfed:

uses
  IdHTTP,RegularExpressions;
var
  T,S,O:String;
  K,V,C:Int32;
begin
  // download all pages in thread and concat them
  repeat
    Inc(C);
    Str(C,S);
    S:=TIdHTTP.Create.Get('http://codegolf.stackexchange.com/questions/34705/output-the-answer-above-yours?page='+S);
    T:=T+S;
  until Pos('<span class="page-numbers next',S)=0;
  O:='Top!'; // initialize code string to 'Top!'
  for T in TRegEx.Split(T,'<a name="') do begin
    S:=T;
    Val(Copy(S,1,Pos('"',S)-1),K,C); // try to extract user id
    if C=1then Continue; // if failed, continue loop
    Delete(S,1,Pos('post ">',S)+6); // prepare S for next parse
    Val(Copy(S,1,Pos('<',S)-1),V,C); // try to extract vote count
    C:=Pos('<code>',S); // check if <code> tag exists
    if(C=0)or(V<0)then Continue; // make sure vote count is positive and <code> tag exists
    if K=34844then Break; // if its our answer, break the loop
    O:=Copy(S,C+6,Pos('</code>',S)-C-6); // get string in <code> tag
  end;
  Write(O); // write <code> string
end.

How to run:

app.exe > output.txt
\$\endgroup\$
  • \$\begingroup\$ nice, could've done that too instead of using the html units.. shame I didn't think of that :P \$\endgroup\$ – Teun Pronk Jul 21 '14 at 7:18
  • \$\begingroup\$ Thanks. Also, one of the (if not only) codes that handles multiple pages too. \$\endgroup\$ – Marko Paunovic Jul 21 '14 at 14:42
1
\$\begingroup\$

PHP - 412 - 422 - 416 - 252 - 248:

Still a work in progress, I haven't done anything regarding multiple pages (nor has anyone else?)

I got the 200 character drop by cutting out a lot of extra dom, why search for objects when I can just find their position?

This is also my first code golf! I'm happy to have done it in the 200s and using dom methods. Thanks to comments, I just shaved off 4 more characters.

I wanted to do something like jquery/jscript in regards to traversing the dom, and am still working on slimming this down. Maybe I could get away with searching for "asi" as my user name?

Golf:

<? $d=new DOMDocument;$d->loadHTMLFile("http://bit.do/JGta");$x=new DOMXPath($d);$r=$x->query("//*[@class='answer']");$a=-1;while($f=$r->item(++$a))if(strpos($f->nodeValue,"Asitaka"))echo$x->query(".//pre//code",$r->item($a-1))->item(0)->nodeValue;

Formatted:

    <?php
$d = new DOMDocument();
$d->loadHTMLFile("http://bit.do/JGta");
$x = new DOMXPath($d);
$r = $x->query("//*[@class='answer']");
$a = -1;
while($f = $r->item(++$a))
        if ( stripos($f->nodeValue, "Asitaka")!= 0)
            echo $x->query(".//pre//code",$r->item($a-1))->item(0)->nodeValue;
?>

Cheers

\$\endgroup\$
  • \$\begingroup\$ Parentheses in new DOMDocument(), and the closing ?> can be omitted in PHP. \$\endgroup\$ – jimmy23013 Jul 19 '14 at 8:24
  • \$\begingroup\$ Thanks, lost 4 more characters. At the moment, I can't imagine how to make it shorter unless I use different classes, DOM accessors are expensive. \$\endgroup\$ – Asitaka Jul 19 '14 at 11:53
  • \$\begingroup\$ Save characters by changing your user name! \$\endgroup\$ – DavidG Jul 20 '14 at 1:59
  • \$\begingroup\$ I think this is cool. I am just trying to learn the query part to DOMXPath but I must admit I am finding it tough. I did try it for this but couldn't quite get it. I tested yours but it seems to be reporting the one two above it, not the one directly above. I am sure it is a quick fix but just thought I would mention it. \$\endgroup\$ – Paul Drewett Jul 20 '14 at 23:43
  • \$\begingroup\$ Following this info "Please look at the order when you open this page in private browsing. It's different from the order when you're logged in - core1024" from different answer comment I have to assume the same is happening here too. Sorry for that. \$\endgroup\$ – Paul Drewett Jul 21 '14 at 9:42
1
\$\begingroup\$

Python 3, 197 191 bytes

import urllib.request as u,gzip,json;p='Top!'
for r in json.loads(gzip.decompress(u.urlopen("http://bit.ly/2hN8TKV").read()).decode())["items"]:
 if r['answer_id']==82837:exit(p)
 p=r['body']

The rules don't say that I can't use the API and that I can't use a url shortener.

https://tinyurl.com/hdemk76 expands to https://api.stackexchange.com/2.2/questions/34705/answers?order=desc&sort=votes&site=codegolf&filter=withbody&pagesize=100 This only works if it is in the top 100 answers sorted by votes.

\$\endgroup\$
  • \$\begingroup\$ -6 if you replace https://tinyurl.com/hdemk76 with http://bit.ly/2hN8TKV \$\endgroup\$ – Taylor Scott Dec 28 '16 at 12:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.