Analysieren Sie das Bookworm-Wörterbuchformat


42

Ich habe mir kürzlich eine Nostalgie in Form von Bookworm Deluxe gegönnt:

Falls Sie es noch nicht gesehen haben, ist es ein Wortspiel, bei dem benachbarte Kacheln zu Wörtern verbunden werden sollen. Um festzustellen, ob ein String ein gültiges Wort ist, vergleicht er es mit seinem internen Wörterbuch, das in einem komprimierten Format gespeichert ist, das wie folgt aussieht:

aa
2h
3ed
ing
s
2l
3iis
s
2rdvark
8s
4wolf
7ves

Die Regeln zum Entpacken des Wörterbuchs sind einfach:

  1. Lesen Sie die Nummer am Anfang der Zeile und kopieren Sie so viele Zeichen vom Anfang des vorherigen Wortes. (Wenn keine Nummer vorhanden ist, kopieren Sie so viele Zeichen wie beim letzten Mal.)

  2. Fügen Sie die folgenden Buchstaben an das Wort an.

Also, unser erstes Wort ist aa, gefolgt von 2h, was bedeutet, dass sich "die ersten beiden Buchstaben kopieren aaund anhängen h" bilden aah. Dann 3edwird aahed, und da die nächste Zeile keine Nummer hat, kopieren wir 3 Zeichen erneut zu bilden aahing. Dieser Vorgang wird im gesamten restlichen Wörterbuch fortgesetzt. Die resultierenden Wörter aus der kleinen Beispieleingabe sind:

aa
aah
aahed
aahing
aahs
aal
aaliis
aals
aardvark
aardvarks
aardwolf
aardwolves

Ihre Herausforderung besteht darin, dieses Entpacken in so wenigen Bytes wie möglich durchzuführen.

Jede Eingabezeile enthält keine oder mehrere Ziffern, 0-9 gefolgt von einem oder mehreren Kleinbuchstaben a-z. Sie können die Eingabe und Ausgabe entweder als Liste von Zeichenfolgen oder als einzelne Zeichenfolge mit Wörtern, die durch andere Zeichen als 0-9/ getrennt sind, vornehmen a-z.

Hier ist ein weiterer kleiner Testfall mit einigen Randfällen, die im Beispiel nicht behandelt werden:

abc cba 1de fg hi 0jkl mno abcdefghijk 10l
=> abc cba cde cfg chi jkl mno abcdefghijk abcdefghijl

Sie können Ihren Code auch im gesamten Wörterbuch testen: Eingabe , Ausgabe .


Gibt es die Möglichkeit, dass in der zweiten Zeile keine Nummer steht? Können wir auch davon ausgehen, dass keine Zahl außer 0führenden 0s haben wird?
Erik the Outgolfer

@EriktheOutgolfer Ja, das ist möglich; Ich habe das zum Testfall hinzugefügt. Und ja, Sie können davon ausgehen, dass die Zahl nicht länger als das vorherige Wort ist.
Türklinke

11
Das ist ein süßes Komprimierungsformat:]
Poke

1
Das locateProgramm verwendet diese Art der Codierung für Pfadnamen.
Dan D.

Ich habe dieses Programm vor ungefähr 15 Jahren für meinen eigentlichen Gebrauch geschrieben. Leider glaube ich nicht mehr, dass ich die Quelle habe ...
hobbs

Antworten:


13

Vim, 57 Bytes

:%s/\a/ &
:%norm +hkyiwjP
:g/\d/norm diw-@"yl+P
:%s/ //g

Probieren Sie es online!


Würde das <H<Ganstelle der letzten Auswechslung funktionieren?
Kritixi Lithos

@cowsquack Leider nein. Bei jeder Eingabe, die nicht mit einer Zahl beginnt, wird die Anzahl der führenden Leerzeichen erhöht, sodass nicht garantiert werden kann, dass eine <Lösung ausreichend oft nicht berücksichtigt wird.
DJMcMayhem

Ich denke, Sie können :%s/ *anstelle der letzten Ersetzung zwei Bytes speichern.
Dexter CD

10

JavaScript (ES6),  66 62  61 Bytes

a=>a.map(p=s=>a=a.slice([,x,y]=/(\d*)(.*)/.exec(s),p=x||p)+y)

Probieren Sie es online!

Kommentiert

