Platzierung in der Minecraft-Truhe

20

In dem Videospiel Minecraft geht es darum, verschiedene Arten von Blöcken in dem 3D- Ganzzahlgitter , aus dem die virtuelle Welt besteht, zu platzieren und zu entfernen . Jeder Gitterpunkt kann genau einen Block enthalten oder leer sein ( offiziell ein " Luft " -Block). In dieser Herausforderung werden wir uns nur mit einer horizontalen 2D-Ebene der 3D-Welt und einem Blocktyp befassen: Truhen .

Mit Truhen können Spieler Gegenstände lagern. Wenn zwei Truhen in derselben horizontalen Ebene orthogonal nebeneinander liegen, verbinden sich ihre Texturen und es bildet sich eine doppelte Truhe mit der doppelten Kapazität. Nichts größer als eine doppelte Truhe kann gemacht werden; es gibt keine dreifachen oder vierfachen Truhen.

Ein Brustblock kann nur in einem leeren Gitterpunkt platziert werden, wenn seine vier orthogonal benachbarten Punkte alle leer sind oder wenn genau einer einen Brustblock enthält, der nicht bereits Teil einer doppelten Brust ist. Diese Platzierungsregeln stellen sicher, dass es niemals zu Unklarheiten darüber kommen kann, welche Brustblöcke sich zu doppelten Truhen verbinden.

Angenommen, es .ist ein leerer Raum und Ceine Truhe: (Die Zahlen sind ebenfalls ein leerer Raum und dienen nur zu Identifikationszwecken.)

.......C..
.1.C2.C3..
........5C
.CC4..CC..
..........
  • Eine Truhe kann auf Platz 1 gelegt werden, da ihre 4 Nachbarn leer sind.
  • Eine Truhe kann in Punkt 2 platziert werden, da die benachbarte Truhe (noch) nicht Teil einer doppelten Truhe ist.
  • Eine Truhe kann nicht in Position 3 platziert werden, da es Unklarheiten darüber geben würde, wie sich die doppelte Truhe bildet.
  • Eine Truhe kann nicht in Position 4 platziert werden, da die benachbarte Truhe bereits Teil einer doppelten Truhe ist.
  • Eine Truhe kann in Position 5 platziert werden. Die diagonal benachbarte Doppel-Truhe hat keinen Einfluss auf irgendetwas.

Angenommen, der Bereich jenseits des Gitters ist leer, ändert sich jeder Bereich .des Gitters in einen, *wenn dort eine Truhe platziert werden könnte:

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

*Natürlich können nicht alle Räume gleichzeitig mit Truhen belegt werden, aber wenn Sie nur eine Truhe hätten, könnten Sie diese in eine der Truhen stellen.

Herausforderung

Schreiben Sie ein Programm oder eine Funktion, die ein .und C-Raster enthält, und ändern Sie jedes .in ein, *wenn eine Truhe dort platziert werden könnte, um das resultierende Raster zu drucken oder zurückzugeben.

  • Die Eingabe kann von stdin oder einer Datei oder als Zeichenfolgenargument für eine Funktion erfolgen.

  • Sie können davon ausgehen, dass die Eingabe gut strukturiert ist, dh ein perfekt rechteckiges Textgitter , das mindestens 1 Zeichen breit und hoch ist und nur Folgendes enthält, .und CSie können optional davon ausgehen, dass nach der letzten Zeile eine nachgestellte neue Zeile steht (und in der Ausgabe möglicherweise eine ).

  • Sie können davon ausgehen, dass die Anordnung der Truhen in der Eingabe den obigen Regeln entspricht. Es wird niemals Unklarheiten darüber geben, welche Truhen Doppel-Truhen bilden.

  • Falls gewünscht, können Sie drei verschiedene verwenden druckbaren ASCII - Zeichen anstelle von ., C, und *. Sie dürfen anstelle von Zeilenumbrüchen nichts anderes verwenden.

  • Alle Truhen sind normale Truhen. Nicht eingeschlossene Truhen oder Ender-Truhen .

