Penempatan Dada Minecraft

20

Permainan video Minecraft adalah tentang menempatkan dan menghapus berbagai jenis blok dalam kisi integer 3D yang membentuk dunia virtual. Setiap titik kisi dapat berisi tepat satu blok atau kosong ( blok " udara " secara resmi). Dalam tantangan ini, kita hanya akan peduli dengan satu bidang 2D horisontal dunia 3D, dan satu jenis blok: peti .

Peti memungkinkan pemain menyimpan item. Ketika dua peti berdekatan secara orthogonal dalam bidang horizontal yang sama, teksturnya saling terhubung dan dada ganda dengan dua kali kapasitas terbentuk. Tidak ada yang lebih besar dari dada ganda yang bisa dibuat; tidak ada peti tiga atau peti empat.

Balok dada hanya dapat ditempatkan di titik kisi kosong jika empat titik yang berdekatan secara orthogonal semuanya kosong, atau jika persis satu berisi blok dada yang belum menjadi bagian dari peti ganda. Aturan penempatan ini memastikan bahwa tidak akan pernah ada ambiguitas tentang blok dada mana yang terhubung untuk membentuk peti ganda.

Misalnya, anggaplah .ruang kosong dan Csebuah peti: (Angka-angka juga ruang kosong dan hanya untuk tujuan identifikasi.)

.......C..
.1.C2.C3..
........5C
.CC4..CC..
..........
  • Sebuah peti dapat ditempatkan di tempat 1 karena 4 tetangganya kosong.
  • Sebuah dada dapat ditempatkan di tempat 2 karena dada tetangga belum menjadi bagian dari dada ganda.
  • Dada tidak bisa diletakkan di posisi 3 karena akan ada ambiguitas tentang bagaimana bentuk dada ganda.
  • Dada tidak dapat ditempatkan di tempat 4 karena dada tetangga sudah merupakan bagian dari dada ganda.
  • Sebuah dada dapat ditempatkan di tempat 5. Dada ganda diagonal tetangga tidak mempengaruhi apa pun.

Dengan asumsi area di luar grid kosong, mengubah setiap .di grid menjadi *jika peti dapat ditempatkan di sana menghasilkan ini:

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

Tidak semua *ruang dapat ditempati dengan peti pada saat yang bersamaan, tetapi jika Anda hanya memiliki satu peti, itu bisa ditempatkan di salah satu dari mereka.

Tantangan

Tulis program atau fungsi yang menggunakan a .dan Ckisi, dan ubah setiap .menjadi *jika peti dapat ditempatkan di sana, mencetak atau mengembalikan kisi yang dihasilkan.

  • Input dapat dari stdin atau file atau sebagai argumen string ke suatu fungsi.

  • Anda dapat mengasumsikan input terbentuk dengan baik - yaitu kotak teks persegi panjang yang sempurna, setidaknya 1 karakter lebar dan tinggi, hanya berisi .dan CAnda dapat secara opsional mengasumsikan ada baris tambahan setelah baris terakhir (dan mungkin ada satu di output ).

  • Anda bisa menganggap susunan peti di input konsisten dengan aturan di atas. Tidak akan pernah ada ambiguitas tentang peti mana yang membentuk peti ganda.

  • Jika diinginkan, Anda dapat menggunakan tiga yang berbeda ASCII printable karakter di tempat ., Cdan *. Anda tidak boleh menggunakan sesuatu yang lain sebagai pengganti baris baru.

  • Semua peti adalah peti normal. Tidak terjebak dada atau dada ender .

Mencetak gol

Pengajuan dengan byte paling sedikit menang.

Untuk tantangan terkait Minecraft yang sedikit lebih menantang, coba Nether Portal Detection .

Hobi Calvin
sumber
5
Dari sudut pandang Minecrafting, saya menemukan ini dalam game yang cukup mengganggu. Untung ada peti yang terperangkap: P
Sp3000
Saat mengambil input kisi dari stdin atau argumen string tunggal, apakah dapat menerima dimensi kisi sebagai input tambahan? atau harus disimpulkan dari baris baru dan panjang tali?
Level River St
@steveverrill Itu harus disimpulkan.
Calvin Hobbies
Hanya karena penasaran, mengapa setiap jawaban termasuk jawaban saya punya satu downvote? Saya hanya dapat berasumsi bahwa itu adalah orang yang sama, apakah mereka mau menjelaskan?
Level River St
Untuk tantangan tambahan, seseorang dapat menulis sebuah program untuk menemukan penempatan optimal untuk peti; yaitu, temukan konfigurasi yang memungkinkan jumlah maksimum peti tambahan untuk ditempatkan tanpa melanggar aturan bahkan di antara peti baru.
AJMansfield

Jawaban:

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*

Format input mengharapkan 0sel udara dan 8sel dada. Keluaran berisi 1untuk semua sel yang dapat ditempatkan dengan Dada.

PEMBARUAN : Memperbaiki bug. Meningkat 3 byte :( lebih lanjut golf :). 4 byte disimpan berkat @ Sp3000

Input contoh:

0000000800
0008008000
0000000008
0880008808
0000000000

Keluaran:

1111110811
1110018010
1008800108
0880088008
1008800110

Saya pikir saya sudah selesai bermain golf untuk saat ini ...

