Wikipedia: ¡filosofía!

26

Como muchos geeks pueden saber, la mayoría de las páginas (95% creo) en wikipedia eventualmente conducen a una filosofía como esta:

Haga clic en el primer enlace que no está en cursiva o entre paréntesis y que está a otro artículo normal: (es decir, no Archivo: o Especial :, pero cosas como Wikipedia: están bien) y repita en ese hasta que llegue a la filosofía.

El guión debe:

  • Tome una primera página como entrada
  • Imprima el nombre de cada artículo que llegue a
  • E imprima cuántos artículos le llevó llegar a Filosofía, y si no lo dijo.

Empiezas con 1000 puntos y pierdes uno por cada personaje en el código. Puntos de bonificación por:

Detectar artículos en bucle y detenerse: +50

Detectando artículos en bucle y solicitando si el usuario debe ir al siguiente enlace del artículo: +170

Permitiendo un valor predeterminado en la verificación anterior como un argumento de línea de comando o similar: +140

La puntuación más alta gana.

AlphaModder
fuente
77
+1, gran desafío! Esta detección de paréntesis es difícil: P
Pomo de la puerta
1
Tengo la sensación de que esto podría usar una mejor definición, pero aún no estoy seguro de cómo hacerlo.
Iszi
3
Pierde un punto por cada personaje escrito. Hmm Genial, lo tengo, solo copiaré y pegaré los personajes. No hay puntos perdidos!
Justin
55
No cambie las reglas después de que las respuestas ya se hayan publicado; eso es bastante grosero y generalmente mal visto en la comunidad aquí ...
Pomo de la puerta

Respuestas:

8

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

Estoy seguro de que hay muchas mejoras por hacer.

(Esto requiere 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

Ejemplo de ejecución:

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

Muestra uno donde tuve que ir a un enlace 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

Trucos que utilicé:

  • Usé el selector p apara obtener solo enlaces que no están en cursiva, porque todos los enlaces en el artículo real que no están en cursiva siempre están en elementos de párrafo en Wikipedia.
Pomo de la puerta
fuente
hmmm ... tal vez no debería permitir más que las bibliotecas que vienen con el idioma ...
AlphaModder
@ user1825860 En realidad no es una biblioteca que viene con el idioma; Es una joya. Edité mi respuesta. Pero realmente, ¿quieres tomar este desafío ya difícil y obligarnos a no usar también las bibliotecas de análisis HTML? : P
Pomo
no lo estoy rechazando pero pierdes puntos: P
AlphaModder
Debería releer la primera publicación y editar en consecuencia: P
AlphaModder
2
@ user1825860 No cambie las reglas después de que las respuestas ya se hayan publicado; eso es bastante grosero ...
Pomo de la puerta
5

"BASH " - (Si no está equivocado: 1000 - 397 + 170 + 140 = 913 puntos)
"BASH" - (Si no está equivocado: 1000 - 386 + 170 + 140 = 924 puntos)

"BASH" - (Si no se equivoca: 1000 - 381 + 170 + 140 = 929 puntos)

BASH está entre comillas a propósito ya que esta es una mezcla de herramientas utilizadas en shells * nix pero envueltas en un script bash.

Editar 1:

  • Eliminado http://por curldefecto a esto.
  • Cambiado href=partido en los anclajes de f=que <a>no tiene ningún otro normales atributos que termina en f. (Es una posibilidad de etiquetas personalizadas. No he visto ninguna hasta ahora).
  • Establezca el mensaje de salida en no encontrado en !Phillugar de NoPhil. Éste es un peculiar tan También se podría decir, por ejemplo !, 0, N, !Po similar.
  • Quirk two: -son curlpodría eliminarse para reducir en tres bytes más, pero eso produciría un resultado desordenado. No estoy seguro si eso es un problema.
  • Ayuda actualizada en esta página.

Usando peculiaridades, el código terminaría en 379 bytes, 931 puntos.

También podría aplicar @plannapus uso de coincidencia (con suerte) caja de navegación mediante la adición de (p|ul).*?<(\1)la adición de seis bytes (restando seis puntos).

Edición 2:

Utilizando ${#c[@]}para imprimir grados de separación en lugar de $icontador.

Usando peculiaridades, el código terminaría en 374 bytes, 936 puntos.


Invoco a Cthulhu y busco una solución regexp + bash / shell / * nix.

Robado:

Implementado:

  • Detecte el bucle y pregunte si se debe tomar el siguiente enlace.
  • Opcionalmente, seleccione el siguiente enlace en duplicado como opción.

Requisitos:

  • bash v.?
  • grepcon -Psoporte (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 en línea. Copiar a archivo. chmod +x filename. Ejecutado por ./script /wiki/…bash shell.

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 ampliado y 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
fuente
¡Maldita sea, me ganaste por un punto! : P Voy a tener que jugar más golf mi solución
Pomo de la puerta
Ye;), pero no estoy seguro de si este es un código válido. Usando herramientas de esta manera.
Runium
5

JavaScript 726 (444 caracteres [556] + 170)

Ahora aprecio que esto podría no ser válido como marcador, pero he disfrutado jugando de todos modos.

Uso: navegue a la página desde la que desea comenzar y ejecute lo siguiente en la consola:

(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, el resultado es el siguiente:

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

Esta solución supondrá que desea saltar al siguiente enlace en un bucle que se está detectando, pero si cambia trueal final false, aparecerá un cuadro de confirmación (bastante molesto ...) no estoy seguro de si eso califica para el bonificación secundaria o no. Asumo que no.

Sangrado:

(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

Así que originalmente me perdí la parte de ignorar los elementos en los padres, agregando que lo hacía mucho más prolijo, así que espero jugar esa función de filtro (o con suerte reemplazarla por completo).

Trabajando en Chrome y Firefox (probado en Firefox 26)

Dom Hastings
fuente
2
Parece increíble, pero falla en Firefox 20.
boothby
Argghh! Solo probé Chrome. ¡Lo miraré!
Dom Hastings
@boothby Debería estar trabajando en Firefox ahora ... ¡Sin embargo, todavía quiero trabajar en los enlaces que elijo!
Dom Hastings
5

C # - 813 caracteres

Puntuación: 1000-813 + 50 + 170 + 140 = 547 :(

No hay bibliotecas externas. Detección de bucle .

El primer argumento es el artículo fuente, el segundo es el artículo objetivo.

Versión de golf:

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);
    }
}

Versión inteligible:

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);
    }
}

