Collocazione del petto di Minecraft


20

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 orizzontale del mondo 3D e di un tipo di blocco: le casse .

I forzieri permettono ai giocatori di conservare gli oggetti. Quando due casse sono ortogonalmente adiacenti nello stesso piano orizzontale, le loro trame si collegano e un doppio petto con il doppio delle forme di capacità. Nulla di più grande di un doppio petto può essere realizzato; non ci sono bauli tripli né quadrupli.

Un blocco toracico può essere posizionato in un punto reticolare vuoto solo se i suoi quattro punti ortogonalmente adiacenti sono tutti vuoti o se esattamente uno contiene un blocco toracico che non fa già parte di un doppio petto. Queste regole di posizionamento assicurano che non ci sia mai alcuna ambiguità su quali blocchi toracici si collegano per formare doppi forzieri.

Ad esempio, supponiamo che .sia uno spazio vuoto ed Cè un forziere: (I numeri sono anche spazi vuoti e solo a scopo di identificazione).

.......C..
.1.C2.C3..
........5C
.CC4..CC..
..........
  • Una cassa può essere posizionata nel punto 1 perché i suoi 4 vicini sono vuoti.
  • Una cassa può essere posizionata nel punto 2 perché la cassa vicina non è (ancora) parte di una doppia cassa.
  • Una cassa non può essere messa nel punto 3 perché ci sarebbe ambiguità su come si forma la doppia cassa.
  • Una cassa non può essere posizionata nel punto 4 perché la cassa vicina fa già parte di una doppia cassa.
  • Una cassa può essere posizionata nel punto 5. La doppia cassa diagonale adiacente non influenza nulla.

Supponendo che l'area oltre la griglia sia vuota, cambiando ogni .nella griglia in un *se si potesse posizionare un forziere, si ottiene questo:

******.C**
***C**C.**
*..***..*C
.CC.*.CC.*
*..***..**

*Ovviamente non tutti gli spazi possono essere occupati con forzieri allo stesso tempo, ma se avessi un solo forziere, potrebbe essere posizionato in uno di essi.

Sfida

Scrivi un programma o una funzione che includa una .e una Cgriglia e cambi ogni .in una *se una cassa potesse essere posizionata lì, stampando o restituendo la griglia risultante.

  • L'input può provenire da stdin o da un file o come argomento stringa in una funzione.

  • Puoi supporre che l'input sia ben formato - cioè una griglia di testo perfettamente rettangolare, almeno 1 carattere largo e alto, contenente solo .e CPuoi facoltativamente supporre che ci sia una nuova riga finale dopo l'ultima riga (e potrebbe essercene una nell'output ).

  • Puoi supporre che la disposizione dei forzieri nell'input sia coerente con le regole sopra. Non ci saranno mai ambiguità su quali forzieri formino doppi forzieri.

  • Se lo si desidera, è possibile utilizzare qualsiasi tre distinte ASCII stampabili caratteri al posto di ., Ce *. Non puoi usare qualcos'altro al posto di newline.

  • Tutte le casse sono normali. Petti non intrappolati o forzieri .

punteggio

Vince l'invio con il minor numero di byte .

Per una sfida relativa a Minecraft che è un po 'più impegnativa, prova Nether Portal Detection .


5
Dal punto di vista di Minecrafting, ho trovato questo gioco abbastanza fastidioso. Per
fortuna

Quando si accetta l'input della griglia da stdin o un singolo argomento stringa, è accettabile prendere le dimensioni della griglia come input aggiuntivo? o deve essere dedotto da newline e lunghezza della stringa?
Level River St,

@steveverrill Deve essere dedotto.
Calvin's Hobbies,

Solo per curiosità, perché ogni risposta, compresa la mia, ha un solo voto negativo? Posso solo supporre che sia la stessa persona, a loro interesserebbe spiegare?
Level River St,

Per una sfida in più, si potrebbe scrivere un programma per trovare il posizionamento ottimale per le casse; vale a dire, trovare una configurazione che consenta di posizionare il numero massimo di bauli aggiuntivi senza infrangere le regole anche tra i nuovi bauli.
AJMansfield,

Risposte:


11

CJam, 82 76 66 62 58 54 byte

qN/::~4{[8_]f/[9_]f*z{[{1$8-g)+}*]W%}%}*{_8<\2<8?}f%N*

Il formato di input prevede 0una cellula d'aria e 8una cellula toracica. L'output contiene 1per tutte le celle che possono essere posizionate con una cassa.

AGGIORNAMENTO : corretto un bug. Aumentato di 3 byte :( golf ulteriormente :). 4 byte salvati grazie a @ Sp3000