Wertung

Die Einsendung mit den wenigsten Bytes gewinnt.

Versuchen Sie für eine Minecraft-bezogene Herausforderung, die etwas schwieriger ist, Nether Portal Detection .

Calvins Hobbys
quelle
5
Aus Sicht von Minecrafting fand ich das ziemlich nervig im Spiel. Gut, dass Truhen gefangen sind: P
Sp3000
Wenn Sie eine Rastereingabe von stdin oder einem einzelnen Zeichenfolgenargument nehmen, ist es akzeptabel, die Rasterdimensionen als zusätzliche Eingabe zu verwenden? oder muss es aus newlines und string length abgeleitet werden?
Level River St
@steveverrill Es muss gefolgert werden.
Calvins Hobbys
Warum hat jede Antwort, auch meine, aus Neugier eine Ablehnung? Ich kann nur davon ausgehen, dass es sich um dieselbe Person handelt. Würden sie es gerne erklären?
Level River St
Für eine zusätzliche Herausforderung könnte man ein Programm schreiben, um die optimale Platzierung für die Truhen zu finden; Suchen Sie also eine Konfiguration, mit der die maximale Anzahl zusätzlicher Truhen platziert werden kann, ohne die Regeln selbst zwischen den neuen Truhen zu verletzen.
AJMansfield

Antworten:

11

CJam, 82 76 66 62 58 54 Bytes

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

Eingabeformat erwartet 0für Luftzelle und 8für eine Brustzelle. Die Ausgabe enthält 1für alle Zellen, die mit einer Truhe platziert werden können.

UPDATE : Fehler behoben. Erhöht um 3 Bytes :( weiter golfen :). 4 Bytes gespart dank @ Sp3000

Beispiel Eingabe:

0000000800
0008008000
0000000008
0880008808
0000000000

Ausgabe:

1111110811
1110018010
1008800108
0880088008
1008800110

Ich glaube, ich bin jetzt mit dem Golfen fertig ...

Erläuterung

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";

Probieren Sie es hier online aus

Optimierer
quelle
8

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

Nach der letzten Herausforderung, die ich in Regex beantwortet habe (der Nether Portal-Herausforderung, die mit dieser Herausforderung verknüpft ist), habe ich mich endlich daran gemacht, ein Befehlszeilentool zu schreiben, das als Interpreter für reguläre Ausdrücke im .NET-Stil fungiert, damit ich Fragen beantworten kann mit Regex, ohne herausgefordert zu werden, dass sie keine eigenständige Sprache sind. Ich habe es Retina genannt.

Nun, diese Herausforderung eignet sich nicht sehr gut für eine Regex-Einreichung, aber ich musste jetzt nur noch Retina verwenden. ;) (Plus, Sp3000 forderte mich auf, dies im Chat zu tun.) Also hier ist es:

Regex-Datei

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

Ersatzdatei

*

