Analyser le format du dictionnaire Bookworm

42

Je me suis récemment laissé aller à une certaine nostalgie sous la forme de Bookworm Deluxe:

Au cas où vous ne l'auriez pas vue auparavant, c'est un jeu de mots où l'objectif est de relier des tuiles adjacentes pour former des mots. Afin de déterminer si une chaîne est un mot valide, il la compare à son dictionnaire interne, qui est stocké dans un format compressé ressemblant à ceci:

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

Les règles pour décompresser le dictionnaire sont simples:

  1. Lisez le numéro au début de la ligne et copiez ce nombre de caractères à partir du début du mot précédent. (S'il n'y a pas de numéro, copiez autant de caractères que la dernière fois.)

  2. Ajoutez les lettres suivantes au mot.

Ainsi, notre premier mot est aa, suivi de 2h, ce qui signifie "copie les deux premières lettres de aaet ajoute h," formant aah. Puis 3eddevient aahed, et depuis la ligne suivante ne porte pas de numéro, nous copier à nouveau 3 caractères à la forme aahing. Ce processus se poursuit dans le reste du dictionnaire. Les mots résultants du petit échantillon entré sont:

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

Votre défi consiste à effectuer cette décompression dans le moins d'octets possible.

Chaque ligne d’entrée contiendra zéro ou plusieurs chiffres 0-9 suivis d’une ou plusieurs lettres minuscules a-z. Vous pouvez prendre en entrée et donner en sortie soit une liste de chaînes, soit une chaîne unique avec des mots séparés par un caractère autre que 0-9/ a-z.

Voici un autre petit cas de test avec quelques cas marginaux non traités dans l'exemple:

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

Vous pouvez également tester votre code sur le dictionnaire complet: entrée , sortie .

Poignée de porte
la source
Est-il possible qu'il n'y ait pas de numéro dans la deuxième ligne? De plus, pouvons-nous supposer qu’aucun nombre, sauf 0les premiers, 0n’est s?
Erik l'Outgolfer
@EriktheOutgolfer Oui, c'est possible. J'ai ajouté cela au cas test. Et oui, vous pouvez supposer que (ainsi que le nombre ne sera pas supérieur à la longueur du mot précédent).
Poignée de porte
11
C'est un format de compression mignon:]
Poke
1
Le locateprogramme utilise ce type d’encodage sur les noms de chemin.
Dan D.
J'ai écrit ce programme pour mon usage actuel, il y a environ 15 ans. Malheureusement, je ne pense plus avoir la source ...
hobbs

Réponses:

13

Vim, 57 octets

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

Essayez-le en ligne!

DJMcMayhem
la source
Est <H<G-ce que la dernière substitution fonctionnerait?
Kritixi Lithos
@ cowsquack Malheureusement, non. Chaque entrée qui ne commence pas par un nombre augmente le nombre d'espaces de premier plan ; il n'y a donc aucun moyen de garantir qu'une <solution ne mente pas suffisamment de temps.
DJMcMayhem
Je pense que vous pouvez faire :%s/ *au lieu de la dernière substitution pour économiser deux octets.
Dexter CD le
10

JavaScript (ES6),  66 62  61 octets

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

Essayez-le en ligne!

Commenté

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()
Arnauld
la source
5

Perl 6 , 50 48 octets

-2 octets grâce à nwellnhof

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

Essayez-le en ligne!

Un port de la solution d' Arnauld . Mec, ce R||tour était une montagne russe de "je pense que cela pourrait être possible", de "non, c'est impossible", de "peut-être possible" et enfin "aha!"

Explication:

