Formwandelkästen

18

Ich definiere vier Boxstile:

+-----+   ooooooo    ^^^^^   *******
|  1  |   o  2  o   <  3  >  *  4  *
|     |   o     o   <     >  *     *
+-----+   ooooooo    vvvvv   *******

Schreiben Sie ein Programm oder eine Funktion, die mit einer Ganzzahl und einer Zeichenfolge eines der obigen Kästchen in der Zeichenfolge findet und dessen Stil in den vom Benutzer gewünschten Kästchenstil ändert. Beispielsweise:

1
This is a test document.
It ********* has
no *purpose* other than
dem*onstrat*ion.
   *********

Wird:

This is a test document.
It +-------+ has
no |purpose| other than
dem|onstrat|ion.
   +-------+

Sie können davon ausgehen, dass die Eingabe genau ein gültiges Feld enthält, das mindestens 3x3 ist. Ihr Code muss unvollständige / falsche Felder ignorieren:

ooooooooooooooooooooooooooooooooo
o This is not a box. o This is. o
ooooooooooo ooooo ooooooooooooooo

      ^^^^     ######
     <NOPE>    #NOPE#
      vVVv     ######

Kürzester Code in Bytes gewinnt.

orlp
quelle
Nur um klar zu sein, im letzten Beispiel ist das Kästchen mit den 2 Großbuchstaben Vs ungültig, aber wenn diese in Kleinbuchstaben vs geschrieben werden, wäre das Kästchen dann noch gültig? Auch wenn es mehrere Kästchen gibt, müssen wir nur 1 ändern, richtig?
Kade,
@ Vioz- Richtig, das Feld mit dem Großbuchstaben Vs ist nur wegen der nicht übereinstimmenden Großschreibung ungültig. Sie können davon ausgehen, dass es niemals zwei oder mehr gültige Felder geben wird - es wird immer genau ein gültiges Feld in der Eingabe geben.
Orlp
Benötigt Stil 3 Leerzeichen in den Ecken?
PurkkaKoodari
@ Pietu1998 Ja.
Orlp
1
Es dauerte einen Moment, bis ich herausgefunden hatte, warum ich von meinem "find the box" - Code eine seltsame Ausgabe erhielt ... Ihr Beispiel für eine Box am Ende enthält zwei gültige Boxen:, o This is. ound o This is no(mit Zeilen von ooben und unten natürlich).
Glen O

Antworten:

5

Julia, 995 818 713 613 Bytes