Esempio di input:

0000000800
0008008000
0000000008
0880008808
0000000000

Produzione:

1111110811
1110018010
1008800108
0880088008
1008800110

Penso di aver finito di giocare a golf per ora ...

Spiegazione

qN/::~                   "This part converts the input into array of integer array";
qN/                      "Split input on new line";
   ::~                   "Parse each character in each row as integer";

4{[8_]f/[9_]f*z{[{1$8-g)+}*]W%}%}*

4{   ...z{       W%}%}*  "Run the logic 4 times, first, columns in correct order, then,";
                         "columns in reverse order, then for rows";
  [8_]f/[9_]f*           "Convert adjacent chests represented by two 8 into two 9";
                         "This happens for all the rows in the columns iterations and";
                         "for all the columns in the rows iterations";
  {               }%     "For each row/column";
   [{        }*]         "Reduce and wrap it back in the array";
     :I8-                "Store the second number in I, remove 8 from it";
         g               "Do signum. Now we have -1 for < 8 number, 0 for 8 and 1 for > 8";
          )+I            "Increment to get 0, 1 & 2. Add it to first number and put I back";

{_8<\2<8?}f%N*           "This part converts the output from previous iterations";
                         "to 3 character based final output and prints it";
{        }f%             "Map each row using the code block";
 _8<   8?                "If the value is greater than 7, make it 8, else:";
    \2<                  "If the value is greater than 1, make it 0, else 1";
            N*           "Join the arrays using new line";

Provalo online qui


8

.NET Regex ( Retina ), 434 416 310 + 1 = 311 byte

Dopo l'ultima sfida a cui ho risposto in regex (la sfida del portale Nether collegata a questa sfida), ho finalmente deciso di scrivere uno strumento da riga di comando, che funge da interprete per le espressioni regolari in stile .NET, quindi posso rispondere alle domande con regex senza essere sfidato che non sono un linguaggio autonomo. L'ho chiamato Retina.

Ora, questa sfida non si presta molto bene alla presentazione di regex, ma ora ho dovuto usare Retina. ;) (Inoltre, Sp3000 mi ha sfidato a farlo in chat.) Quindi eccolo:

File Regex

m`(?<=(?=.(.)*).*)(?<=((?<=(?<2>C|C(?(1)!)(\n|(?<-1>.))*)?)C(?=(?<2>C|(\n|(?<-1>.))*(?(1)!)C)?)(()(?(6)!)|(?<=^(?(7)!)(?<-7>.)*C).*\n(.)*()(?(8)!)))?){2}_(?=(?<2>((?(10)!)()|(?(11)!)()(.)*\n.*(?=C(?<-12>.)*(?(12)!)$))(?<=(?<2>C|C(?(1)!)(\n|(?<-1>.))*)?)C(?=(?<2>C|(\n|(?<-1>.))*(?(1)!)C)?))?){2}(?<-2>)?(?(2)!)

File di sostituzione

*

Il file regex è principalmente solo regex, tranne per il fatto che `consente di inserire alcune opzioni nel file, in questo caso semplicemente in modalità multilinea. Quando vengono dati due file, Retina assume automaticamente la modalità di sostituzione totale. Questi due file definiscono un programma che legge l'input da STDIN e stampa il risultato su STDOUT.