Ejemplo ejecutado, de "Cielo" a "Filosofía":

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
fuente
5

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

La solución actualizada que toma automáticamente el siguiente enlace si ya se ha consumido uno. Gracias por los 140 puntos extra.

Lógica: seleccione el primer enlace "/ wiki" que no tenga un ":" (por lo que ignora los enlaces "Archivo:"). Enjuague y repita con recursión devolviendo el conteo + 1 cada vez. Mantengo una lista de todas las salidas anteriores a mano para que el programa no entre en un bucle infinito.

Expresión regular: tengo 2 formas de la expresión regular.

  • "<p>.*?\"/wiki/([^:]*?)\".*?/p>"que encuentra enlaces dentro de las <p>etiquetas
  • "p>.*?/wiki/([^:]*?)\""que es una etiqueta un poco más experimental que ha demostrado funcionar pero proporciona resultados diferentes porque, a veces, recoge enlaces de la barra de información del lado derecho. Estos son artículos regulares, así que creo que todavía es válido. Si se determina que no lo es, el OP (o alguien más) puede dejarme un comentario y puedo actualizar mi solución a un mejor registro.

Voy a usar la segunda expresión regular hasta que encuentre un caso de prueba en el que no funciona o el OP menciona que no está permitido recoger enlaces de la barra lateral (en mi opinión, las barras de información todavía son parte de el artículo en sí mismo; más de un resumen).


Fuente 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}}}

Fuente legible:

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
    }
  }
}

Salida de muestra:

Entrada

Space_toilet

Salida

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
fuente
1
Scala no requiere un objeto o método principal. Puede ejecutarlo con el intérprete como "scala <nombre de archivo> [args ..]". Uso args(0)de conseguir el primer argumento, deshacerse de sus objecty maindefiniciones, y creo que se puede quitar el :Inttambién. pastebin.com/YqywKcG8
KChaloux
Resulta que no puedes eliminar el : Int. No me di cuenta de que estabas haciendo una llamada recursiva. También mi pastebin fue tomado de su antigua fuente legible, pero se aplican los mismos conceptos.
KChaloux
Intentaré deshacerme del método principal. Y sí, las llamadas recursivas me hicieron agregar el :Intallí. Más tarde hoy, también agregaré una forma legible de la solución 333 char que tengo. Gracias por las sugerencias @KChaloux
javatarz
1
Como dije, la referencia a object Q extends App { ... }es totalmente innecesaria si ejecuta el código con el intérprete en lugar de compilar con scalac. Solo corre conscala <filename> [args..]
KChaloux
4

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

Versión que pregunta a los usuarios cómo proceder cuando se detecta un bucle

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)

Con muescas y comentarios:

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)

Ejemplo de ejecución:

> 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; ??? puntos

Versión que, por defecto, toma el primer enlace no redundante (es decir, sin bucle).

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
fuente