Rilevamento portale Nether


53

Il videogioco Minecraft è incentrato sul posizionamento e la rimozione di diversi tipi di blocchi nel reticolo intero 3D che costituisce il mondo virtuale. Ogni punto reticolare può contenere esattamente un blocco o essere vuoto (un blocco " aria " ufficialmente). In questa sfida, ci occuperemo solo di un piano 2D verticale del mondo 3D e di un tipo di blocco: ossidiana .

Quando l'ossidiana forma il contorno di un rettangolo vuoto su un piano verticale, è possibile creare un portale inferiore . Il rettangolo vuoto può essere di qualsiasi dimensione da 2 unità di larghezza per 3 unità di altezza a 22 unità di larghezza per 22 unità di altezza. Gli angoli del rettangolo non devono necessariamente essere bordati in ossidiana, ma solo i lati.

Ad esempio, supponiamo che Xsia ossidiana ed .è vuoto: (I numeri sono solo a scopo identificativo e sono anche vuoti.)

...................................
..XXXX....XXXX....XXXXXXXXX........
..X..X...X....X..X.........X..XXXX.
..X.1X...X.2..X..X...3...X.X..X....
..X..X...X....XXXX.........X..X.6X.
..XXXX....XXXX...XXXXXXXXXXX..X..X.
.............X.4.X....X.5.X...XXXX.
.............X...X....X...X........
..............XXX......XXX.........
...................................

Questa griglia contiene 3 portali validi:

  • Il portale 1 è 2 per 3 unità, totalmente vuoto e delimitato da ossidiana. Pertanto è valido.
  • Il portale 2 è 4 per 3, completamente vuoto e delimitato da ossidiana. Pertanto è valido.
  • Portal 3 non è completamente vuoto. Pertanto non è valido.
  • Il portale 4 è 3 per 3, completamente vuoto e delimitato da ossidiana. Pertanto è valido.
  • Portal 5 è 3 per 2 unità, che è troppo piccolo. Pertanto non è valido.
  • Nel portale 6 manca una parte del bordo. Pertanto non è valido.

Sfida

Scrivi un programma o una funzione che includa queste rappresentazioni di stringhe di griglie di ossidiana e vuoto, e stampa o restituisce il numero di portali bassi validi presenti.

  • L'input può essere da argomento stdin o file o funzione.
  • Si può presumere che l'input sia sempre ben formato, ovvero una griglia di testo perfettamente rettangolare, larga almeno 1 carattere, contenente solo Xe .. Puoi facoltativamente supporre che ci sia una nuova riga finale dopo l'ultima riga.

  • Se lo si desidera, è possibile utilizzare due caratteri ASCII stampabili distinti al posto di Xe ..

  • L'ossidiana può trovarsi ai bordi della griglia. Qualsiasi cosa oltre i confini è considerata vuota.

Esempio di input: l'output dovrebbe essere 4:

................................................................
...................................XXXXXXXXXXXXXXXXXXXXXXXXX....
..XXXX....XXXX....XXXXXXXXX........X.......................X....
..X..X...X....X..X.........X..XXXX.X.......................X....
..X..X...X....X..X.......X.X..X....X.......................X....
..X..X...X....XXXX.........X..X..X..XXXXXXXXXXXXXXXXXXXXXXXX....
..XXXX....XXXX...XXXXXXXXXXX..X..X.X......................X..XXX
.............X...X....X...X...XXXX.X......................X..X..
.............X...X....X...X........X......................X..X..
..............XXX......XXX........XXXXXXXXXXXXXXXXXXXXXXXX...X..
..................................XX.........................XXX

punteggio

Vince l'invio con il minor numero di byte .


Posso usare un altro carattere ASCII al posto delle nuove righe?
Zgarb,

@Zgarb No, voglio ancora che l'input appaia come una griglia.
Calvin's Hobbies

4
Quando sono cambiate le dimensioni dei portali del Nether da 2x3 statico a dimensioni maggiori opzionali?
Sparr

5
@Sparr SInce 1.7.2 (consultare la cronologia degli aggiornamenti ). Non sono sicuro che possano farlo nelle edizioni della console.
Calvin's Hobbies

4
Sicuramente +1 perché Minecraft.
Alex A.

Risposte:


24