Die Regex-Datei ist meist nur die Regex-Datei, mit der Ausnahme, dass `Sie einige Optionen in die Datei einfügen können, in diesem Fall einfach den Mehrzeilenmodus. Bei zwei Dateien nimmt Retina automatisch den Alle-Ersetzen-Modus an. Diese beiden Dateien definieren ein Programm, das die Eingabe von STDIN liest und das Ergebnis an STDOUT ausgibt.

Sie können es auch mit RegexHero und RegexStorm testen . Der reguläre Ausdruck funktioniert sowohl mit als auch ohne nachfolgende Zeilenumbrüche und wird _anstelle von verwendet .. (Anscheinend hat RegexStorm gelegentlich Probleme, wenn keine nachgestellte Zeile vorhanden ist, aber RegexHero scheint mit beiden Fällen in Ordnung zu sein.)

Es gibt eine schreckliche Menge an Duplikaten im regulären Ausdruck, und ich habe ein paar Ideen, um ihn signifikant zu verkürzen ... Ich werde es später versuchen und dann eine Erklärung hinzufügen. Lassen Sie mich in der Zwischenzeit wissen, ob Sie Eingaben finden, die zu einem falschen Ergebnis führen.

Martin Ender
quelle
7

J, 75 73 Bytes

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

Verwendet das Format in der Frage und verwendet ./ */ Cfür Leerzeichen / nutzbaren Raum / Truhe.

Bearbeiten: behebt einen kleinen Fehler (ich habe versehentlich einen Torus verwendet, anstatt die Umgebung als leeren Raum zu behandeln).

Erläuterung

## 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
FireFly
quelle
4

C 193

2 unnötige Zeilenumbrüche zur Verdeutlichung. Zu den Änderungen in Bezug auf ungolfed code gehören: Zeichen als ASCII-Codes anstelle von Zeichenliteralen; Neuanordnung von v = 0, strlen und strchr zum Speichern von Zeichen (strchr ist am hässlichsten, da eine Berechnung, die sonst nur einmal ausgeführt würde, 5-mal pro Zelle ausgeführt wird!)

C-Funktionen akzeptieren keine Zeichenfolgen als Argumente oder geben sie als Werte zurück. Daher kann ich Folgendes tun: qist ein Zeiger auf die Eingabezeichenfolge. Die Funktion ändert die Zeichenfolge und wenn die Funktion zurückgibt, wird die Ausgabe in der ursprünglichen Zeichenfolge gefunden.

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

Um die Regeln zusammenzufassen:

Ein leeres Quadrat (das kein C oder keine Newline enthält) kann konvertiert werden, wenn es maximal einen Nachbarn mit einem C hat

... UND dieser Nachbar hat keine Nachbarn mit einem C.

Die Funktion g enthält eine Funktion f, die von Tiefe 1 bis Tiefe 0 f(r,0)rekursiv abläuft. Bei nur 2 Rekursionsebenen ist ein einfacher rekursiver Aufruf nicht erforderlich f(r,d-1)!

Ungolfed Code im Testprogramm

Die Eingabe-Testzeichenfolge ist fest codiert. getsund scanfakzeptiert keine Eingabezeichenfolge mit Zeilenumbrüchen; sie hacken es bei jeder neuen Zeile in Stücke.

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

Ausgabe anhand eines Fragenbeispiels

******.C**
***C**C.**
*..***..*C
.CC.*.CC.*
*..***..**
Level River St
quelle
1

JavaScript (ES6) 124 129

Verwenden der Zeichen 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 und erklärte

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 In der Firefox / FireBug-Konsole

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

console.log(F(a))

Ausgabe

0000007600
0006006700
0770007706
7667076670
0770007700
edc65
quelle
1

Perl, 66

Die Regexp Matching-Konflikte in der Brust endeten auf der langen Seite, so dass diesmal keine Konkurrenz zu CJam bestand.

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

Verwendet 0 und 2 für Leerzeichen und Leerzeichen in der Eingabe, 1 zum Markieren der Punkte auf der Ausgabe.

Probieren Sie es hier aus .

nutki
quelle
0

Python 2 - 281 Bytes

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=''

(Die Zeilen 8 und 9 enthalten ein einzelnes Tabulatorzeichen, das SE in 4 Leerzeichen umwandelt. Jede Zeile in diesem Programm enthält entweder 0 oder 1 Byte führende Leerzeichen.)

Eingabe: 0für keine Truhe, 2für Truhe
Ausgabe: 0für keine Truhe, 2für bestehende Truhe, 1für mögliche neue Truhe


Gott, das ist schrecklich. Ich muss ernsthaft aus der Übung sein. Ich habe jeden Trick geworfen, den ich kenne, und er kam heraus ... nun, er kam als 281 Bytes heraus und verlor gegen jede Antwort außer der in Regex , haha. Ich habe ehrlich gesagt das Gefühl, dass ich ein bisschen gut Golf gespielt habe, also schätze ich, dass mein Algorithmus einfach nicht optimal war.

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=''
untergrundbahn
quelle