Penjelasan

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

Cobalah online di sini

Pengoptimal
sumber
8

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

Setelah tantangan terakhir yang saya jawab di regex (Tantangan Portal Belanda terkait dengan tantangan ini), saya akhirnya mulai menulis alat baris perintah, yang bertindak sebagai juru bahasa untuk ekspresi reguler gaya .NET, sehingga saya dapat menjawab pertanyaan dengan regex tanpa ditantang bahwa mereka bukan bahasa yang berdiri sendiri. Saya menamainya Retina.

Sekarang, tantangan ini tidak cocok dengan pengajuan regex, tapi saya hanya harus menggunakan Retina sekarang. ;) (Plus, Sp3000 menantang saya untuk melakukannya dalam obrolan.) Jadi, ini dia:

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 pengganti

*

File regex sebagian besar hanya regex, kecuali yang `memungkinkan Anda meletakkan beberapa opsi dalam file, dalam hal ini hanya mode multiline. Ketika diberi dua file, Retina secara otomatis mengasumsikan ganti semua mode. Kedua file ini mendefinisikan program yang membaca input dari STDIN dan mencetak hasilnya ke STDOUT.

Anda juga dapat mengujinya di RegexHero dan RegexStorm . Regex berfungsi baik dengan dan tanpa membuntuti baris baru, dan digunakan _sebagai pengganti .. (Rupanya, RegexStorm kadang-kadang memiliki masalah jika tidak ada baris baru, tetapi RegexHero tampaknya menangani kedua case tersebut dengan baik.)

Ada banyak sekali duplikasi di regex, dan saya punya beberapa ide untuk memperpendeknya secara signifikan ... Saya akan mencobanya nanti dan kemudian menambahkan penjelasan. Sementara itu, beri tahu saya jika Anda dapat menemukan input yang menghasilkan hasil yang salah.

Martin Ender
sumber
7

J, 75 73 byte

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

Menggunakan format dalam pertanyaan, masing-masing menggunakan ./ */ Cuntuk ruang / ruang yang dapat digunakan / dada.

Sunting: memperbaiki bug kecil (saya tidak sengaja menggunakan torus alih-alih memperlakukan sekitarnya sebagai ruang kosong dengan benar).

Penjelasan

## 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
sumber
4

C, 193

2 baris baru yang tidak perlu untuk kejelasan. Perubahan yang berkaitan dengan kode yang tidak disatukan meliputi: karakter sebagai kode ascii alih-alih literal karakter; penataan ulang v = 0, strlen, dan strchr untuk menyimpan karakter (strchr adalah yang paling jelek, karena itu berarti bahwa perhitungan yang seharusnya dilakukan sekali saja, dilakukan 5 kali per sel!)

Fungsi C tidak menerima string sebagai argumen atau mengembalikannya sebagai nilai, jadi yang terbaik yang bisa saya lakukan adalah sebagai berikut: qadalah pointer ke string input. Fungsi memodifikasi string dan ketika fungsi mengembalikan output ditemukan dalam string asli.

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

Untuk meringkas aturan:

kotak kosong (yang tidak mengandung C atau baris baru) dapat dikonversi jika memiliki maksimum 1 tetangga dengan C

... DAN tetangga itu tidak punya tetangga dengan huruf C.

Fungsi g berisi fungsi f yang berulang turun dari kedalaman 1 ke kedalaman 0. Dengan hanya 2 tingkat rekursi, f(r,0)panggilan rekursif sederhana akan dilakukan, tidak perlu f(r,d-1)!

Kode yang tidak digabungkan dalam program pengujian

Input string tes di-hardcode. getsdan scanftidak akan menerima string input dengan baris baru di dalamnya; mereka memotong-motongnya di setiap baris baru.

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

Keluaran berdasarkan contoh pertanyaan

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

JavaScript (ES6) 124 129

Menggunakan karakter 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('')

Tidak diikat dan dijelaskan

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
}

Uji di Firefox / konsol FireBug

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

console.log(F(a))

Keluaran

0000007600
0006006700
0770007706
7667076670
0770007700
edc65
sumber
1

Perl, 66

Konflik dada pencocokan regexp berakhir pada sisi yang panjang, jadi tidak ada yang bersaing dengan CJam saat ini.

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

Gunakan 0 dan 2 untuk ruang kosong dan dada pada input, 1 untuk menandai bintik pada output.

Coba di sini .

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

(Baris 8 dan 9 dimaksudkan dengan karakter tab tunggal, yang dikonversi SE menjadi 4 spasi. Setiap baris dalam program ini memiliki 0 atau 1 byte spasi kosong terkemuka.)

Input: 0untuk tanpa dada, 2untuk dada
Ouput: 0untuk tanpa dada, 2untuk dada yang ada, 1untuk kemungkinan dada baru


Ya Tuhan, ini mengerikan. Saya harus benar-benar keluar dari latihan. Saya melemparkan setiap trik yang saya tahu dan keluar ... yah, itu keluar sebagai 281 byte, kalah setiap jawaban kecuali yang ada di regex , haha. Sejujurnya saya merasa seperti bermain golf dengan baik, jadi saya menduga algoritma saya kurang ideal.

Tidak Terkumpul:

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=''
monmon bawah tanah
sumber