g=(s,n)->(w=map;f=t->(t[z=end];for i=1:z-2,j=eachmatch(r"([*o]|(\+)|(\ ))(?(2)-|(?(3)\^|\1))+\1",t[i],1>0),k=i+2:z N=j.match;N[M=end];p=N[1];J=j.offset;u=w(i->i[[J:J+M-1]∩[1:end]],t);try p%3<1?for l=matchall(r"^([*o])\1+\1",u[k]),q=3:endof(l) w(r->r[[1,q]],u[i:k])⊆["$p$p"]&&return(i,k,J,J+q-1)end:u[k]==replace(N,"^","v")&&w(r->r[[1,M]],u[i+1:k-1])⊆[p<33?"<>":"||"]&&return(i,k,J,M+J-1)end;end);o=ones(5)';T=split(s,'\n');(i,j,k,l)=f(T);u=w(collect,T);(a,u[i][r=k+1:l-1],u[j][r],b,c)=41+[2 4 4 83 83;70o;-9 53 77 19 21;o][n,:];u[i][I]=u[j][I=[k,l]]=a;w(e->(e[k]=b;e[l]=c),u[i+1:j-1]);join(w(join,u),'\n'));

Ungolfed mit Erklärung:

function g(s,n)
  # First, we define function f(t), which finds the box
  function f(t)
    # determine the number of rows of text
    z=length(t)
    # Get an iterator of all of the matches to iterate over
    # Regex handles all four box styles
    temp=i->eachmatch(r"([*o]|(\+)|(\ ))(?(2)-|(?(3)\^|\1))+\1",t[i],1>0)
    # Iterate over rows up to third-last one (i)...
    # and over any possible box-tops on each of those rows (j)...
    # and all possible box-bottom rows for each possible box-top (k)
    for i=1:z-2,j=temp(i),k=i+2:z
      # N holds the matched box-top
      N=j.match
      # M stores the length of the match
      M=length(N)
      # p holds the first letter of the match, the corner character.
      p=N[1]
      # J holds the position of the first character of the match in row i
      J=j.offset
      # The intersection here allows truncation of each row to only those
      # parts that lie within the valid range of the box-top
      u=map(i->i[[J:J+M-1]∩[1:end]],t)
      # A try block is being used to skip if a BoundsError is encountered
      # this BoundsError will occur if a box cannot be formed due to
      # a row not being long enough to form both sides or to form bottom
      try
        # This distinguishes between simple boxes (types 2 and 4)
        # from fancy boxes (types 1 and 3), as code differs between them
        if p%3<1 # "then" for simple boxes
          # loop over l either doesn't run (if bottom won't form a match
          # from position 1 within u) or holds the unique match
          # then loop over q looks at all possible bottom-lengths
          for l=matchall(r"^([*o])\1+\1",u[k]),q=3:endof(l)
            # If box sides are found to match top and bottom...
            if map(r->r[[1,q]],u[i:k])⊆["$p$p"]
              # return the coordinates of the box
              return(i,k,J,J+q-1)
            end
          end
        else # "else" for fancy boxes
          # If the bottom matches the top (replace fixes for type 3)...
          if u[k]==replace(N,"^","v")
            # ... and the edges are also there...
            if map(r->r[[1,M]],u[i+1:k-1])⊆[p<33?"<>":"||"]
              # return the coordinates
              return(i,k,J,M+J-1)
            end
          end
        end
      end
    end
  end
  # That defines function f(t), now for the replacement part of the code
  # Input s is a single string with newlines, split into separate strings
  T=split(s,'\n')
  # Find the coordinates of the box using f(T)
  (i,j,k,l)=f(T)
  # u holds the same strings, but stored as char arrays
  u=map(collect,T)
  # Here, we have the appropriate replacement characters for each type
  # with n determining which character from each array is taken
  # Variable names are used here to make it clearer
  corners =  ['+';'o';' ';'*'][n]
  topedge =  ['-';'o';'^';'*'][n]
  bottomedge=['-';'o';'v';'*'][n]
  leftedge = ['|';'o';'<';'*'][n]
  rightedge= ['|';'o';'>';'*'][n]
  # Assign the appropriate characters in the appropriate places
  u[i][[k,l]]=corners
  u[j][[k,l]]=corners
  u[i][k+1:l-1]=topedge
  u[j][k+1:l-1]=bottomedge
  # Iteration is required here because it's an array of arrays
  for e=i+1:j-1
    u[e][k]=leftedge
    u[e][l]=rightedge
  end
  # All that's left to do is recombine to form a single string again
  # we join each internal char array into single-line strings...
  # then join the strings together with a newline delimiter, and return
  return join(map(join,u),'\n')
end

Im Gegensatz zu meiner ersten Vorgehensweise funktioniert dieser Code nur für "gültige" Typennummern - 1, 2, 3 oder 4. Er ist in zwei Teile unterteilt - einen Boxfinder und einen Boxersetzer. Der Box-Finder-Code function f(t)verwendet reguläre Ausdrücke, um Oberseiten und für die einfacheren Boxen (Typen 2 und 4) Unterseiten zu lokalisieren.

Der erste reguläre Ausdruck ist der einfachste Weg, den ich finden konnte, um die Box-Tops zu finden. Hier ist die Logik davon:

r"([*o]|(\+)|(\ ))(?(2)-|(?(3)\^|\1))+\1"
  ([*o]|(\+)|(\ ))                        < This finds the first corner
        ( 2) ( 3)                         . if a + or space, conditionals
  (    1         )                        . kick in, so they're captured
                                          . separately
                  (?(2)-|           )     < If a +, top edge must be
                                          . at least one -
                         (?(3)\^|\1)      < Otherwise, if a space, top
                                          . edge must be at least one ^,
                                          . otherwise, repeat the corner
                                     +    < Allows more than one top-edge
                                          . character
                                      \1  < finish with the same corner
                                          . char found at the start

Der Code wird folgendermaßen verwendet:

julia> s="""This is a test document.
       It************* has
       no *purpose* other than
       dem*onstrat*ion.
        ************o""";

julia> print(s)
This is a test document.
It************* has
no *purpose* other than
dem*onstrat*ion.
 ************o
julia> print(g(s,1))
This is a test document.
It*+-------+*** has
no |purpose| other than
dem|onstrat|ion.
 **+-------+*o

Das Drucken ist in der Funktion nicht enthalten, da das Ausgabeformat nicht angegeben ist. Ich gebe nur die Zeichenfolge zurück. Sie können sie anschließend wie oben gezeigt drucken.

Glen O
quelle