Perl, 81 86

Utilizzando più di una regexp.

#!perl -p0
$_=map{/.
/;$n="@-"-++$.;/(?=X{$.}..{$n}(X\.{$.}X.{$n}){3,22}.X{$.})/gs}($_)x21

La regexp per una larghezza specifica di un portale è molto più semplice di una generica: X{$m}..{$n}(X\.{$m}X.{$n}){3,22}.X{$m}dov'è mla larghezza del portale ed nè total width - 1 - m. Il regexp deve essere inserito in un'asserzione in avanti di larghezza zero (?=...)perché le corrispondenze possono sovrapporsi. Quindi ho ripetuto 21 volte su questa impostazione regexp $ne $.. "@-"valuta l'inizio della posizione dell'ultima corrispondenza ( /.\n/) che risulta essere la larghezza totale - 1. $.viene utilizzata come altra variabile quando viene inizializzata 1quando utilizzata con -p0.


2
Puoi salvare un byte se usi un carattere diverso rispetto .alle celle vuote (quindi non devi scappare).
Martin Ender,

62

Regex (sapore .NET), 182 181 145 132 126 114 104 100 98 97 96 byte

Riconoscimento del modello di arte ASCII 2D? Sembra un lavoro per regex! (Non lo fa.)

So che questo scatenerà di nuovo discussioni infinite sul fatto che gli invii regex siano programmi validi o meno, ma dubito che questo batterà APL o CJam comunque, quindi non vedo alcun danno. (Detto questo, che fanno passare il nostro test di die-hard per "Che cosa è un linguaggio di programmazione?" .)

Questo accetta l'input come stringa da abbinare e il risultato è il numero di corrispondenze trovate. Usa _al posto di ., perché dovrei sfuggire a quest'ultimo. Richiede anche una nuova riga finale.

(X(X){1,21})(?=\D+((?>(?<-2>_)+)_))(?=.((?!\7)(.)*
.*(X\3X|()\1.)(?=(?<-5>.)*(?(5)!)
)){4,23}\7)

Puoi provarlo dal vivo su RegexHero o RegexStorm ). Le partite saranno le prime file di ossidiana dei portali. Se riesci a trovare un caso di prova in cui non riesce, fammi sapere!

Cos'è questa stregoneria?

La seguente spiegazione presuppone una comprensione di base dei gruppi di bilanciamento di .NET . Il punto è che le acquisizioni sono stack nella regex di .NET: ogni nuova acquisizione con lo stesso nome viene inserita nello stack, ma c'è anche una sintassi per estrarre nuovamente le catture da quelle pile, così come la sintassi per estrarre le acquisizioni da una pila e spingere le acquisizioni su un altro allo stesso tempo. Per un quadro più completo, puoi dare un'occhiata alla mia risposta su Stack Overflow che dovrebbe coprire tutti i dettagli.

L'idea di base è abbinare un modello come:

 X{n}..{m}
X_{n}X.{m} |
X_{n}X.{m} |  3 to 22 times
X_{n}X.{m} |
 X{n}..{m} 

Dove nè compreso tra 2 e 22 (incluso). La cosa difficile è far sì che tutte le ns siano tutte muguali. Poiché i personaggi effettivi non saranno gli stessi, non possiamo semplicemente usare un backreference.

Nota che regex deve incorporare le nuove righe, che scriverò come \ndi seguito.