a =>                  // a[] = input, re-used to store the previous word
  a.map(p =           // initialize p to a non-numeric value
  s =>                // for each string s in a[]:
    a =               //   update a:
      a.slice(        //     extract the correct prefix from the previous word:
        [, x, y] =    //       load into x and y:
          /(\d*)(.*)/ //         the result of a regular expression which splits the new
          .exec(s),   //         entry into x = leading digits and y = trailing letters
                      //       this array is interpreted as 0 by slice()
        p = x || p    //       update p to x if x is not an empty string; otherwise leave
                      //       it unchanged; use this as the 2nd parameter of slice()
      )               //     end of slice()
      + y             //     append the new suffix
  )                   // end of map()

5

Perl 6 , 50 48 Bytes

-2 bytes dank nwellnhof

{my$l;.map:{$!=S[\d*]=substr $!,0,$l [R||]=~$/}}

Probieren Sie es online!

Ein Hafen von Arnauld's Lösung . Mann, dieser R||Trick war eine Achterbahnfahrt von "Ich denke, das könnte möglich sein", zu "nah, es ist unmöglich", zu "irgendwie vielleicht möglich" und schließlich zu "aha!"

Erläuterung:

{my$l;.map:{$!=S[\d*]=substr $!,0,$l [R||]=~$/}}
{                                              }  # Anonymous code block
 my$l;    # Declare the variable $l, which is used for the previous number
      .map:{                                  }  # Map the input list to
            $!=              # $! is used to save the previous word
               S[\d*]=       # Substitute the number for
                      substr $!,0    # A substring of the previous word
                                 ,              # With the length of 
                                           ~$0     # The num if it exists
                                  $l [R||]=        # Otherwise the previous num