Puoi anche testarlo su RegexHero e RegexStorm . Il regex funziona sia con che senza newline finale, e usa _al posto di .. (Apparentemente, RegexStorm occasionalmente ha problemi se non c'è una nuova riga finale, ma RegexHero sembra gestire bene entrambi i casi.)

C'è una quantità orribile di duplicazioni nel regex e ho un paio di idee per accorciarlo in modo significativo ... Ci proverò più tardi e poi aggiungerò una spiegazione. Nel frattempo, fammi sapere se riesci a trovare input che producono risultati errati.


7

J, 75 73 byte

((,.|.)0 _1 0 1)(+:@](LF,@:,.~'*.C'{~>.)(2=f)+.[f]*f=.[:+/|.!.0)'C'&=;._2

Utilizza il formato nella domanda, usando rispettivamente ./ */ Cper spazio / spazio utilizzabile / petto.

Modifica: corregge un piccolo bug (ho usato accidentalmente un toro invece di trattare correttamente l'ambiente circostante come spazio vuoto).

Spiegazione

## Preparation
              'C'&=;._2  NB. Map ./C to 0/1, turn into matrix
((,.|.)0 _1 0 1)         NB. Compute offsets to shift into each direction
                         NB. (i.e. [[_1 0], [1 0], [0 _1], [0 1]] in any order)


## "Part B"
(2=f)+.[f]*f=.[:+/|.!.0  NB. This part computes a matrix that is 1 for cells that
                         NB. cannot contain a chest:
              [:+/|.!.0  NB. Sum of shifts: shift in each of the four cardinal
                         NB. directions (using the array above) and then sum up.
           f=.           NB. Define this function as `f`; we'll use it some more.
         ]*              NB. Multiply by the "is chest" matrix: this isolates
                         NB. double-chests.
       [f                NB. Sum of shifts--1 for double-chest neighbours.
(2=f)                    NB. Isolate cells with two neighbouring chest.
     +.                  NB. Boolean or--either two neighbouring chests or next
                         NB. to a double-chest.

## Wrap up the result
(+:@] (fmt >.) PartB)    NB. Maximum of the array from the above and twice the "is
 +:@]      >.  PartB     NB. chest" matrix--this is 0,1,2 for '*', '.' or chest,
                         NB. respectively.

## Output formatting
LF,@:,.~'*.C'{~          NB. Format output...
        '*.C'{~          NB. Map 0,1,2 to '*.C' by using the value as index
LF   ,.~                 NB. Append line feed at end of each line
  ,@:                    NB. Ravel into one line

4

C, 193

2 newline inutili per chiarezza. Le modifiche rispetto al codice non golfizzato includono: caratteri come codici ascii invece di caratteri letterali; riarrangiamento di v = 0, strlen e strchr per salvare i caratteri (strchr è il più brutto, in quanto significa che un calcolo che verrebbe eseguito una sola volta, viene eseguito 5 volte per cella!)

Le funzioni C non accettano le stringhe come argomenti o le restituiscono come valori, quindi il meglio che posso fare è il seguente: qè un puntatore alla stringa di input. La funzione modifica la stringa e quando la funzione restituisce l'output si trova nella stringa originale.

g(char*q){int v,j,w,l;
int f(p,d){int s=0,i=w=strchr(q,10)-q+1,r;for(;w/i;i-=i-1?w-1:2)r=p+i,r>-1&r<l&&q[r]==67&&++s&&d&&f(r,0);v|=s>d;}
for(j=l=strlen(q);j--;f(j,1),46-q[j]||v||(q[j]=42))v=0;}

Per riassumere le regole:

un quadrato vuoto (che non contiene C o newline) può essere convertito se ha al massimo 1 vicino con una C

... E quel vicino non ha vicini con una C.

La funzione g contiene una funzione f che ricorre dalla profondità 1 alla profondità 0. Con solo 2 livelli di ricorsione, una semplice f(r,0)chiamata ricorsiva farà, non è necessario f(r,d-1)!

Codice non registrato nel programma di test

La stringa di test di input è codificata. getse scanfnon accetterà una stringa di input con newline in essa; lo tagliano a pezzi in ogni riga.

char n[]=".......C..\n...C..C...\n.........C\n.CC...CC..\n..........";

g(char*q){

  int v,j,w,l;

  int f(p,d){                    //p=cell to be checked,d=recursion depth
    int s=0,i=w,r;               //sum of C's found so far=0, i=width
    for(;w/i;i-=i-1?w-1:2)       //For i in   w,1,-1,-w   = down,right,left,up
      r=p+i,                     //r=cell adjacent to p
      r>-1&r<l&&q[r]=='C'&&++s   //If r not out of bounds and equal to C, increment s...
        &&d&&f(r,0);             //...and if recursion depth not yet at zero, try again one level deeper. 
    v|=s>d;                      //If the local s exceeds d, set global v to true to indicate invalid.
  }

  w=strchr(q,10)-q+1;            //width equals index of first newline + 1                   
  l=strlen(q);                   //length of whole string;
  for(j=l;j--;)                  //for l-1 .. 0 
    v=0,                         //clear v
    f(j,1),                      //and scan to see if it should be set
    '.'-q[j]||v||(q[j]='*');     //if the character is a '.' and v is not invalid, change to '*'
}

main(){
  g(n);
  puts(n);
}

Output basato sull'esempio della domanda

******.C**
***C**C.**
*..***..*C
.CC.*.CC.*
*..***..**

1

JavaScript (ES6) 124 129

Uso dei caratteri 0 (*), 6 (C), 7 (.)

F=s=>[for(c of(d=[o=~s.search('\n'),-o,1,i=-1],s))
   d.map(j=>t-=s[i+j]==6&&~d.some(k=>s[i+j+k]==6),t=i++)|c<7|t>i&&c
].join('')

Ungolfed e spiegato

F=s=>
{
  o=~s.search('\n') // offset to prev row (~ is shorter than +1 and sign does not matter)
  d=[o,-o,1,-1] // array of offset to 4 neighbors
  i=-1
  result = '' // in golfed code, use array comprehension to build the result into an array, then join it
  for (c of s) // scan each char
  {
    t = i++ // set a starting value in t and increment current position in i
    d.forEach(j => // for each near cell, offset in j
    {         
      if (s[i+j]==6) // if cell contains a Chest, must increment t
      {  
        // In golfed code "~some(...)" will be -1(false) or -2(true), using decrement instead of increment
        if (d.some(k=>s[i+j+k]==6)) // look for another Cheast in the neighbor's neighbors
        {
          // more than one chest, position invalid
          t += 2
        }
        else
        {
          t += 1
        }
      }
    })
    if (c < 7 // current cell is not blank
        || t > i) // or t incremented more than once, position invalid
    {
       result += c // curent cell value, unchanged
    }
    else
    {
       result += 0 // mark a valid position 
    }
  }
  return result
}

Test nella console di Firefox / FireBug

a='\
7777777677\n\
7776776777\n\
7777777776\n\
7667776677\n\
7777777777\n';

console.log(F(a))

Produzione

0000007600
0006006700
0770007706
7667076670
0770007700

1

Perl, 66

I regexp corrispondenti ai conflitti toracici si sono conclusi sul lato lungo, quindi questa volta non c'è competizione con CJam.

#!perl -p0
/.
/;$"=".{@-}";s%0%s/\G0/2/r!~/2((.$")?2(.$")?|2$"|$"2)2/s*1%eg

Usa 0 e 2 per gli spazi vuoti e di petto sull'ingresso, 1 per contrassegnare i punti sull'uscita.

Provalo qui .


0

Python 2 - 281 byte

f=lambda x,y:sum(m[y][x-1:x+2])+m[y-1][x]+m[y+1][x]
m=[];o=''
try:
 while 1:m+=[map(int,'0%s0'%raw_input())]
except:a=len(m[0]);l=len(m);m+=[[0]*a]
for y in range(l*2):
 for x in range(1,a-1):
    if y<l:m[y][x]*=f(x,y)
    else:o+=`2if m[y-l][x]else +(f(x,y-l)<5)`
 if y>=l:print o;o=''

(Le righe 8 e 9 sono intese con un singolo carattere di tabulazione, che SE converte in 4 spazi. Ogni riga in questo programma ha 0 o 1 byte di spazio bianco iniziale.)

Input: 0senza petto, 2per petto
Ouput: 0senza petto, 2per petto esistente, 1per eventuale nuovo petto


Dio, questo è orribile. Devo essere seriamente fuori allenamento. Ho lanciato ogni trucco che conosco ed è venuto fuori ... beh, è ​​venuto fuori come 281 byte, perdendo per ogni risposta tranne quella in regex , haha. Sinceramente mi sembra di averlo giocato bene, quindi immagino che il mio algoritmo non sia proprio l'ideale.

Ungolfed:

def f(x,y):
    """Given x,y coords of the board, return the sum of that point and all
    adjacent points.
    """
    return (sum(board[y][x-1:x+2]) # (x-1,y) + (x,y) + (x+1,y)
            + board[y-1][x]
            + board[y+1][x])
board=[]
output=''
try:
    while True:
        row = '0%s0' % raw_input() # line from stdin with a leading and trailing 0
        board.append(map(int, row)) # convert to list of ints
except:
    pass # exception is thrown when stdin is empty

board_width = len(board[0])
board_height = len(board)

board.append([0]*board_width) # new row of all 0s

for y in xrange(board_height*2):
    # board_height multiplied by 2 so we can use this loop to simulate two
    for x in xrange(1,board_width-1):
        if y < board_height: # "first loop"
            board[y][x] *= f(x,y) # multiply everything on the board by itself + sum
                                  # of neighbours
                                  # empty cells (0) stay 0 no matter what
                                  # lone chests (2 surrounded by 0) become 2*2==4
                                  # double chests (2 touching another 2) are weird:
                                  # - one chest becomes 2*(2+2)==8
                                  # - the other chest becomes 2*(2+8)==20
        else: # "second loop"
            if board[y - board_height][x] != 0:
                output += '2' # anything not equal to 0 is an existing chest
            else:
                valid = f(x, y - board_height) < 5 # if the sum of neighbours > 4, the
                                                   # current cell is either beside a
                                                   # double chest or more than one
                                                   # single chest
                output += '01'[valid]
    if y >= board_height: # only print during the "second loop"
        print output
        output=''
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.