(                     # Open capturing group 1. This will contain the top of a portal, which
                      # I can reuse later to match the bottom (being of the same length).
  X                   # Match a single X.
  (X){1,21}           # Match 1 to 21 X's, and push each separately on the <2> stack. Let's
                      # Call the number of X's captured N-1 (so N is the inner width of the
                      # portal).
)                     # End of group 1. This now contains N X's.
(?=                   # Start a lookahead. The purpose of this lookahead is to capture a 
                      # string of N underscores in group 2, so I can easily use this to match 
                      # the inside rows of the portal later on. I can be sure that such a 
                      # string can always be found for a valid portal (since it cannot have 0 
                      # inner height).
  \D+                 # Skip past a bunch of non-digits - i.e. *any* of the vaild characters
                      # of the input (_, X, \n). This to make sure I search for my N 
                      # underscores anywhere in the remainder of the input.
  (                   # Open capturing group 3. This will contain a portal row.
    (?>               # This is an atomic group. Once the engine hass successfully matched the
                      # contents of this group, it will not go back into the group and try to
                      # backtrack other possible matches for the subpattern.
      (?<-2>_)+       # Match underscores while popping from the <2> stack. This will match as
                      # many underscores as possible (but not more than N-1).
    )                 # End of the atomic group. There are two possible reasons for the
                      # subpattern stopping to match: either the <2> stack is empty, and we've
                      # matched N-1 underscores; or we've run out of underscores, in which 
                      # case we don't know how many underscores we matched (which is not 
                      # good).
    _                 # We simply try to match one more underscore. This ensures that we 
                      # stopped because the <2> stack was empty and that group 3 will contain
                      # exactly N underscores.
  )                   # End of group 3.
)                     # End of the lookahead. We've got what we want in group 2 now, but the
                      # regex engine's "cursor" is still at the end of the portal's top.
(?=                   # Start another lookahead. This ensures that there's actually a valid
                      # portal beneath the top. In theory, this doesn't need to be a 
                      # lookahead - I could just match the entire portal (including the lines
                      # it covers). But matches cannot overlap, so if there were multiple
                      # portals next to each other, this wouldn't return all of them. By 
                      # putting the remainder of the check in a lookahead the actual matches
                      # won't overlap (because the top cannot be shared by two portals).
  .                   # Match either _ or X. This is the character above the portal side.

  (                   # This group (4) is where the real magic happens. It's purpose is to to
                      # count the length of the rest of the current line. Then find a portal
                      # row in the next line, and ensure that it's the same distance from the
                      # end of the line. Rinse and repeat. The tricky thing is that this is a
                      # single loop which matches both inner portal rows, as well as the 
                      # bottom, while making sure that the bottom pattern comes last.

    (?!\7)            # We didn't have a group 7 yet... group 7 is further down the pattern.
                      # It will capture an empty string once the bottom row has been matched.
                      # While the bottom row has not been matched, and nothing has been
                      # captured, the backreference will fail, so the negative lookahead will
                      # pass. But once we have found the bottom row, the backreference will
                      # always match (since it's just an empty string) and so the lookahead
                      # will fail. This means, we cannot repeat group 4 any more after the
                      # bottom has been matched.
    (.)*              # Match all characters until the end of the line, and push each onto
                      # stack <5>.
    \n                # Match a newline to go to the next line.
    .*                # Match as many characters as necessary to search for the next portal
                      # row. This conditions afterwards will ensure that this backtracks to
                      # the right position (if one exists).
    (                 # This group (6) will match either an inner portal row, or the bottom
                      # of the portal.
      X\3X            # Match X, then N underscores, then X - a valid inner portal row.
    |                 # OR
      ()              # Capture an empty string into group 7 to prevent matching further rows.
      \1.             # Use the captured top to match the bottom and another character.
    )
    (?=               # This lookahead makes sure that the row was found at the same 
                      # horizontal position as the top, by checking that the remaining line
                      # is the same length.
      (?<-5>.)*       # Match characters while popping from the <5> stack.
      (?(5)!)\n       # Make sure we've hit end of the line, *and* the <5> stack is empty.
    )
  ){4,23}             # Repeat this 4 to 23 times, to ensure an admissible portal height.
                      # Note that this is one more than the allowed inner height, to account
                      # for the bottom row.
  \7                  # Now in the above repetition there is nothing requiring that we have
                      # actually matched any bottom row - it just ensured we didn't continue
                      # if we had found one. This backreference takes care of that. If no
                      # bottom row was found, nothing was captured into group 7 and this
                      # backreference fails. Otherwise, this backreference contains an empty
                      # string which always matches.
)

C #, 185 byte

Ecco una funzione C # completa, solo per renderla una voce valida. È tempo che scriva un "interprete" da riga di comando per le espressioni regolari di .NET ...

static int f(string p){return System.Text.RegularExpressions.Regex.Matches(p,@"(X(X){1,21})(?=\D+((?>(?<-2>_)+)_))(?=.((?!\7)(.)*
.*(X\3X|()\1.)(?=(?<-5>.)*(?(5)!)
)){4,23}\7)").Count;}

