Wikipedia: Filosofia!

26

Como muitos geeks podem conhecer a maioria das páginas (95% eu acho) na wikipedia acabam por levar a filosofia assim:

Clique no primeiro link não itálico ou entre parênteses, para outro artigo normal: (ou seja, não Arquivo: ou Especial :, mas coisas como Wikipedia: estão OK) e repita esse procedimento até que você atinja a filosofia.

O script deve:

  • Pegue uma primeira página como entrada
  • Imprima o nome de cada artigo que ele recebe
  • E imprima quantos artigos foram necessários para chegar à Filosofia e, se não for o caso.

Você começa com 1000 pontos e perde um para cada personagem no código, pontos de bônus por:

Detectando artigos em loop e parando: +50

Detectando artigos em loop e solicitando se o usuário deve ir para o próximo link no artigo: +170

Permitindo um padrão na verificação anterior como um argumento de linha de comando ou similar: +140

Maior pontuação ganha.

AlphaModder
fonte
7
+1, grande desafio! Essa detecção de parênteses é difícil: P
Maçaneta da porta
1
Tenho a sensação de que isso poderia usar uma definição melhor, mas ainda não tenho certeza de como.
Iszi
3
Perca um ponto para cada caractere digitado. Hmm. Ótimo, entendi, vou copiar e colar os personagens! Sem pontos perdidos!
Justin
5
Por favor, não altere as regras depois que as respostas já tiverem sido postadas; isso é muito rude e geralmente desaprovado na comunidade aqui ...
Maçaneta da porta

Respostas:

8

Ruby, 1000 - 303 299 337 - 50 373 - 170 382 - 170 - 140 379 - 170 - 140 caracteres = 697 701 713 797 928 931

Tenho certeza de que há muitas melhorias a serem feitas.

(Isso requer Nokogiri)

require'open-uri'
require'nokogiri'
x="/wiki/"+gets.chomp
r=[n=i=0]
until x=~/\/Philosophy/
d=Nokogiri.HTML open"http://en.wikipedia.org#{x}"
x=d.css('p a').select{|a|t=a.xpath('preceding::text()').map(&:text)*'';t.count('(')==t.count(')')&&a.attr('href')=~/^.wiki[^:]+$/}[i].attr'href'
i=0
puts r.index(x)?"#{$><<'i=';i=($*[0]||gets).to_i;''}": r.push(x)[-1][6..-1]
n+=1
end
p n

Exemplo de execução:

c:\a\ruby>wikipedia_crawl_philosophy
Latin (note: this is my input)
Classical_antiquity
History
Umbrella_term
Terminology
Word
Linguistics
Science
Knowledge
Fact
Proof_(truth)
Argument
Logic
Reasoning
Consciousness
Quality_(philosophy)
Property_(philosophy)
Modern_philosophy
Philosophy
18

Exemplo um onde eu tive que ir para um link diferente

c:\a\ruby>wikipedia_crawl_philosophy
Snow
Precipitation_(meteorology)
Meteorology
Atmospheric_physics
Synoptic_scale_meteorology
i=2 // I put the 0-indexed number of the link I wanted to go to (so, the third link)

Weather
Atmosphere
Gas
State_of_matter#The_four_fundamental_states
Physics
Natural_science
Sciences
Knowledge
Fact
Proof_(truth)
Argument
Logic
Reasoning
Consciousness
Quality_(philosophy)
Property_(philosophy)
Modern_philosophy
Philosophy
25

Truques que usei:

  • Usei o seletor p apara obter apenas links não itálicos, porque todos os links no artigo real que não estão em itálico estão sempre em elementos de parágrafo na Wikipedia.
Maçaneta da porta
fonte
hmmm ... talvez eu deveria proibir qualquer mas librarys que vêm com a língua ...
AlphaModder
@ user1825860 Na verdade, não é uma biblioteca que acompanha o idioma; é uma jóia. Eu editei minha resposta. Mas, sério, você quer aceitar esse desafio já difícil e nos forçar a não usar bibliotecas de análise de HTML também? : P
Maçaneta da porta
não o estou desaprovando, mas você perde pontos: P
AlphaModder
Você deve reler o primeiro post e editar de acordo: P
AlphaModder
2
@ user1825860 Não altere as regras depois que as respostas já tiverem sido postadas; isso é muito rude ...
Maçaneta da porta
5

