Розміщення грудної клітки Minecraft


20

У відеоігри Minecraft все йде про розміщення та видалення різних типів блоків у цілій 3D- решітці, яка складає віртуальний світ. Кожна точка решітки може містити рівно один блок або бути порожньою (" повітряний " блок офіційно). У цьому виклику ми будемо стосуватися лише однієї горизонтальної двовимірної площини тривимірного світу та одного типу блоку: скрині .

Скрині дозволяють гравцям зберігати речі. Коли дві комоди ортогонально сусідять в одній горизонтальній площині, їх текстури з’єднуються і утворюється подвійний комод з подвійною місткістю. Не можна зробити нічого більшого, ніж подвійний комод; немає потрійних скринь чи чотириразових скринь.

Грудний блок може бути розміщений у порожній точці решітки лише у тому випадку, якщо чотири ортогонально суміжні точки є порожніми або якщо саме одна містить грудний блок, який вже не є частиною подвійної скрині. Ці правила розміщення гарантують, що ніколи не може бути двозначності щодо того, які грудні блоки пов'язують, щоб утворити подвійні скрині.

Наприклад, припустимо, що .це порожній простір і Cє скринькою: (Цифри також порожні місця та просто для ідентифікації).

.......C..
.1.C2.C3..
........5C
.CC4..CC..
..........
  • Скриню можна розмістити в місці 1, оскільки 4 сусідки порожні.
  • Скриня може бути розміщена у місці 2, оскільки сусідня скриня не є (ще) частиною подвійної скрині.
  • Скриня не може бути поставлена ​​в місці 3, тому що існує двозначність щодо того, як утворюється подвійна скриня.
  • Скриня не може бути розміщена в місці 4, оскільки сусідня скриня вже є частиною подвійної скрині.
  • Скриня може бути розміщена на місці 5. Діагонально сусідня подвійна скриня нічого не впливає.

Якщо припустити, що область поза сіткою порожня, змінюючи кожну . в сітці на a, *якщо там можна розмістити скриню:

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

Не всі *простори можуть бути одночасно зайняті комодами, але якщо у вас була лише одна скриня, її можна розмістити в будь-якому з них.

Виклик

Напишіть програму або функцію, яка займає а .та Cсітку, і змініть кожен .на a, *якщо туди можна було розмістити комод, надрукувавши або повернувши отриману сітку.

  • Введення може бути з stdin або файлу або як аргумент рядка функції.

  • Ви можете припустити, що вхід добре сформований - тобто ідеально прямокутна сітка тексту, щонайменше 1 символ у ширину та висоту, містить лише .таC ви, при бажанні, можете припустити, що після останнього рядка є зворотний новий рядок (а у виході може бути один ).

  • Ви можете припустити, що розташування комодів на вході відповідає правилам, наведеним вище. Ніколи не буде сумнівів щодо того, які скрині утворюють подвійні скрині.

  • При бажанні, ви можете використовувати будь-які три різних друкуються ASCII символи замість ., Cі *. Ви можете використовувати щось інше замість нових рядків.

  • Усі скрині - це звичайні скрині. Не захоплені комоди чи вічні скрині .

Оцінка балів

Виграє подання з найменшими байтами .

Для виклику, пов'язаного з Minecraft, це трохи складніше, спробуйте виявлення порталу Nether .


5
З точки зору Minecrafting, я виявив це досить дратівливим у грі. Хороша річ, що є скрині в пастці: P
Sp3000

Приймаючи введення сітки з stdin або аргументу одного рядка, чи прийнятно приймати розміри сітки як додатковий вхід? чи це слід зробити з нових рядків та довжини рядка?
Рівень р. Св.

@steveverrill Це потрібно зробити висновок.
Захоплення Кальвіна

Чому з цікавості, чому кожна відповідь, включаючи мою власну, має один голос? Я можу лише припустити, що це одна і та ж людина, чи вони б хотіли пояснити?
Рівень р. Св.

Для додаткового виклику можна написати програму, щоб знайти оптимальне місце для грудей; тобто знайдіть конфігурацію, яка дозволяє розмістити максимальну кількість додаткових скринь, не порушуючи правила навіть між новими скринями.
AJMansfield

Відповіді:


11

CJam, 82 76 66 62 58 54 байт

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

Формат введення очікується 0для повітряного елемента та 8для грудної клітини. Вихідні дані містять 1для всіх комірок, які можна розмістити зі скринкою.

ОНОВЛЕННЯ : виправлена ​​помилка. Збільшено на 3 байти :( далі в гольф :). 4 байти збережено завдяки @ Sp3000

Приклад введення:

0000000800
0008008000
0000000008
0880008808
0000000000

Вихід:

1111110811
1110018010
1008800108
0880088008
1008800110

Я думаю, що зараз займаюся гольфом ...

Пояснення

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

Спробуйте його онлайн тут


8

.NET Regex ( Retina ), 434 416 310 + 1 = 311 байт

Після останнього виклику, на який я відповів у регулярному виразі (виклик Nether Portal, пов'язаний із цим викликом), я нарешті вирішив написати інструмент командного рядка, який виступає інтерпретатором регулярних виразів у стилі .NET, тому я можу відповідати на запитання з регулярним виразом, не заперечуючи, що вони не є окремою мовою. Я назвав її Retina.

Тепер цей виклик не дуже добре піддається регексу, але мені просто довелося зараз використовувати Retina. ;) (Плюс, Sp3000 кинув мені виклик зробити це у чаті.) Ось ось що:

Файл 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)!)

Замінний файл

*

Файл regex - це здебільшого лише регулярний вираз, за ​​винятком цього ` ви можете помістити у файл кілька варіантів, у цьому випадку просто багаторядковий режим. Якщо надано два файли, Retina автоматично переходить у режим заміни. Ці два файли визначають програму, яка зчитує вхід з STDIN і друкує результат на STDOUT.

Ви також можете протестувати його на RegexHero та RegexStorm . Регекс працює як з, так і без закінчення нового рядка, і використовує_ замість .. (Мабуть, у RegexStorm періодично виникають проблеми, якщо немає останнього рядка, але RegexHero, здається, справляється в будь-якому випадку.)

У підсумку є жахлива кількість дублювання, і у мене є кілька ідей щодо його скорочення ... Спробую пізніше, а потім додам пояснення. Тим часом, дайте мені знати, чи зможете ви знайти будь-які матеріали, які дають неправильний результат.


7

J, 75 73 байт

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

Використовує формат у запитанні, використовуючи ./ */ Cдля простору / корисного простору / скрині відповідно.

Редагувати: виправляє невелику помилку (я випадково використав торус замість того, щоб правильно ставитись до оточуючих як до порожнього місця).

Пояснення

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

С, 193

2 зайві нові рядки для наочності. Зміни відносно коду, який не має волі, включають: символи як коди ascii замість буквених символів; перестановка v = 0, strlen та strchr для збереження символів (strchr - найпотворніший, оскільки це означає, що обчислення, яке в іншому випадку було б виконано лише один раз, проводиться 5 разів на комірку!)

Функції C не приймають рядки як аргументи або не повертають їх як значення, тому найкраще, що я можу зробити, q- це вказівник на рядок введення. Функція змінює рядок, і коли функція повертає, вихід знайдеться в початковій рядку.

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

Для узагальнення правил:

порожній квадрат (який не містить C або новий рядок) може бути перетворений, якщо у нього макс 1 сусід із C

... І у того сусіда немає сусідів із С.

Функція g містить функцію f, яка повторюється вниз з глибини 1 на глибину 0. За допомогою лише 2 рівнів рекурсії f(r,0)виконає простий рекурсивний виклик, немає потреби вf(r,d-1) !

Невикористаний код у тестовій програмі

Вхідний тестовий рядок є жорстким кодом. getsі scanfне прийме рядок введення з новими рядками в ньому; вони подрібнюють його на шматочки в кожному новому рядку.

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

Результат на основі прикладу запитань

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

1

JavaScript (ES6) 124 129

Використання символів 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('')

Безумовно і пояснив

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
}

Тест на консолі Firefox / FireBug

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

console.log(F(a))

Вихідні дані

0000007600
0006006700
0770007706
7667076670
0770007700

1

Перл, 66

Конфлікти грудної клітки, що збігаються з регулярним виразом, закінчилися довгою стороною, тому цього разу жоден конкуруючий з CJam не був.

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

Використовує 0 і 2 для порожніх та скрині на вході, 1 для позначення плям на виході.

Спробуйте тут .


0

Python 2 - 281 байт

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

(Рядки 8 і 9 призначені для одного символу табуляції, який SE перетворює на 4 пробіли. Кожен рядок у цій програмі має або 0, або 1 байт провідних пробілів.)

Вхід: 0 не для грудей, 2для грудей.
Ouput: 0для грудей немає, 2для існуючих грудей, 1для можливих нових грудей


Боже, це жахливо. Я повинен бути серйозно поза практикою. Я кидав кожен трюк, який я знаю, і він вийшов ... ну, він вийшов як 281 байт, втрачаючи кожну відповідь, окрім тієї, що знаходиться в регулярному виразі , ха-ха. Я, чесно кажучи, відчуваю, що добре зіграв у нього, тому я здогадуюсь, що мій алгоритм був менш ідеальним.

Безголівки:

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=''
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.