5
Hmm, non sono sicuro di come mi sento per una risposta regex pura. La corrispondenza delle parti superiori non equivale alla stampa del numero. Naturalmente sarebbe bene usare regex in un programma e stampare il numero di corrispondenze. Tuttavia, come dici tu, sarà probabilmente battuto, quindi sono troppo preoccupato.
Calvin's Hobbies,

1
Puoi usare ^(o qualsiasi personaggio inutilizzato) per (?!).
jimmy23013,

@ user23013 Oh, buon punto, grazie.
Martin Ender,


@ user23013 Ho ottenuto 114 usando solo un gruppo senza nome, ma non combinando i controlli di linea in uno.
Martin Ender,

11

Python, 219 byte

def f(s):s=s.split();L=len;R=range;return L([r for r in R(L(s))for a in R(L(s[0]))for w in R(2,23)for h in R(3,min(L(s)+~r,23))if(s[r][a:a+w]==s[r-~h][a:a+w]==w*"X")*all(s[r-~k][a-1:a+w+1]=="X"+"."*w+"X"for k in R(h))])

Meglio di Java, ma ragazzo, i cappi nidificati quintupli fanno male. Il for/inpotrebbe essere leggermente comprimibile con %sla sostituzione, ma non sarebbe risparmiare molto.

Allargato:

def f(s):
  s=s.split()
  L=len
  R=range
  return L([r for r in R(L(s))
              for a in R(L(s[0]))
              for w in R(2,23)
              for h in R(3,min(L(s)+~r,23))
              if(s[r][a:a+w]==s[r-~h][a:a+w]==w*"X")* 
                 all(s[r-~k][a-1:a+w+1]=="X"+"."*w+"X"for k in R(h))])

1
Il mio istinto è quello di provare la stregoneria generazione di loop annidati itertools.
imallett,

7

Java, 304 byte

Questo è molto più lungo di un'espressione regolare. Semplicemente scorre su ogni possibile quadrato nell'input. Se è un portale valido, incrementa un contatore di 1. Quindi restituisce il contatore. Questo può probabilmente essere giocato molto più a lungo. Eventuali suggerimenti sono ben accetti

int a(String...a){a=a[0].split("\n");int b=0,c=0,d,e,f,g,h,i=a.length,j=a[0].length();for(;c<j;c++)for(d=0;d<i;d++)for(e=c+2;++e<j&e<c+24;)a:for(f=d+3;++f<i&f<d+24;){for(g=c;g<=e;g++)for(h=d;h<=f;h++){if(g==c|g==e&&h==d|h==f)continue;if((g==c|g==e|h==d|h==f)^a[h].charAt(g)>60)continue a;}b++;}return b;}

rientrato:

int a(String...a){
    a=a[0].split("\n");
    int b=0,c=0,d,e,f,g,h,i=a.length,j=a[0].length();
    for(;c<j;c++)
        for(d=0;d<i;d++)
            for(e=c+2;++e<j&e<c+24;)
                a:for(f=d+3;++f<i&f<d+24;){
                    for(g=c;g<=e;g++)
                        for(h=d;h<=f;h++){
                            if(g==c|g==e&&h==d|h==f)
                                continue;
                            if((g==c|g==e|h==d|h==f)^a[h].charAt(g)>60)
                                continue a;
                        }
                    b++;
                }
    return b;
}

Programma completo:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;

public class B {

    public static void main(String[] args) throws FileNotFoundException {
        String blocks = new BufferedReader(new FileReader(args[0])).lines().reduce((a,b)->a+"\n"+b).get();
        System.out.println(new B().a(blocks));
    }

    int a(String...a){
        a=a[0].split("\n");
        int b=0,c=0,d,e,f,g,h,i=a.length,j=a[0].length();
        for(;c<j;c++)
            for(d=0;d<i;d++)
                for(e=c+2;++e<j&e<c+24;)
                    a:for(f=d+3;++f<i&f<d+24;){
                        for(g=c;g<=e;g++)
                            for(h=d;h<=f;h++){
                                if(g==c|g==e&&h==d|h==f)
                                    continue;
                                if((g==c|g==e|h==d|h==f)^a[h].charAt(g)>60)
                                    continue a;
                            }
                        b++;
                    }
        return b;
    }

}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.