"BASH " - (Se não estiver enganado: 1000 - 397 + 170 + 140 = 913 pontos)
"BASH" - (Se não estiver enganado: 1000 - 386 + 170 + 140 = 924 pontos)

"BASH" - (Se não estiver enganado: 1000 - 381 + 170 + 140 = 929 pontos)

O BASH está entre aspas de propósito, pois é uma mistura de ferramentas usadas nos shells * nix, mas agrupadas em um script bash.

Editar 1:

  • Removido http://como curlpadrão para isso.
  • Mudou href=jogo em âncoras para f=como <a>não tem quaisquer outros normais atributos terminando em f. (É uma possibilidade de tags personalizadas. Não vi nenhuma até agora.)
  • Defina a mensagem de saída como não encontrada para em !Philvez de NoPhil. Este é um peculiar pouco como se também poderia dizer, por exemplo !, 0, N, !Pou similar.
  • A peculiaridade dois: -son curlpode ser removida para reduzir em mais três bytes, mas isso produziria uma saída confusa. Não tenho certeza se isso é um problema.
  • Ajuda atualizada nesta página.

Usando peculiaridades, o código terminaria em 379 bytes, 931 pontos.

Eu também poderia implementar @plannapus uso de correspondência (espero) caixa de navegação , adicionando (p|ul).*?<(\1)adicionando seis bytes (subtrair seis pontos).

Edição 2:

Usando ${#c[@]}para imprimir graus de separação em vez de $icontador.

Usando peculiaridades, o código terminaria em 374 bytes, 936 pontos.


Convoco Cthulhu e opto por uma solução regexp + bash / shell / * nix.

Roubado:

Implementado:

  • Detecte o loop e pergunte se o próximo link deve ser utilizado.
  • Opcionalmente, selecione o próximo link na duplicata como opção.

Requisitos:

  • bash v.?
  • grepcom -Psuporte (PCRE).
  • sed
  • curl
  • cut

Uso:

script PATH [OPTIONS]

Print separation of article from ``PATH'' to ``Philosophy'' on Wikipedia.
Degrees of separation, if found, is printed as last line. 
If not found last line yields ``!Phil''.

PATH    
     Absolute path to starting article, e.g: /wiki/Word 
OPTIONS
     y   Automatically select next link if already visited.
     n   (Or other) Quit if next link already visited.
BUGS
     1. On previous visit; "next link" is not checked. Thus if next link
     has already been visited we get eternal loop. Not sure if this
     disqualify +170 points.
     2. Sure there are.

Código embutido. Copiar para arquivo. chmod +x filename. Executar a ./script /wiki/…partir do shell bash.

u=($1);c=($1);while ! [[ "$u" =~ /Philosophy$ ]];do echo "$u";u=($(curl -s "en.wikipedia.org$u"|tr '\n' ' '|grep -Po '<p>.*?</p>'|sed 's/>[^<]*([^)]*)//g'|grep -o '<a [^>]*f="/wiki/[^":]*"'|cut -d\" -f2));for x in "${c[@]}";do if [ "$x" = "$u" ];then [ $2 ] &&s=$2||read -p "${u[0]}?" s;[ $s = y ] &&u[0]=${u[1]}||{ echo "!Phil";exit;} fi;done;c=("${c[@]}" "$u");done;echo ${#c[@]};

Código expandido e explicado:

u=($1); # Array of paths.
c=($1); # Array of visited paths.
# While $u != /Philosophy, ugly trick is to use $u instead of ${u[0]}.
while ! [[ "$u" =~ /Philosophy$ ]];do   
        echo "$u";      # Print current page.
        # curl   : prints retreived page to stdout. "-s" could be skipped.
        # tr     : replace all newline with space. This is a ®sanity thing when it comes to 
        #          twidling with html using regex.
        # grep 1 : match <p> tags. Using -P's ungreedy *?.
        # sed    : remove all occurences of "(" something ")".
        # grep 2 : match links where "href" attribute starts with /wiki/ and is not e.g. File:
        # cut    : match actual href value.
        # Result is added to array ``u''.
        u=($(curl -s "en.wikipedia.org$u" |
                tr '\n' ' ' | 
                grep -Po '<p>.*?</p>' | 
                sed 's/>[^<]*([^)]*)//g' | 
                grep -o '<a [^>]*f="/wiki/[^":]*"' | 
                cut -d\" -f2));

        # For previously visited pages as x.
        for x in "${c[@]}"; do 
                # If x equals to first page ...
                if [ "$x" = "$u" ]; then        
                        # Use option or ask.
                        [ $2 ] && s=$2 || read -p "${u[0]}?" s; 
                        # If response is "y" use next link, else exit with status.
                        [ $s = y ] && u[0]=${u[1]} || { 
                                echo "!Phil"; 
                                exit;
                        } 
                fi;
        done;
        # Append current link to "visited"
        c=("${c[@]}" "$u"); 
done;
# Print number of visited pages.
echo ${#c[@]}
Runium
fonte
Droga, você me venceu por um ponto! : P vou ter que jogar mais a minha solução
Maçaneta da porta
Ye;), mas não tenho certeza se este é um código válido. Usando ferramentas dessa maneira.
Runium 18/01/14
5

JavaScript 726 (444 caracteres [556] + 170)

Agora aprecio que isso possa não ser válido como um bookmarklet, mas gostei de mexer nele de qualquer maneira.

Uso: Navegue até a página da qual você deseja iniciar e execute o seguinte no console:

(function(a){c=0,o="";$(u="html")[u](f=$('<iframe src="'+location+'?">').on("load",function(){$=f.contentWindow.$;p=f.contentDocument.title[s="split"](" - ")[0];c++;p=="Philosophy"?document.write("<pre>"+o+p+"\n"+c):(i=RegExp("^"+p+"$","m").test(o)?a||confirm("Loop, try next?")?2:0:1)&&(f.src=$("p>a").filter(function(){return(t=$(this).parent()[u]()[s](this.outerHTML)[0])[s]("(").length==t[s](")").length})[--i].href);o+=p+"\n"})[0])})(true)

Para JavaScript, a saída é a seguinte:

JavaScript
Interpreter (computing)
Computer science
Science
Knowledge
Fact
Proof (truth)
Argument
Logic
Reason
Consciousness
Quality (philosophy)
Property (philosophy)
Modern philosophy
Philosophy
15

Esta solução pressupõe que você deseja pular para o próximo link em um loop que está sendo detectado, mas se você alterar o truebotão no final false, aparecerá uma caixa de confirmação (bastante irritante ...), sem saber se isso se qualifica para o bônus secundário ou não. Eu vou assumir que não.

Recuado:

(function(l){
    c=0,o='';
    $(u='html')[u](f=$('<iframe src="'+location+'?">').on('load',function(){ // Firefox needs the ? to properly load the frame
        $=f.contentWindow.$; // reference repeated calls as strings to save more bytes
        p=f.contentDocument.title[s='split'](' - ')[0]; // get the title

        c++;
        p=='Philosophy'?
            document.write('<pre>'+o+p+'\n'+c): // pre for nice formatting
            (i=RegExp('^'+p+'$','m').test(o)?
                l||confirm('Loop, try next?')?
                    2: // desired index + 1 so we can use as a boolean
                    0
                :
                1)&&
            (f.src=$('p>a').filter(function(){
                return (t=$(this).parent()[u]()[s](this.outerHTML)[0])[s]('(').length == t[s](')').length // shorter, but still not overly happy with this...
            })[--i].href);
            o+=p+'\n' // update output
    })[0])
})(true) // change this to show confirm box when loop detected

Então, originalmente, eu perdi a parte de ignorar itens em parênteses, acrescentando que o tornava muito mais prolixo, por isso espero reduzir a função de filtro (ou, espero, substituí-la completamente).

Trabalhando no Chrome e no Firefox (testado no Firefox 26)

Dom Hastings
fonte
2
Parece incrível, mas falha no Firefox 20.
Boothby
Argghh! Eu testei apenas o Chrome. Vou dar uma olhada!
Dom Hastings
@boothby Deve estar trabalhando no Firefox agora ... Ainda quero trabalhar nos links que estou escolhendo!
Dom Hastings
5

C # - 813 caracteres

Pontuação: 1000-813 + 50 + 170 + 140 = 547 :(

Nenhuma biblioteca externa. Detecção de loop .

O primeiro argumento é o artigo de origem, o segundo é o artigo de destino.

Versão Golfed:

class Program
{
    static void Main(string[] a)
    {
        Func<XmlDocument,IList<string>> G=delegate(XmlDocument xd){return xd.SelectNodes("//p//a[starts-with(@href,'/wiki/') and not(contains(@href,':'))]").Cast<XmlNode>().Select(n=>n.Attributes["href"].InnerText).ToList();};Action<string> W=delegate(string s){Console.WriteLine(s);};var h=new HashSet<string>();var c=new WebClient();var x=new XmlDocument();var t=c.DownloadString(@"http://wikipedia.org/wiki/"+a[0]);int i=0,C=0;
    GO:
        x.LoadXml(t);var ns=G(x);
    COL:
        var f=ns[i];if(f.Equals("/wiki/"+a[1],StringComparison.OrdinalIgnoreCase)){goto END;}if(h.Contains(f)){W("loop: "+f);i++;goto COL;}else{h.Add(f);i=0;C++;}W(f);t=c.DownloadString(@"http://wikipedia.org"+f);goto GO;
    END:
        W("Found in "+C);
    }
}

Versão inteligente:

class Program
{
    // arg[0] source article. arg[1] target article
    static void Main(string[] arg)
    {
        Func<XmlDocument, IList<string>> G = delegate(XmlDocument xd)
        {
            return xd.SelectNodes("//p//a[starts-with(@href,'/wiki/') and not(contains(@href,':'))]").Cast<XmlNode>().Select(n => n.Attributes["href"].InnerText).ToList();
        };
        Action<string> W = delegate(string s) { Console.WriteLine(s); };
        var h = new HashSet<string>(); var c = new WebClient(); var x = new XmlDocument();
        var allText = c.DownloadString(@"http://wikipedia.org/wiki/" + arg[0]);
        int i = 0; int C = 0;
    GO:
        x.LoadXml(allText);
        var ns = G(x);
    COL:
        var f = ns[i];
        if (f.Equals("/wiki/" + arg[1], StringComparison.OrdinalIgnoreCase))
        {
            goto END;
        }
        if (h.Contains(f))
        {
            W("loop: " + f); i++; goto COL;
        }
        else
        {
            h.Add(f); i = 0; C++;
        }
        W(f);
        allText = c.DownloadString(@"http://wikipedia.org" + f);
        goto GO;
    END:
        W("Found in " + C);
    }
}

Exemplo de execução, de "Sky" a "Philosophy":

C:\>wiki.exe Sky Philosophy

/wiki/Earth
/wiki/Geometric_albedo
/wiki/Phase_angle_(astronomy)
/wiki/Observational_astronomy
/wiki/Astronomy
/wiki/Natural_science
/wiki/Sciences
/wiki/Latin_language
/wiki/Classical_antiquity
/wiki/History
/wiki/Ancient_Greek
/wiki/Greek_language
/wiki/Modern_Greek
loop: /wiki/Greek_language
/wiki/Colloquialism
/wiki/Word
/wiki/Linguistics
/wiki/Science
loop: /wiki/Latin_language
/wiki/Knowledge
/wiki/Fact
/wiki/Latin
loop: /wiki/Classical_antiquity
/wiki/Italic_languages
/wiki/Indo-European_languages
/wiki/Language_family
/wiki/Language
/wiki/Human
/wiki/Extinct
/wiki/Biology
loop: /wiki/Natural_science
/wiki/Life
loop: /wiki/Earth
/wiki/Physical_body
/wiki/Physics
loop: /wiki/Greek_language
loop: /wiki/Natural_science
/wiki/Matter
/wiki/Rest_mass
/wiki/Center_of_momentum_frame
loop: /wiki/Physics
/wiki/Inertial_frame
loop: /wiki/Physics
/wiki/Frame_of_reference
loop: /wiki/Physics
/wiki/Coordinate_system
/wiki/Geometry
loop: /wiki/Ancient_Greek
/wiki/Mathematics
/wiki/Quantity
/wiki/Property_(philosophy)
/wiki/Modern_philosophy
Found in 41

C:\>
thepirat000
fonte
5

Scala (294 caracteres => 1000-294 + 140 = 846 pontos)

A solução atualizada que pega automaticamente o próximo link se já tiver sido consumido. Obrigado pelos 140 pontos de bônus.

Lógica: Escolha o primeiro link "/ wiki" que não tenha um ":" (ele ignora os links "Arquivo:"). Enxágue e repita com recursão retornando a contagem + 1 todas as vezes. Eu mantenho uma lista de todas as saídas anteriores à mão para que o programa não entre em um loop infinito.

Expressão regular: Eu tenho 2 formas da expressão regular.

  • "<p>.*?\"/wiki/([^:]*?)\".*?/p>"que encontra links nas <p>tags
  • "p>.*?/wiki/([^:]*?)\""que é uma tag um pouco mais experimental que provou funcionar, mas fornece resultados diferentes porque, às vezes, pega links na barra de informações do lado direito. Como artigos regulares, acredito que ainda seja válido. Se for julgado que não, o OP (ou outra pessoa) pode me deixar um comentário e eu posso atualizar minha solução para um melhor registro.

Vou usar a segunda expressão regular até encontrar um caso de teste em que ele não funcione ou o OP mencione que pegar links na barra lateral não é permitido (na minha opinião, as barras de informações ainda fazem parte de o artigo propriamente dito; mais um resumo).


Fonte Minificada:

object W extends App{print(x(Seq(args(0))));def x(s:Seq[Any]):Int={val? =s.last;println(?);?match{case "Philosophy"=>1;case _=>x(s:+"p>.*?/wiki/([^:]*?)\".*?/p>".r.findAllMatchIn(io.Source.fromURL("http://en.wikipedia.org/wiki/"+ ?).getLines.mkString).map(_ group 1).filter(!s.contains(_)).next)+1}}}

Fonte legível:

object W extends App {
  print(x(Seq(args(0))))

  def x(s: Seq[Any]): Int = {
    val ? = s.last
    println(?)
    ? match {
      case "Philosophy" => 1
      case _ => x(s :+ "p>.*?/wiki/([^:]*?)\"".r.findAllMatchIn(io.Source.fromURL("http://en.wikipedia.org/wiki/" + ?).getLines.mkString).map(_ group 1).filter(!s.contains(_)).next) + 1
    }
  }
}

Saída de amostra:

Entrada

Space_toilet

Saída

Space_toilet
Weightlessness
G-force
Weight
Force
SI_unit
French_language
Second_language
Language_acquisition
Word
Linguistics
Science
Latin_language
Pontifical_Academy_for_Latin
Pope_Benedict_XVI
Pope_Benedict_(disambiguation)
Regnal_name#Catholic_Church
Monarch
State_(polity)
Community
Commutative_property
Mathematics
Quantity
Property_(philosophy)
Modern_philosophy
Philosophy
26
javatarz
fonte
1
Scala não requer um objeto ou método principal. Você pode executá-lo com o intérprete como "scala <nome do arquivo> [args ..]". Use args(0)para obter o primeiro argumento, se livrar de seus objecte maindefinições, e eu acho que você pode remover o :Inttambém. pastebin.com/YqywKcG8
KChaloux
Acontece que você não pode remover o : Int. Não sabia que você estava fazendo uma ligação recursiva. Também o meu pastebin foi retirado de sua antiga fonte legível, mas os mesmos conceitos se aplicam.
precisa saber é o seguinte
Vou tentar me livrar do método principal. E sim, ligações recursivas me fizeram adicionar a opção :Intlá. Ainda hoje, também adicionarei uma forma legível da solução de 333 caracteres que tenho. Obrigado pelas sugestões @KChaloux
javatarz
1
Como eu disse, a referência a object Q extends App { ... }é totalmente desnecessária se você executar o código com o intérprete em vez de compilar com o scalac. Apenas execute comscala <filename> [args..]
KChaloux
4

R, 379 caracteres; 1000-379 + 170 = 791 pontos

Versão que pergunta aos usuários como proceder quando o loop é detectado

library(XML);w="http://en.wikipedia.org";W="/wiki/";n=1;A=c(scan(,""));while(A[n]!="Philosophy"){a=paste0(w,W,A[n]);d=sapply(strsplit(grep(W,sapply(xpathApply(xmlParse(readLines(a)),"//p/a[@href]|//ul/li/a[@href]",xmlAttrs),`[`,'href'),v=T),"/"),`[`,3);B=d[-grep(":",d)];n=n+1;if(B[1]%in%A)if(readline("Loop!2nd link?")=="n")break;A[n]=head(B[!B%in%A],1);cat(A[n],"\n")};cat(n-1)

Com recuos e comentários:

library(XML) #Uses package XML
w="http://en.wikipedia.org"
W="/wiki/"
n=1
A=c(scan(,"")) #Stdin + makes it a vector so we can store each iteration
while(A[n]!="Philosophy"){
    a=paste0(w,W,A[n])
    d=sapply(strsplit(grep(W,sapply( #The heart of the program
             xpathApply(xmlParse(readLines(a)),"//p/a[@href]|//ul/li/a[@href]",xmlAttrs),
             `[`,'href'),v=T),"/"),`[`,3)
    B=d[-grep(":",d)] #get rid of Templates, Files ,etc...
    n=n+1
    #Ask user if should proceed when loop encountered 
    #(any answer other than "n" is considered agreement):
    if(B[1]%in%A)if(readline("Loop!2nd link?")=="n")break
    A[n]=head(B[!B%in%A],1) #Take the first link that is not redundant
    cat(A[n],"\n")
    }
cat(n-1)

Exemplo de execução:

> library(XML);w="http://en.wikipedia.org";W="/wiki/";n=1;A=c(scan(,""));while(A[n]!="Philosophy"){a=paste(w,W,A[n],sep="");d=sapply(strsplit(grep(W,sapply(xpathApply(xmlParse(readLines(a)),"//p/a[@href]|//ul/li/a[@href]",xmlAttrs),`[`,'href'),v=T),"/"),`[`,3);B=d[-grep(":",d)];n=n+1;if(B[1]%in%A)if(readline("Loop!2nd link?")=="n")break;A[n]=head(B[!B%in%A],1);cat(A[n],"\n")};cat(n-1)
1: Extended_ASCII
2: 
Read 1 item
Eight-bit 
Computer_architecture 
Computer_science 
Science 
Logic 
List_of_aestheticians 
Art 
Human_behavior 
Behavior 
Organism 
Biology 
Loop!2nd link?y
Mathematics 
Quantity 
Property_(philosophy) 
Modern_philosophy 
Philosophy 
16

R, 325 caracteres; ??? pontos

Versão que, por padrão, obtém o primeiro link não redundante (ou seja, sem loop).

library(XML);w="http://en.wikipedia.org";W="/wiki/";n=1;A=c(scan(,""));while(A[n]!="Philosophy"){a=paste0(w,W,A[n]);d=sapply(strsplit(grep(W,sapply(xpathApply(xmlParse(readLines(a)),"//p/a[@href]|//ul/li/a[@href]",xmlAttrs),`[`,'href'),v=T),"/"),`[`,3);B=d[-grep(":",d)];n=n+1;A[n]=head(B[!B%in%A],1);cat(A[n],"\n")};cat(n-1)
plannapus
fonte