{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

La $l [R||]=~$/partie se traduit approximativement par $l= ~$/||+$lmais ... elle a la même quantité d'octets :(. A l'origine, il sauvegardait des octets en utilisant une variable anonyme, de sorte que cela my$lavait disparu, mais cela ne fonctionnait pas, car la portée correspond maintenant à la substitution, pas au mapcodeblock. Tant pis. Quoi qu'il en soit, Rc'est le méta-opérateur inverse, de sorte qu'il inverse les arguments de ||, de sorte que la $lvariable finit par se voir attribuer le nouveau numéro ( ~$/) si elle existe, sinon elle-même.

Cela pourrait être 47 octets si Perl 6 ne lançait pas une erreur de compilation un peu redondante pour =~.

Jo King
la source
5

Ruby , 49 45 43 octets

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

Essayez-le en ligne!

Explication

$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 $_
Kirill L.
la source
5

C, 65 57 octets

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

Essayez-le en ligne!

Explication:

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. */
Dexter CD
la source
5

brainfuck , 201 octets

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

Essayez-le en ligne!

Nécessite une fin de ligne à la fin de l’entrée. Une version sans cette exigence est plus longue de 6 octets:

brainfuck , 207 octets

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

Essayez-le en ligne!

Les deux versions supposent que tous les nombres sont strictement inférieurs à 255.

Explication

La bande est disposée comme suit:

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

La cellule "numéro" est égale à 0 si aucun chiffre n'est entré et à n + 1 si le nombre n est entré. L'entrée est prise à la cellule marquée "85".

,[                     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
Nitrodon
la source
4

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

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

Essayez-le en ligne!

Explication

J'ai cédé et j'ai utilisé des expressions régulières. Cela a sauvé au moins 17 octets. :

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

Lorsque la chaîne ne commence pas par un chiffre, la longueur de cette chaîne sera 0. Cela signifie que:

n=int(t or n)

sera nsi test vide, et int(t)sinon.

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

supprime le nombre que l'expression régulière a trouvé s(s'il n'y en a pas, les 0caractères seront supprimés , sans être stronqués) et remplacera tous les ncaractères sauf les premiers du mot précédent par le fragment de mot actuel; et:

yield w

affiche le mot actuel.

wizzwizz4
la source
4

Haskell, 82 81 octets

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

Prend et retourne une liste de chaînes.

Essayez-le en ligne!

        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 octet grâce à @Nitrodon.

nimi
la source
1
Contrairement à la sagesse habituelle de Haskell en matière de golf, vous pouvez enregistrer un octet ici en ne définissant pas la fonction d’aide comme un opérateur infixe.
Nitrodon
@Nitrodon: bien repéré! Merci!
nimi
3

Japt, 19 18 17 octets

Initialement inspiré par la solution JS d' Arnauld .

;£=¯V=XkB ªV +XoB

L'essayer

                      :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
Hirsute
la source
2

Gelée , 16 octets

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

Essayez-le en ligne!

Comment ça marche

⁹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.
Dennis
la source
1

Python 2 , 118 octets

import re
n=0
l=input()
o=l.pop(0)
print o
for i in l:(N,x),=re.findall('(\d*)(.+)',i);n=int(N or n);o=o[:n]+x;print o

Essayez-le en ligne!

Erik l'Outgolfeur
la source
1

Retina 0.8.2 , 69 octets

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

Essayez-le en ligne! Le lien inclut les cas de test plus difficiles. Explication:

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

Pour toutes les lignes commençant par des lettres, copiez le numéro de la ligne précédente, en boucle jusqu'à ce que toutes les lignes commencent par un nombre.

\d+
$*

Convertissez le nombre en unaire.

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

Utilisez des groupes d'équilibrage pour remplacer tous les 1s par la lettre correspondante de la ligne précédente. (Cela se révèle être légèrement plus golfique que de remplacer toutes les exécutions de 1s.)

Neil
la source
1

Rouge , 143 octets

func[b][a: charset[#"a"-#"z"]u: b/1 n: 0 foreach c b[parse c[copy m to a
p: copy s to end(if p<> c[n: do m]print u: rejoin[copy/part u n s])]]]

Essayez-le en ligne!

Galen Ivanov
la source
1

Java (JDK) , 150 octets

a->{String p="",s[];for(int n=0,i=0;i<a.length;a[i]=p=p.substring(0,n=s.length<1?n:new Short(s[0]))+a[i++].replaceAll("\\d",""))s=a[i].split("\\D+");}

Essayez-le en ligne!

Olivier Grégoire
la source
1

Groovy , 74 octets

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

Essayez-le en ligne!

Explication:

{                                                                        }  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
ASCII seulement
la source
0

Perl 5 -p , 45 41 octets

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

Essayez-le en ligne!

Explication:

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
wastl
la source
0

Groovy , 103 à 99 octets

{w=it[0];d=0;it.collect{m=it=~/(\d+)(.+)/;i=m.find()?{d=m[0][1] as int;m[0][2]}():it;w=w[0..<d]+i}}

Essayez-le en ligne!

GolfIsAGoodWalkSpoilt
la source
76?
ASCII uniquement
1
74?
ASCII uniquement
0

05AB1E , 20 19 17 octets

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

Essayez-le en ligne ou vérifiez tous les cas de test .

Explication:

õ                  # 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)
Kevin Cruijssen
la source
0

Common Lisp, 181 octets

(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)))

Essayez-le en ligne!

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

Comme d'habitude, les identifiants longs de Common Lisp le rendent particulièrement adapté au PPCG.

Renzo
la source
0

C # (compilateur interactif Visual C #) , 134 octets

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

Essayez-le en ligne!

-9 octets grâce à @ASCIIOnly!

Moins joué au golf ...

// 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);
  });
}
Dana
la source
134?
ASCII uniquement
C'est plutôt cool :) J'ai changé l=n>0?n:lpour l=m>0?n:lparce qu'il ne reprenait pas le cas lorsqu'une ligne commençait par zéro ( 0jkl). Merci pour le conseil!
Dana
0

Scala , 226 129 102 octets

Merci @ ASCII-only pour leur travail ici (et pour la réponse Groovy).

s=>{var(w,d,r)=("",0,"(\\d*)(.+)".r)
s map(_ match{case r(a,b)=>{if(a>"")d=a.toInt
w=w.take(d)+b}
w})}

Essayez-le en ligne!

V. Courtois
la source
: | les deux liens sont les mêmes
ASCII seulement
ouais, montage. Je ne savais pas comment le résoudre et j'étais pressé, je n'ai donc pas modifié ce que je faisais.
V. Courtois
130
ASCII seulement
129
ASCII seulement
127
ASCII seulement