Der $l [R||]=~$/Teil wird grob übersetzt, hat $l= ~$/||+$laber die gleiche Anzahl von Bytes :(. Ursprünglich wurden die Bytes mithilfe einer anonymen Variablen gespeichert, sodass das my$lnicht mehr funktioniert, da der Gültigkeitsbereich jetzt die Ersetzung und nicht der mapCodeblock ist. Naja. Wie auch immer, Rist der umgekehrte metaoperator, so dass er die Argumente umkehrt ||, so dass der $lvariable endet die neue Nummer zugeordnet wird ( ~$/) , wenn es vorhanden ist , sonst selbst wieder.

Es könnten 47 Bytes sein, wenn Perl 6 keinen redundanten Compiler-Fehler verursacht =~.


5

Ruby , 49 45 43 Bytes

$0=$_=$0[/.{0#{p=$_[/\d+/]||p}}/]+$_[/\D+/]

Probieren Sie es online!

Erläuterung

$0=                                         #Previous word, assign the value of
   $_=                                      #Current word, assign the value of
      $0[/.{0#{              }}/]           #Starting substring of $0 of length p which is
               p=$_[/\d+/]||p               #defined as a number in the start of $_ if any 
                                 +$_[/\D+/] #Plus any remaining non-digits in $_

5

C, 65 57 Bytes

n;f(){char c[99];while(scanf("%d",&n),gets(c+n))puts(c);}

Probieren Sie es online!

Erläuterung:

n;                     /* n is implicitly int, and initialized to zero. */

f() {                  /* the unpacking function. */

    char c[99];        /* we need a buffer to read into, for the longest line in
                          the full dictionary we need 12 + 1 bytes. */

    while(             /* loop while there is input left. */

        scanf("%d",&n) /* Read into n, if the read fails because this line
                          doesn't have a number n's value does not change.
                          scanf's return value is ignored. */

        ,              /* chain expressions with the comma operator. The loop
                          condition is on the right side of the comma. */

        gets(c+n))     /* we read into c starting from cₙ. c₀, c₁.. up to cₙ is
                          the shared prefix of the word we are reading and the
                          previous word. When gets is successful it returns c+n
                          else it will return NULL. When the loop condition is
                          NULL the loop exits. */

        puts(c);}      /* print the unpacked word. */

5

Brainfuck , 201 Bytes

,[[[-<+>>>+<<]>-[---<+>]<[[-<]>>]<[-]>>[<<,>>>[-[-<++++++++++>]]++++<[->+<]-[----->-<]<]<]>>>[[>>]+[-<<]>>[[>>]+[<<]>>-]]+[>>]<[-]<[<<]>[->[>>]<+<[<<]>]>[>.>]+[>[-]<,.[->+>+<<]>>----------]<[<<]>-<<<,]

Probieren Sie es online!

Benötigt eine abschließende neue Zeile am Ende der Eingabe. Eine Version ohne diese Anforderung ist 6 Byte länger:

Brainfuck , 207 Bytes

,[[[-<+>>>+<<]>-[---<+>]<[[-<]>>]<[-]>>[<<,>>>[-[-<++++++++++>]]++++<[->+<]-[----->-<]<]<]>>>[[>>]+[-<<]>>[[>>]+[<<]>>-]]+[>>]<[-]<[<<]>[->[>>]<+<[<<]>]>[>.>]+[>[-]<,[->+>+<<]>>[----------<.<]>>]<[<<]>-<<<,]

Probieren Sie es online!

Bei beiden Versionen wird davon ausgegangen, dass alle Zahlen streng unter 255 liegen.

Erläuterung

Das Band ist wie folgt aufgebaut:

tempinputcopy 85 0 inputcopy number 1 a 1 a 1 r 1 d 0 w 0 o 0 l 0 f 0 ...

Die "Zahl" -Zelle ist gleich 0, wenn keine Ziffern eingegeben werden, und n + 1, wenn die Zahl n eingegeben wird. Die Eingabe erfolgt in der mit "85" gekennzeichneten Zelle.

,[                     take input and start main loop
 [                     start number input loop
  [-<+>>>+<<]          copy input to tempinputcopy and inputcopy
  >-[---<+>]           put the number 85 in the cell where input was taken
  <[[-<]>>]            test whether input is less than 85; ending position depends on result of comparison
                       (note that digits are 48 through 57 while letters are 97 through 122)
  <[-]>                clean up by zeroing out the cell that didn't already become zero
  >[                   if input was a digit:
   <<,>>               get next input character
   >[-[-<++++++++++>]] multiply current value by 10 and add to current input
   ++++                set number cell to 4 (as part of subtracting 47)
   <[->+<]             add input plus 10*number back to number cell
   -[----->-<]         subtract 51
  <]                   move to cell we would be at if input were a letter
 <]                    move to input cell; this is occupied iff input was a digit

                       part 2: update/output word

 >>>                   move to number cell
 [                     if occupied (number was input):
  [>>]+[-<<]>>         remove existing marker 1s and decrement number cell to true value
  [[>>]+[<<]>>-]       create the correct amount of marker 1s
 ]
 +[>>]<[-]             zero out cell containing next letter from previous word
 <[<<]>                return to inputcopy
 [->[>>]<+<[<<]>]      move input copy to next letter cell
 >[>.>]                output word so far
 +[                    do until newline is read:
  >[-]<                zero out letter cell
  ,.                   input and output next letter or newline
  [->+>+<<]            copy to letter cell and following cell
  >>----------         subtract 10 to compare to newline
 ]
 <[<<]>-               zero out number cell (which was 1 to make copy loop shorter)
 <<<,                  return to input cell and take input
]                      repeat until end of input

4

Python 3.6+, 172 195 156 123 122 121 104 Bytes

import re
def f(l,n=0,w=""):
 for s in l:t=re.match("\d*",s)[0];n=int(t or n);w=w[:n]+s[len(t):];yield w

Probieren Sie es online!

Erläuterung

Ich gab nach und benutzte reguläre Ausdrücke. Dies sparte mindestens 17 Bytes. :

t=re.match("\d*",s)[0]

Wenn die Zeichenfolge überhaupt nicht mit einer Ziffer beginnt, beträgt die Länge dieser Zeichenfolge 0. Das bedeutet, dass:

n=int(t or n)

wird sein, nwenn tleer ist, und int(t)ansonsten.

w=w[:n]+s[len(t):]

Entfernt die Zahl, von der der reguläre Ausdruck gefunden wurde s(wenn keine Zahl gefunden wurde, werden 0Zeichen entfernt, die nicht sgekürzt werden) und alle nZeichen bis auf die ersten Zeichen des vorherigen Wortes werden durch das aktuelle Wortfragment ersetzt. und:

yield w

gibt das aktuelle Wort aus.


4

Haskell, 82 81 Bytes

tail.map concat.scanl p["",""]
p[n,l]a|[(i,r)]<-reads a=[take i$n++l,r]|1<2=[n,a]

Nimmt und gibt eine Liste von Zeichenfolgen zurück.

Probieren Sie es online!

        scanl p["",""]        -- fold function 'p' into the input list starting with
                              -- a list of two empty strings and collect the
                              -- intermediate results in a list
  p [n,l] a                   -- 1st string of the list 'n' is the part taken form the last word
                              -- 2nd string of the list 'l' is the part from the current line
                              -- 'a' is the code from the next line
     |[(i,r)]<-reads a        -- if 'a' can be parsed as an integer 'i' and a string 'r'
       =[take i$n++l,r]       -- go on with the first 'i' chars from the last line (-> 'n' and 'l' concatenated) and the new ending 'r'
     |1<2                     -- if parsing is not possible
       =[n,a]                 -- go on with the previous beginning of the word 'n' and the new end 'a'
                              -- e.g. [         "aa",     "2h",      "3ed",       "ing"       ] 
                              -- ->   [["",""],["","aa"],["aa","h"],["aah","ed"],["aah","ing"]]
  map concat                  -- concatenate each sublist
tail                          -- drop first element. 'scanl' saves the initial value in the list of intermediate results. 

Edit: -1 Byte dank @Nitrodon.


1
Im Gegensatz zu dem üblichen Haskell Golf - Weisheit, können Sie tatsächlich speichert ein Byte hier nicht die Helferfunktion als Infixoperator definieren.
Nitrodon

@Nitrodon: gut gesehen! Vielen Dank!
nimi

3

Japt, 19 18 17 Bytes

Ursprünglich inspiriert von Arnauld's JS-Lösung .

;£=¯V=XkB ªV +XoB

Versuch es

                      :Implicit input of string array U
 £                    :Map each X
   ¯                  :  Slice U to index
      Xk              :    Remove from X
;       B             :     The lowercase alphabet (leaving only the digits or an empty string, which is falsey)
          ªV          :    Logical OR with V (initially 0)
    V=                :    Assign the result to V for the next iteration
             +        :  Append
              Xo      :  Remove everything from X, except
;               B     :   The lowercase alphabet
  =                   :  Reassign the resulting string to U for the next iteration

2

Gelee , 16 Bytes

⁹fØDVo©®⁸ḣ;ḟØDµ\

Probieren Sie es online!

Wie es funktioniert

⁹fØDVo©®⁸ḣ;ḟØDµ\  Main link. Argument: A (array of strings)

              µ\  Cumulatively reduce A by the link to the left.
⁹                     Yield the right argument.
  ØD                  Yield "0123456789".
 f                    Filter; keep only digits.
    V                 Eval the result. An empty string yields 0.
     o©               Perform logical OR and copy the result to the register.
       ®              Yield the value in the register (initially 0).
        ⁸ḣ            Head; keep that many character of the left argument.
          ;           Concatenate the result and the right argument.
            ØD        Yield "0123456789".
           ḟ          Filterfalse; keep only non-digits.


1

Retina 0,8,2 , 69 Bytes

+`((\d+).*¶)(\D)
$1$2$3
\d+
$*
+m`^((.)*(.).*¶(?<-2>.)*)(?(2)$)1
$1$3

Probieren Sie es online! Link enthält härtere Testfälle. Erläuterung:

+`((\d+).*¶)(\D)
$1$2$3

Kopieren Sie für alle Zeilen, die mit Buchstaben beginnen, die Nummer aus der vorherigen Zeile, und wiederholen Sie den Vorgang, bis alle Zeilen mit einer Nummer beginnen.

\d+
$*

Wandle die Zahl in eine unäre um.

+m`^((.)*(.).*¶(?<-2>.)*)(?(2)$)1
$1$3

Verwenden Sie Bilanzkreise, um alle 1s durch den entsprechenden Buchstaben aus der vorherigen Zeile zu ersetzen . (Dies stellt sich als etwas golfer heraus, als alle Läufe von 1s zu ersetzen .)




1

Groovy , 74 Bytes

{w="";d=0;it.replaceAll(/(\d*)(.+)/){d=(it[1]?:d)as int;w=w[0..<d]+it[2]}}

Probieren Sie es online!

Erläuterung:

{                                                                        }  Closure, sole argument = it
 w="";d=0;                                                                  Initialize variables
          it.replaceAll(/(\d*)(.+)/){                                   }   Replace every line (since this matches every line) and implicitly return. Loop variable is again it
                                     d=(it[1]?:d)as int;                    If a number is matched, set d to the number as an integer, else keep the value
                                                        w=w[0..<d]+it[2]    Set w to the first d characters of w, plus the matched string


0

Perl 5 -p , 45 41 Bytes

s:\d*:substr($p,0,$l=$&+$l*/^\D/):e;$p=$_

Probieren Sie es online!

Erläuterung:

s:\d*:substr($p,0,$l=$&+$l*/^\D/):e;$p=$_ Full program, implicit input
s:   :                           :e;      Replace
  \d*                                       Any number of digits
      substr($p,0,              )           By a prefix of $p (previous result or "")
                  $l=  +                      With a length (assigned to $l) of the sum
                     $&                         of the matched digits
                          *                     and the product
                        $l                        of $l (previous length or 0)
                           /^\D/                  and whether there is no number in the beginning (1 or 0)
                                                (product is $l if no number)
                                    $p=$_ Assign output to $p
                                          Implicit output


0

05AB1E , 20 19 17 Bytes

õUvyþDõÊi£U}Xyá«=

Probieren Sie es online aus oder überprüfen Sie alle Testfälle .

Erläuterung:

õ                  # Push an empty string ""
 U                 # Pop and store it in variable `X`
v                  # Loop `y` over the (implicit) input-list
 yþ                #  Push `y`, and leave only the digits (let's call it `n`)
   DõÊi  }         #  If it's NOT equal to an empty string "":
       £           #   Pop and push the first `n` characters of the string
        U          #   Pop and store it in variable `X`
          X        #  Push variable `X`
           yá      #  Push `y`, and leave only the letters
             «     #  Merge them together
              =    #  Print it (without popping)

0

Common Lisp, 181 Bytes

(do(w(p 0))((not(setf g(read-line t()))))(multiple-value-bind(a b)(parse-integer g :junk-allowed t)(setf p(or a p)w(concatenate'string(subseq w 0 p)(subseq g b)))(format t"~a~%"w)))

Probieren Sie es online!

Ungolfed:

(do (w (p 0))   ; w previous word, p previous integer prefix (initialized to 0)
    ((not (setf g (read-line t ()))))   ; read a line into new variable g
                                        ; and if null terminate: 
  (multiple-value-bind (a b)            ; let a, b the current integer prefix
      (parse-integer g :junk-allowed t) ; and the position after the prefix
    (setf p (or a p)                    ; set p to a (if nil (no numeric prefix) to 0)
          w (concatenate 'string        ; set w to the concatenation of prefix
             (subseq w 0 p)             ; characters from the previous word 
             (subseq g b)))             ; and the rest of the current line
    (format t"~a~%"w)))                 ; print the current word

Die langen Identifikatoren von Common Lisp machen es wie üblich nicht besonders für PPCG geeignet.



0

C # (Visual C # Interactive Compiler) , 134 Byte

a=>{int l=0,m,n;var p="";return a.Select(s=>{for(m=n=0;s[m]<58;n=n*10+s[m++]-48);return p=p.Substring(0,l=m>0?n:l)+s.Substring(m);});}

Probieren Sie es online!

-9 Bytes dank @ASCIIOnly!

Weniger golfen ...

// a is an input list of strings
a=>{
  // l: last prefix length
  // m: current number of digits
  // n: current prefix length
  int l=0,m,n;
  // previous word
  var p="";
  // run a LINQ select against the input
  // s is the current word
  return a.Select(s=>{
    // nibble digits from start of the
    // current word to build up the
    // current prefix length
    for(m=n=0;
      s[m]<58;
      n=n*10+s[m++]-48);
    // append the prefix from the
    // previous word to the current
    // word and capture values
    // for the next iteration
    return
      p=p.Substring(0,l=m>0?n:l)+
      s.Substring(m);
  });
}


Das ist ziemlich cool :) Ich habe zu gewechselt l=n>0?n:l, l=m>0?n:lweil es den Fall nicht aufgegriffen hat, als eine Zeile mit Null ( 0jkl) begann. Danke für den Tipp!
Dana

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.